var coordinatesBB = []
//var url = "https://simstadt-api.iaf-ex.hft-stuttgart.de:8080/workflow/execute" //old link
var url = "http://vm24.fkc.hft-stuttgart.de:8082/workflow/execute" // URL to API
var url2 = "http://vm24.fkc.hft-stuttgart.de:8082/workflow/timedShadowValueByDay/"
var pvURL = "http://vm24.fkc.hft-stuttgart.de:8082/workflow/readPVPotential"

/*TODO#1:   -get current data from the api and create local test data (apiData foler)
            -add connection handeling  (error messages when there isnt a connection and then using the local test data)
*/
var localShadowData = "/3dclient4simstadtapi/public/test/APIdata/shadowData.json"

var buildingFunctionSort
var constructionYearSortPick
var heightSortPick
var heatedVolumeSortPick
var totalSurfaceAreaSortPick
var roofTypeSortPick
var uValueSortPick
var shadowdata


async function fetchPvPotentialJSON() {    
    var bottomLat = coordinatesBB[1]
    var leftLng = coordinatesBB[0]
    var rightLng = coordinatesBB[2]
    var topLat = coordinatesBB[3]

    const response = await fetch(pvURL,  {
        method: "POST",
        body: JSON.stringify({
            "boundingBox": {
                "bottomLat": bottomLat, //48.779004965,
                "leftLng": leftLng,     //9.1686843081,
                "lodType": "LOD2",
                "rightLng": rightLng,   //9.175336684,
                "topLat": topLat        //48.7822869656
              },
              "cityGMLRef": "campusLOD2"
        }),
        headers: {
            "Content-Type": "application/json",
            "Authorization": "Basic YWRtaW46YWRtaW4xMjM="
        }
    })

    const data = await response.json();
    return data
}

async function fetchshadowDataJSON() {
    var bottomLat = coordinatesBB[1]
    var leftLng = coordinatesBB[0]
    var rightLng = coordinatesBB[2]
    var topLat = coordinatesBB[3]//
    var day = "1";
    const response = await fetch(url2 + day,  {
        method: "POST",
        body: JSON.stringify({
            "boundingBox": {
                "bottomLat": bottomLat, //48.779004965,
                "leftLng": leftLng,     //9.1686843081,
                "lodType": "LOD2",
                "rightLng": rightLng,   //9.175336684,
                "topLat": topLat        //48.7822869656
            },
            "cityGMLRef": "campusLOD2"
        }),
        headers: {
            "Content-Type": "application/json",
            "Authorization": "Basic YWRtaW46YWRtaW4xMjM="
        }
    })

    const data = await response.json();
    return data
}


async function fetchDataJSON() {
    var bottomLat = coordinatesBB[1]
    var leftLng = coordinatesBB[0]
    var rightLng = coordinatesBB[2]
    var topLat = coordinatesBB[3]//

const response = await fetch(url, {
        method: "POST",
        body: JSON.stringify({
            "boundingBox": {
                "bottomLat": bottomLat, //48.779004965,
                "leftLng": leftLng,     //9.1686843081,
                "lodType": "LOD2",
                "rightLng": rightLng,   //9.175336684,
                "topLat": topLat        //48.7822869656
            },
            "cityGMLRef": "campusLOD2",
            "interestedAttributes": [
                "uValue",
                "volume",
                "height",
                "heatedVolume",
                "yearOfConstruction",
                "buildingFunction",
                "monthlyHeating",
                "monthlyCooling",
                "pvPotential",
                "roofType",
                "totalSurfaceArea"                
            ],
            "properies": {
                "physicsUseScenario": false
            }
        }),
        headers: {
            "Content-Type": "application/json",
            "Authorization": "Basic YWRtaW46YWRtaW4xMjM="
        }
    })
    const data = await response.json()
    return data
}

document.getElementById("loader").style.visibility = "hidden"

async function getLocalShadowdata(){
    // gets the response from the api and put it inside a constant
    const response = await fetch(localShadowData);
    //the response have to be converted to json type file, so it can be used
     const data = await response.json();
    console.log(data)
   // shadowData=data;
    return data;
  }

function processData() {
    console.log(coordinatesBB)
    console.log("Waiting for data....")

    timeout(25000, fetchshadowDataJSON()).then((response)=>{        
        console.log(response)  
        shadowdata = response  ;                     
        }).catch((error)=>{ //catching the error(no connection)/ timeout and displaying an alert for the user
     //  shadowdata=  getLocalShadowdata();
        console.log(shadowdata);
        //loadLocalAPIshadowData here...
    }) 

    timeout(10000,  fetchPvPotentialJSON()).then((response)=>{        
        console.log(response)                
     }).catch((error) => {
        console.log(error)
    }) 
    
    
    timeout(10000,  fetchDataJSON()).then((response)=>{        
        calculateData(response);                      
     }).catch((error) => {
        console.log(error)
        /*
        fetch("/3dclient4simstadtapi/public/test/APIdata/buildingInformation.json")
        .then(response => response.text())
        .then(text => calculateData( JSON.parse(text)))
        */
    })

          

   
}



