"use strict";


// Functions
import {
    aggregateResponse,
    switchDayMonth_inDate,
    whereIsDateInArray,
} from "./aggregation.js";


// Functions
import {
    getDatastreamIdFromBuildingNumber,
    getObservationsUrl,
    createTemporalFilterString,
    formatSTAResponseForHeatMap,
    drawHeatMapHC,
    formatSTAResponseForLineChart,
    drawLineChartHC,
    followNextLink,
} from "./appChart.js";

// Constants
import {
    BASE_URL,
    PARAM_RESULT_FORMAT,
    PARAM_ORDER_BY,
    PARAM_SELECT,
} from "./appChart.js";

var ALLDATA = [];
var bld = 0;

Cesium.Ion.defaultAccessToken =
    "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIyODgxYzJlNi1kNDZiLTQ3ZmQtYmUxYy0yMWI0OGM3NDA5MzAiLCJpZCI6NDczOSwic2NvcGVzIjpbImFzciIsImdjIl0sImlhdCI6MTU0MTUyMzU0MX0.shj2hM3pvsvcmE_wMb2aBDuk_cKWmFmbolltInGImwU";

// Flag to determine models that will be loaded
// Set to `true` or `false`
const LOAD_DETAILED_BLDG225 = false;

// Global variable
const viewer = new Cesium.Viewer("cesiumGlobeContainer", {
    scene3DOnly: true,
    imageryProvider: Cesium.createOpenStreetMapImageryProvider({
        url: "https://a.tile.openstreetmap.org/",
    }),
});

/**
 * Load and zoom to the extents of 3DTiles
 * @param {String} urlTiles URL to the 3DTiles to be loaded
 * @returns {undefined} undefined
 */
const loadTiles = function(urlTiles) {
    const tileset = new Cesium.Cesium3DTileset({
        url: urlTiles,
    });
    viewer.scene.primitives.add(tileset);

    tileset.readyPromise.then(function() {
        viewer
            .zoomTo(
                tileset,
                new Cesium.HeadingPitchRange(
                    0.0, -0.5,
                    tileset.boundingSphere.radius / 0.5
                )
            )
            .otherwise(function(err) {
                throw err;
            });
    });
};

/**
 * Load 3DTiles for all the buildings; ignore any glTF models
 * @param{*}
 * @returns {undefined} undefined
 */
const loadNonDetailed = function() {
    // Paths to data sources
    const URL_3DTILES = "data_3d/3dtiles/1_full/tileset.json";

    // Tileset with all buildings
    loadTiles(URL_3DTILES);
};

/**
 * Load glTF models
 * @param {String} gltfUrl Path to the folder containing the glTF models
 * @param {String} gltfId Name of the glTF model file without the extension i.e. exclude the `.gltf` suffix
 * @returns {undefined} undefined
 */
const gltfLoad = function(gltfUrl, gltfId) {
    const modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(
        Cesium.Cartesian3.fromDegrees(9.083385, 48.881342, 0)
    );

    viewer.scene.primitives.add(
        Cesium.Model.fromGltf({
            url: `${gltfUrl}/${gltfId}.gltf`,
            modelMatrix: modelMatrix,
            scale: 0.0254,
            allowPicking: true,
        })
    );
};

/**
 * Load detailed glTF models for Building 225 and 3DTiles for the rest of the buildings
 * @param{*}
 * @returns {undefined} undefined
 */
const loadDetailed = function() {
    // Paths to data sources
    const URL_3DTILES = "data_3d/3dtiles/2_partial/tileset.json";
    const URL_GLTF = "data_3d/gltf";

    // Tileset without building 225
    loadTiles(URL_3DTILES);

    // Load Building 225
    gltfLoad(URL_GLTF, "bosch_si225_3");

    // Load sensors in Building 225
    const gltfArray = [
        "sensor_013",
        "sensor_023",
        "sensor_033",
        "sensor_053",
        "sensor_063",
        "sensor_073",
        "sensor_083",
        "sensor_093",
        "sensor_103",
        "sensor_113",
        "sensor_123",
        "sensor_133",
        "sensor_143",
        "sensor_153",
        "sensor_163",
        "sensor_173",
        "sensor_183",
        "sensor_213",
        "sensor_223",
        "sensor_233",
        "sensor_253",
        "sensor_263",
        "sensor_273",
        "sensor_283",
        "sensor_293",
        "sensor_303",
        "sensor_313",
        "sensor_323",
        "sensor_333",
        "sensor_343",
        "sensor_353",
        "sensor_363",
        "sensor_373",
        "sensor_383_v2",
    ];

    gltfArray.forEach((sensor) => gltfLoad(URL_GLTF, sensor));
};