function calculateData(data){
    console.log(data);
    document.getElementById("cesiumContainer").style.opacity = "1";
    document.getElementById("loader").style.visibility = "hidden"
    console.log("....received data")

    var buildingsMAP = new Map()

    data.buildings.forEach(bu => {

        var partsArray = []
        var surefacesArray = []

        bu.parts.forEach(p =>
            p.surfaces.forEach(s =>
                surefacesArray.push(new Surface(s.id,
                    s.attributes.uValue,
                    s.attributes.totalSurfaceArea))))

        bu.parts.forEach(p => partsArray.push(new Part(p.id,
            surefacesArray,
            p.attributes.volume,
            p.attributes.height,
            p.attributes.heatedVolume,
            p.attributes.yearOfConstruction,
            p.attributes.buildingFunction,
            p.attributes.monthlyHeating,
            p.attributes.monthlyCooling,
            p.attributes.roofType)))

        buildingsMAP.set(bu.id, new Building(bu.id, partsArray))  //puts buildings with parts and surfaces in a map

    })

    var partHeightMAP = new Map()
    var partVolumeMAP = new Map()
    var partHeatedVolumeMAP = new Map()
    var partConstructionYearMAP = new Map()
    var partBuildingTypeMAP = new Map()
    var partMonthlyHeatingMAP = new Map()
    var partMonthlyCoolingMAP = new Map()
    var surfaceUValueMAP = new Map()
    var partRoofTypeMAP = new Map()
    var surfaceTotalSurfaceAreaMAP = new Map()

    //fill height, heated volume and construction year map
    buildingsMAP.forEach(b => {
        b.parts.forEach(part => {
            if (part.height !== undefined) {
                partHeightMAP.set(part.id, part.height)
            }
            if (part.volume !== undefined) {
                partVolumeMAP.set(part.id, part.volume)
            }
            if (part.heatedVolume !== undefined) {
                partHeatedVolumeMAP.set(part.id, part.heatedVolume)
            }
            if (part.yearOfConstruction !== undefined && part.yearOfConstruction <= "2020") {
                partConstructionYearMAP.set(part.id, part.yearOfConstruction)
            }
            if (part.buildingFunction !== undefined) {
                partBuildingTypeMAP.set(part.id, part.buildingFunction)
            }
            if (part.monthlyHeating !== undefined) {
                partMonthlyHeatingMAP.set(part.id, part.monthlyHeating)
            }
            if (part.monthlyCooling !== undefined) {
                partMonthlyCoolingMAP.set(part.id, part.monthlyCooling)
            }
            if (part.roofType !== undefined) {
                partRoofTypeMAP.set(part.id, part.roofType)
            }
            part.surfaces.forEach(s => {
                if (s.uValue !== undefined) {
                    surfaceUValueMAP.set(s.id, s.uValue)
                }
            })
            //totalSurfaceArea
            surfaceTotalSurfaceAreaMAP.set(part.id, part.surfaces)
        })
    })

    //sort maps
    const heightSort = new Map([...partHeightMAP.entries()].sort((a, b) => b[1] - a[1]));
    const heatedVolumeSort = new Map([...partHeatedVolumeMAP.entries()].sort((a, b) => b[1] - a[1]));
    const constructionYearSort = new Map([...partConstructionYearMAP.entries()].sort((a, b) => a[1] - b[1]));
    const uValueSort = new Map([...surfaceUValueMAP.entries()].sort((a, b) => b[1] - a[1]));

    //for Properties Single Buildings
    buildingFunctionSortPick = new Map([...partBuildingTypeMAP.entries()].sort((a, b) => b[1] - a[1]));
    constructionYearSortPick = new Map([...partConstructionYearMAP.entries()].sort((a, b) => a[1] - b[1]));
    heightSortPick = new Map([...partHeightMAP.entries()].sort((a, b) => b[1] - a[1]));
    heatedVolumeSortPick = new Map([...partHeatedVolumeMAP.entries()].sort((a, b) => b[1] - a[1]));
    totalSurfaceAreaSortPick = new Map([...surfaceTotalSurfaceAreaMAP.entries()].sort((a, b) => b[1] - a[1]));
    roofTypeSortPick = new Map([...partRoofTypeMAP.entries()].sort((a, b) => b[1] - a[1]));
    uValueSortPick = new Map([...surfaceUValueMAP.entries()].sort((a, b) => b[1] - a[1]));


    //fill arrays needed for charts
    heightSort.forEach((value, key) => addHeightInfosToArrays(key, value))
    heatedVolumeSort.forEach((value, key) => addHeatedVolumeInfosToArrays(key, value))
    constructionYearSort.forEach((value) => yearOfConstructionValues.push(value))
    partBuildingTypeMAP.forEach((value) => buildingTypeValues.push(value))
    partMonthlyHeatingMAP.forEach((valueArray, key) => yearlyHeatingDemand(key, valueArray))
    partMonthlyCoolingMAP.forEach((valueArray, key) => yearlyCoolingDemand(key, valueArray))
    uValueSort.forEach((value, key) => {
        uValueSurfaces(key, value)
        uValuesAll.push(value)
    })

    partMonthlyHeatingMAP.forEach((value, key) => addmonthlyHeatingInfosToArrays(key, value))
    partMonthlyCoolingMAP.forEach((value, key) => addmonthlyCoolingInfosToArrays(key, value))
    partVolumeMAP.forEach((value, key) => addVolumeValues(key, value))

    //calculates year of construction frequency
    yearFrequency()

    //calculates building type frequency
    buildingTypeFrequency()

    //calculates uValue frequency
    uValueFrequency()

    //sorts yearly heating & cooling demand for charts
    sortMap()

    //disables attributes in chart without values
    availableAttributes()

    //color buildings with heating demand
    document.getElementById("checkbox2").addEventListener("change", function () {
        if (this.checked) {
            tileContent.forEach(t => {
                let tileID = t.getProperty("gml_parent_id")
                let tileColor = heatingIDColorMAP.get(tileID)
                if (tileColor !== undefined) {
                    t.color = Cesium.Color.fromCssColorString(tileColor)
                } else {
                    t.color = new Cesium.Color(1, 1, 1, 1)
                }
            })
            console.log("colored")
        } else {
            tileContent.forEach(t => t.color = new Cesium.Color(1, 1, 1, 1))
            console.log("not colored")
        }
    })

    //color surfaces with uValue
    document.getElementById("checkbox1").addEventListener("change", function () {
        if (this.checked) {
            tileContent.forEach(t => {
                let tileID = t.getProperty("gml_id")
                let tileColor = surfaceIDColorMAP.get(tileID)
                if (tileColor !== undefined) {
                    t.color = Cesium.Color.fromCssColorString(tileColor)
                } else {
                    t.color = new Cesium.Color(1, 1, 1, 1)
                }
            })
            console.log("colored")
        } else {
            tileContent.forEach(t => t.color = new Cesium.Color(1, 1, 1, 1))
            console.log("not colored")
        }
    })
}

function showAllUVales() {
    this.parts.forEach(p => p.surfaces.forEach(s => console.log(s.uValue)))
}

function Building(id, parts) {
    this.id = id
    this.parts = parts
    this.showAllUVales = showAllUVales
}

function Part(id, surfaces, volume, height, heatedVolume, yearOfConstruction, buildingFunction, monthlyHeating, monthlyCooling, roofType) {
    this.id = id;
    this.surfaces = surfaces
    this.volume = volume
    this.height = height
    this.heatedVolume = heatedVolume
    this.yearOfConstruction = yearOfConstruction
    this.buildingFunction = buildingFunction
    this.monthlyHeating = monthlyHeating
    this.monthlyCooling = monthlyCooling
    this.roofType = roofType
}

function Surface(id, uValue, totalSurfaceArea) {
    this.id = id;
    this.uValue = uValue
    this.totalSurfaceArea = totalSurfaceArea
}

let tileContent = []

// When the user clicks the button, open the modal
var elemurlevt = document.getElementById("submitID");
elemurlevt.addEventListener("click", loadTileset);

//Get the modal
var modal = document.getElementById("myModal");
var span = document.getElementsByClassName("close")[0];

//close the modal
span.onclick = function () {
    modal.style.display = "none";
    deleteTilesetButtons()
}

// modal closes, when the user clicks anywhere outside of the modal
window.onclick = function (event) {
    if (event.target == modal) {
        modal.style.display = "none";
        deleteTilesetButtons()
    }
}