if (!LOAD_DETAILED_BLDG225) {
    // Default case: load only 3dTiles
    loadNonDetailed();
} else {
    // Alternative case: load 3dTiles + glTF
    loadDetailed();
}

/**
 * Activate feature picking for the displayed 3DTiles
 * @param {*}
 * @returns {undefined}
 */
const activate3DTileFeaturePicking = function() {
    // HTML overlay for showing feature name on mouseover
    const nameOverlay = document.createElement("div");
    viewer.container.appendChild(nameOverlay);
    nameOverlay.className = "backdrop";
    nameOverlay.style.display = "none";
    nameOverlay.style.position = "absolute";
    nameOverlay.style.bottom = "0";
    nameOverlay.style.left = "0";
    nameOverlay.style["pointer-events"] = "none";
    nameOverlay.style.padding = "4px";
    nameOverlay.style.backgroundColor = "black";
    nameOverlay.style.color = "white";
    nameOverlay.style.fontFamily = "Fira Sans, sans-serif";
    nameOverlay.style.fontSize = "0.75em";

    // Information about the currently selected feature
    const selected = {
        feature: undefined,
        originalColor: new Cesium.Color(),
    };

    // An entity object which will hold info about the currently selected feature for infobox display
    const selectedEntity = new Cesium.Entity();

    // Get default left click handler for when a feature is not picked on left click
    const clickHandler = viewer.screenSpaceEventHandler.getInputAction(
        Cesium.ScreenSpaceEventType.LEFT_CLICK
    );

    // Change the feature color on mouse over

    // Information about the currently highlighted feature
    const highlighted = {
        feature: undefined,
        originalColor: new Cesium.Color(),
    };

    // Color a feature on hover.
    viewer.screenSpaceEventHandler.setInputAction(function onMouseMove(movement) {
        // If a feature was previously highlighted, undo the highlight
        if (Cesium.defined(highlighted.feature)) {
            highlighted.feature.color = highlighted.originalColor;
            highlighted.feature = undefined;
        }
        // Pick a new feature
        const pickedFeature = viewer.scene.pick(movement.endPosition);
        if (!Cesium.defined(pickedFeature)) {
            nameOverlay.style.display = "none";
            return;
        }
        // A feature was picked, so show it's overlay content
        nameOverlay.style.display = "block";
        nameOverlay.style.bottom =
            viewer.canvas.clientHeight - movement.endPosition.y + "px";
        nameOverlay.style.left = movement.endPosition.x + "px";
        let name = pickedFeature.getProperty("_gebaeude");
        if (!Cesium.defined(name)) {
            name = pickedFeature.getProperty("id");
        }
        nameOverlay.textContent = name;
        // Highlight the feature if it's not already selected.
        if (pickedFeature !== selected.feature) {
            highlighted.feature = pickedFeature;
            Cesium.Color.clone(pickedFeature.color, highlighted.originalColor);
            pickedFeature.color = Cesium.Color.GREY;
        }
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

    // Color a feature on selection and show metadata in the InfoBox.
    viewer.screenSpaceEventHandler.setInputAction(function onLeftClick(movement) {
        // If a feature was previously selected, undo the highlight
        if (Cesium.defined(selected.feature)) {
            selected.feature.color = selected.originalColor;
            selected.feature = undefined;
        }
        ALLDATA = [];
        cnt = 0;
        // Pick a new feature
        const pickedFeature = viewer.scene.pick(movement.position);
        if (!Cesium.defined(pickedFeature)) {
            clickHandler(movement);
            return;
        }
        // Select the feature if it's not already selected
        if (selected.feature === pickedFeature) {
            return;
        }
        selected.feature = pickedFeature;
        // Save the selected feature's original color
        if (pickedFeature === highlighted.feature) {
            Cesium.Color.clone(highlighted.originalColor, selected.originalColor);
            highlighted.feature = undefined;
        } else {
            Cesium.Color.clone(pickedFeature.color, selected.originalColor);
        }
        // Highlight newly selected feature
        pickedFeature.color = Cesium.Color.LIME;
        // Set feature infobox description
        const featureName = pickedFeature.getProperty("name");
        selectedEntity.name = featureName;
        selectedEntity.description =
            'Loading <div class="cesium-infoBox-loading"></div>';
        viewer.selectedEntity = selectedEntity;
        selectedEntity.description = `
    <table class="cesium-infoBox-defaultTable">
      <tbody> 
        <tr><th>Bau</th><td>
        ${pickedFeature.getProperty("_gebaeude")} 
        </td></tr> 
        <tr><th>Nutzung</th><td>
        ${pickedFeature.getProperty("_nutzung")}
        </td></tr>
        <tr><th>Baujahr</th><td>
        ${pickedFeature.getProperty("_baujahr")}
        </td></tr>
        <tr><th>Geschosse</th><td>
        ${pickedFeature.getProperty("_geschosse")} 
        </td></tr>
        <tr><th>Gebäudefläche (m<sup>2</sup>)</th><td>
        ${pickedFeature.getProperty("_gebaeudeflaeche")} 
        </td></tr>
      </tbody>
    </table>
    `;

        const clickedBuilding = pickedFeature.getProperty("_gebaeude");
        const clickedBuildingDatastreamId = getDatastreamIdFromBuildingNumber(
            clickedBuilding,
            "vl",
            "60min"
        );

        const BASE_URL_OBSERVATIONS = getObservationsUrl(
            BASE_URL,
            clickedBuildingDatastreamId
        );
        const PARAM_FILTER = createTemporalFilterString("2020-01-01", "2021-01-01");

        // const axiosGetRequest = axios.get(BASE_URL_OBSERVATIONS, {
        //     params: {
        //         "$resultFormat": PARAM_RESULT_FORMAT,
        //         "$orderBy": PARAM_ORDER_BY,
        //         "$filter": PARAM_FILTER,
        //         "$select": PARAM_SELECT,
        //     },
        // });

        const BUILDING_STREAM_ID = [75, 76, 77, 78, 79, 80];
        const BUILDING_ID = ["101", "102", "107", "112, 118", "125", "225"];
        // ALLDATA = [];
        var cnt = 0;


        for (bld = 0; bld < BUILDING_STREAM_ID.length; bld++) {

            var baseUrlBld = getObservationsUrl(BASE_URL, BUILDING_STREAM_ID[bld]);
            const axiosGetRequest = axios.get(baseUrlBld, {
                params: {
                    "$resultFormat": PARAM_RESULT_FORMAT,
                    "$orderBy": PARAM_ORDER_BY,
                    "$filter": PARAM_FILTER,
                    "$select": PARAM_SELECT,
                },
            });

            // Get "ALL" the Observations that satisfy our query
            followNextLink(axiosGetRequest)
                .then((success) => {
                    const successValue = success.data.value;

                    // Array that will hold the combined observations
                    const combinedObservations = [];

                    successValue.forEach((dataObj) => {
                        // Each page of results will have a dataArray that holds the observations
                        const dataArrays = dataObj.dataArray;

                        combinedObservations.push(...dataArrays);
                    });
                    // DEBUG: Check total number of observations
                    // console.log(combinedObservations.length);
                    // DEBUG: Print the array of observations
                    // console.log(combinedObservations);

                    return combinedObservations;
                })
                .catch((err) => {
                    console.log("ERROR: ")
                    console.log(err);
                })
                .then((observationArr) => {
                    var agg = aggregateResponse(observationArr, 0, 'mean');
                    var tmpObj = {
                        BldID: BUILDING_ID[cnt],
                        streamID: BUILDING_STREAM_ID[cnt],
                        timestamp: agg.aggDates,
                        data: agg.aggVals,
                    };
                    ALLDATA.push(tmpObj);
                    // console.log(agg);

                    drawHeatMapHC(formatSTAResponseForHeatMap(agg.originalFormat));
                    drawLineChartHC(formatSTAResponseForLineChart(agg.originalFormat));

                    if (ALLDATA.length == 6) {
                        var selectedDate = document.getElementById("DateSelected").innerHTML;

                        var date = new Date(
                            Date.parse(
                                switchDayMonth_inDate(selectedDate)
                            )
                        );

                        var p = whereIsDateInArray(ALLDATA[0].timestamp, date);
                        const DATA = getDataForAllBuildingsPerDate(p);
                        colorBlds(DATA);
                        console.log(date);
                    }

                    console.log(ALLDATA.length);
                    cnt++

                    // alert('waiting...');
                });



        }


    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

};

activate3DTileFeaturePicking();

function goon(ALLDATA) {

    if (ALLDATA.length > 0) {
        var selectedDate = document.getElementById("DateSelected").innerHTML;

        var date = new Date(
            Date.parse(
                switchDayMonth_inDate(selectedDate)
            )
        );

        var p = whereIsDateInArray(ALLDATA[0].timestamp, date);
        const DATA = getDataForAllBuildingsPerDate(p);
        colorBlds(DATA);
        console.log(date);
    }
}



// /**
//  * 
//  * @param {Number} datePos 
//  */

export const getDataForAllBuildingsPerDate = function(datePos) {

    var dataObjPerBld = [];
    var dataArray = [];
    for (var i = 0; i < ALLDATA.length; i++) {

        var tmp = {
            BldId: ALLDATA[i].BldID,
            dateVal: ALLDATA[i].timestamp[datePos],
            dataVal: ALLDATA[i].data[datePos]
        };
        dataArray.push(tmp.dataVal);
        dataObjPerBld.push(tmp);
    }


    return {
        dataPerBld: dataObjPerBld,
        dataArray: dataArray
    };
}

export const colorBlds = function(bldInfo) {


    // see: https://github.com/PimpTrizkit/PJs/wiki/12.-Shade,-Blend-and-Convert-a-Web-Color-(pSBC.js)
    const RGB_Linear_Blend = (p, c0, c1) => {
        var i = parseInt,
            r = Math.round,
            P = 1 - p,
            [a, b, c, d] = c0.split(","),
            [e, f, g, h] = c1.split(","),
            x = d || h,
            j = x ? "," + (!d ? h : !h ? d : r((parseFloat(d) * P + parseFloat(h) * p) * 1000) / 1000 + ")") : ")";
        return "rgb" + (x ? "a(" : "(") + r(i(a[3] == "a" ? a.slice(5) : a.slice(4)) * P + i(e[3] == "a" ? e.slice(5) : e.slice(4)) * p) + "," + r(i(b) * P + i(f) * p) + "," + r(i(c) * P + i(g) * p) + d;
    }

    // get the gradient colors between the two defined colors;
    const c1 = "rgb(255,64,0)";
    const c2 = "rgb(63,131,163)";
    var L = bldInfo.dataArray.length;
    var offset = 1 / (L - 1);
    var colorsForBld = [];
    var p = 0;
    for (var i = 0; i < L; i++) {
        var cnew = RGB_Linear_Blend(p, c1, c2);
        cnew = cnew.replace('undefined', ')');
        colorsForBld.push(cnew);
        p += offset;
        console.log(p);
    }

    var numbers = bldInfo.dataArray,
        ma = numbers.reduce(function(a, b) { return Math.max(a, b); }),
        mi = numbers.reduce(function(a, b) { return Math.min(a, b); }),
        dif = ma - mi,
        l = numbers.length,
        i;

    for (i = 0; i < l; i++) {
        numbers[i] = (numbers[i] - mi) / dif;
    }

    function sortWithIndeces(toSort) {
        for (var i = 0; i < toSort.length; i++) {
            toSort[i] = [toSort[i], i];
        }
        toSort.sort(function(left, right) {
            return left[0] < right[0] ? -1 : 1;
        });
        toSort.sortIndices = [];
        for (var j = 0; j < toSort.length; j++) {
            toSort.sortIndices.push(toSort[j][1]);
            toSort[j] = toSort[j][0];
        }
        return toSort;
    }


    sortWithIndeces(numbers);
    // alert(numbers.sortIndices.join(","));
    var sortedIndices = numbers.sortIndices;
    // convert object to array
    var i = 0,
        arr = [];
    for (var ob in inputObj)
        arr[i++] = ob;


    // numbers = (6)[0.37684400819550146, 0, 0.5862015830883935, 1, 0.444816858861194, 0.9179110359561272],

    console.log(numbers);
    // assign the color to the buildings based on their id
    // var sortedValues = bldInfo.dataArray.sort

    // if (!Cesium.defined(name)) {
    //     name = pickedFeature.getProperty("id");
    // }

}