//-------------------------------------------------------------------------------
var tileData = null;
var tileset = null;
//var tilesetURL = 'http://vm24.fkc.hft-stuttgart.de:8081/CampusLOD2Old/tileset.json';
var tilesetURL = 'http://vm24.fkc.hft-stuttgart.de:8081/CampusLOD2/tileset.json';
var tilesetURLb1 = 'http://vm24.fkc.hft-stuttgart.de:8081/Baue/bau1u3.json';
var tilesetURLb2 = 'http://vm24.fkc.hft-stuttgart.de:8081/Baue/bau2.json';
var tilesetURLb4 = 'http://vm24.fkc.hft-stuttgart.de:8081/Baue/bau4.json';
var tilesetURLb5 = 'http://vm24.fkc.hft-stuttgart.de:8081/Baue/bau5.json';
var tilesetURLb6 = 'http://vm24.fkc.hft-stuttgart.de:8081/Baue/bau6.json';
var tilesetURLb7 = 'http://vm24.fkc.hft-stuttgart.de:8081/Baue/bau7.json';
var tilesetURLb8 = 'http://vm24.fkc.hft-stuttgart.de:8081/Baue/bau8.json';

var localTestTileset = 'test/gmlTileset_v1.json';
var localB1 = 'test/bau1u3.json';
var localB2 = 'test/bau2.json';
var localB4 = 'test/bau4.json';
var localB5 = 'test/bau5.json';
var localB6 = 'test/bau6.json';
var localB7 = 'test/bau7.json';
var localB8 = 'test/bau8.json';


function timeout(ms, promise) {
    return new Promise(function(resolve, reject) {
      setTimeout(function() {
        reject(new Error("timeout"))
      }, ms)
      promise.then(resolve, reject)
    })
}

function pageLoad() {
    if (window.location.hash === "#load-bau1") {
        fetchTileset(tilesetURLb1);
    }if (window.location.hash === "#load-bau2") {
        fetchTileset(tilesetURLb2);
    }if (window.location.hash === "#load-bau4") {
        fetchTileset(tilesetURLb4);
    }if (window.location.hash === "#load-bau5") {
        fetchTileset(tilesetURLb5);
    }if (window.location.hash === "#load-bau6") {
        fetchTileset(tilesetURLb6);
    }if (window.location.hash === "#load-bau7") {
        fetchTileset(tilesetURLb7);
    }if (window.location.hash === "#load-bau8") {
        fetchTileset(tilesetURLb8);
    }
}

//fetching the tileset and handling the connection
async function fetchTileset(tileset){   
    timeout(1000, fetch(tileset)).then((response)=>{        
        loadAndZoomToTileset(tileset);                          
     }).catch((error)=>{ //catching the error(no connection)/ timeout and displaying an alert for the user
        //var errorString = error["stack"]+"\n"+error["message"]; // formatting the error array
        swal({text:"Could not connect to Server. Using now: local data",icon:"info" } );  
        console.log("Using local test data");
        loadAndZoomToTileset(localTestTileset); //TODO#3: fix the link so the local tileset can be loaded
    }) 
}



/*
    NOTE #1:    -load the models but the are in the too high in the "air"
                -building view doesn´t work because all buildings are grouped together
                -surfaces are also broken

            -->this fixme is the problem of the backendteam !

    ? maybe add old menu back and the option to also load the new ones 
    
*/


//loads tileset after submit button is clicked
function loadTileset() {    
    viewer.scene.primitives.remove(tileset);
    tileContent = [];
    modal.style.display = "block";
    
    fetchTileset();
    
    //var userurl = document.getElementById("3Durl").value;   //returns the chosen area from the dropdown    
}
//loads the tileset from the url into the cesium viewer and zooms to it

function loadAndZoomToTileset(url){
    tileset=viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
        
        url: url
    }));
    

    viewer.zoomTo(tileset, new Cesium.HeadingPitchRange(0, -0.5, 0));
            modal.style.display = "none";
            saveTilesetContent(tileset)
            deleteTilesetButtons()
}


function useContent(content) {
    content.forEach(cont => {
        var element = document.createElement("input")
        element.type = "button"
        element.value = cont.title
        element.value = cont.title
        element.name = "individualTileset"

        document.getElementById("myList").appendChild(element);

        element.onclick = function () {
            tileset = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
                url: cont.href
            }));
            viewer.zoomTo(tileset, new Cesium.HeadingPitchRange(0, -0.5, 0));
            modal.style.display = "none";
            saveTilesetContent(tileset)
            deleteTilesetButtons()
        };
    })
}

function saveTilesetContent(tileset) {
    tileset.tileLoad.addEventListener(tile => {
        const content = tile.content;
        for (let i = 0; i < content.featuresLength; i++) {
            let f = content.getFeature(i);
            tileContent.push(f)
        }
    })
}

function deleteTilesetButtons() {
    var x = document.getElementsByName("individualTileset")
    var len = x.length
    
    //checking if there are even tileset to delete
    if(x.length>0){
        parentNode = x[0].parentNode;
        for (var i = 0; i < len; i++) {
            parentNode.removeChild(x[0]);
        }
    }
   
}