$(function () {
    Cesium.Ion.defaultAccessToken =
      "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI5ODI4ZTYyZS1mMTg2LTQ5NGEtYjdiOS02ODg2NzVhNjc0MTAiLCJpZCI6MjkwNCwiaWF0IjoxNTM1MTA5OTAzfQ.kyDX_0ScvJBkYnvXI0DW5NfZbiaRL5ezwtAUhxYnk1Y";
    var imageryViewModels = [];
    imageryViewModels.push(
      new Cesium.ProviderViewModel({
        name: "Sentinel-2",
        iconUrl: Cesium.buildModuleUrl(
          "Widgets/Images/ImageryProviders/sentinel-2.png"
        ),
        tooltip: "Sentinel-2 cloudless.",
        creationFunction: function () {
          return new Cesium.IonImageryProvider({ assetId: 3954 });
        },
      })
    );
  
    imageryViewModels.push(
      new Cesium.ProviderViewModel({
        name: "Blue Marble",
        iconUrl: Cesium.buildModuleUrl(
          "Widgets/Images/ImageryProviders/blueMarble.png"
        ),
        tooltip: "Blue Marble Next Generation July, 2004 imagery from NASA.",
        creationFunction: function () {
          return new Cesium.IonImageryProvider({ assetId: 3845 });
        },
      })
    );
  
    var viewer = new Cesium.Viewer("cesiumContainer", {
      imageryProvider: new Cesium.IonImageryProvider({ assetId: 3954 }),
  
      terrainProvider: new Cesium.CesiumTerrainProvider({
        url: Cesium.IonResource.fromAssetId(1),
      }),
      scene3DOnly: false,
      shouldAnimate: true,
      animation: true,
      infoBox: true,
      baseLayerPicker: true,
      fullscreenButton: false,
      timeline: false,
      navigationHelpButton: true,
      navigationInstructionsInitiallyVisible: false,
      homeButton: false,
      selectionIndicator: true,
      geocoder: true,
      // imageryProviderViewModels: imageryViewModels
    });
  
    // var layer = viewer.imageryLayers.addImageryProvider(
    // 	new Cesium.IonImageryProvider({ assetId: 3 })
    // );
  
    var imageryLayer = viewer.imageryLayers.addImageryProvider(
      new Cesium.IonImageryProvider({ assetId: 3954 })
    );
  
    var canvas = viewer.canvas;
    canvas.setAttribute("tabindex", "0"); // needed to put focus on the canvas
    canvas.addEventListener("click", function () {
      canvas.focus();
    });
    canvas.focus();
    var scene = viewer.scene;
  
    var tileset = viewer.scene.primitives.add(
      new Cesium.Cesium3DTileset({
        url: "buildingTiles/StoeckachLOD1/tileset.json",
        show: true,
      })
    );
  
    tileset.readyPromise.then(function (tileset) {
      return zoomAll(tileset);
    });
  
    tileset.readyPromise.then(function (tileset) {
      var R = 0; // roll
      var P = 0; // pitch
      var Yaw = 0; // yaw
      var height = 53;
      var cartographic = Cesium.Cartographic.fromCartesian(
        tileset.boundingSphere.center
      );
      var surface = Cesium.Cartesian3.fromRadians(
        cartographic.longitude,
        cartographic.latitude,
        0.0
      );
      var offset = Cesium.Cartesian3.fromRadians(
        cartographic.longitude,
        cartographic.latitude,
        height
      );
      var translation = Cesium.Cartesian3.subtract(
        offset,
        surface,
        new Cesium.Cartesian3()
      );
  
      //var rotMat = new Cesium.Matrix3();
      var rotation = new Cesium.Matrix3.fromHeadingPitchRoll(
        new Cesium.HeadingPitchRoll(Yaw, P, R)
      );
  
      tileset.modelMatrix = Cesium.Matrix4.fromRotationTranslation(
        rotation,
        translation
      );
  
      return zoomAll(tileset);
    });
  
    viewer.scene.globe.enableLighting = true; // set lighting to true
  
    var zoomAll = function (tileset) {
      return new Promise(function (resolve, reject) {
        if (!tileset) {
          reject("Tileset is undifined");
        }
        viewer.camera.viewBoundingSphere(
          tileset.boundingSphere,
          new Cesium.HeadingPitchRange(0, -0.5, 1500)
        );
        viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
        resolve();
      });
    };
  
    //////////////////////////////////////////
    // load streamline data from text file and parse it to polyline with multiple colors.
  
    var pos = [];
    var cols = [];
    var streamID = [];
    var Velocity = [];
    var pt_to_pt_dist = [];
    var avgVelocity = [];
    var czmlArray = [];
  
    function get_date_time_dt(deltaTime) {
      // deltaTime should be given in SECONDS and is then converted to milliseconds
      // set deltaTime to 0 if you want to get current date and time
      // set to +60000 to get date and time of 60 seconds = 60000 milliseconds in the future
  
      return (currentdate = new Date(
        new Date().getTime() + deltaTime * 1000
      ).toISOString());
    }
  
    d3.dsv(",", "results/polylines_with_velocity.csv").then(function (text) {
      const particleDuration = 90; // units in seconds the particle / point should take to move from start to finish
      //define the czml structure
      var particle_czml = [
        {
          id: "document",
          name: "CZML Point - Time Dynamic",
          version: "1.0",
        },
        {
          id: "point",
          availability:
            get_date_time_dt(0) + "/" + get_date_time_dt(particleDuration),
          position: {
            epoch: get_date_time_dt(0),
            cartographicDegrees: [
              // use 4 coordinates / values : (t,x,y,z) or rather (t,lon,lat,alt)
            ],
          },
          point: {
            color: {
              rgba: [0, 0, 0, 250],
            },
            outlineColor: {
              rgba: [255, 0, 0, 128],
            },
            outlineWidth: 1,
            pixelSize: 6,
          },
        },
      ];
  
      var temp = text;
      for (var i = 0; i < temp.length; i++) {
        // use i+=7 when parsed as d3.text(...)
        pos.push([
          parseFloat(text[i].Lon),
          parseFloat(text[i].Lat),
          parseFloat(text[i].z),
        ]);
        cols.push([
          parseInt(text[i].R),
          parseInt(text[i].G),
          parseInt(text[i].B),
        ]);
        streamID.push(parseInt(text[i].ID));
        Velocity.push(parseFloat(text[i].velocity));
        avgVelocity.push(parseFloat(text[i].AverageVelocity));
        pt_to_pt_dist.push(parseFloat(text[i].pt_to_pt_dist));
        // use these lines if parsed as text. i.e. using d3.text(...)
        //pos.push([parseFloat(temp[i+0]), parseFloat(temp[i+1]), parseFloat(temp[i+2])]);
        //colors.push([parseFloat(temp[i+3]),parseFloat(temp[i+4]),parseFloat(temp[i+5])])
        //streamID.push([parseFloat(temp[i+6])]);
      }
  
      const maxID = streamID.reduce(function (a, b) {
        return Math.max(a, b);
      });
  
      //find out the unique ids within the streamID array
      const uniqueStreamID = Array.from(new Set(streamID)); // const uniqueStreamID = [...new Set(streamID)]; // same can be done with spread operator
  
      //get index of each unique id, first element of those
      let sIDidx = [];
      for (var i = 0; i <= maxID; i++) {
        var tmpIdx = streamID.indexOf(i);
        if (tmpIdx !== -1) sIDidx.push(tmpIdx);
      }
  
      /////////////////////////////////////////////////
      // Create and draw a polyline with per vertex colors
      /////////////////////////////////////////////////
      const heightOffset = 120;
      for (var line = 0; line < uniqueStreamID.length; line++) {
        let positions = [];
        let positionsInDegrees = [];
        let colors = [];
        let individual_particle_velo = [];
        let individual_particle_pt_distance = [];
        let individual_particle_avg_velo = [];
  
        for (i = sIDidx[line - 1]; i < sIDidx[line] - 1; ++i) {
          positions.push(
            Cesium.Cartesian3.fromDegrees(
              pos[i][0],
              pos[i][1],
              pos[i][2] + heightOffset
            )
          );
          positionsInDegrees.push([
            pos[i][0],
            pos[i][1],
            pos[i][2] + heightOffset,
          ]);
          colors.push(
            Cesium.Color.fromBytes(cols[i][0], cols[i][1], cols[i][2], 180)
          );
          individual_particle_avg_velo.push(avgVelocity[i]);
          individual_particle_pt_distance.push(pt_to_pt_dist[i]);
          individual_particle_velo.push(Velocity[i]);
        }
        // For per segment coloring, supply the colors option with
        // an array of colors for each vertex.  Also set the
        // colorsPerVertex option to true.
        viewer.scene.primitives.add(
          new Cesium.Primitive({
            geometryInstances: new Cesium.GeometryInstance({
              geometry: new Cesium.PolylineGeometry({
                positions: positions,
                width: 5.0,
                vertexFormat: Cesium.PolylineColorAppearance.VERTEX_FORMAT,
                colors: colors,
                colorsPerVertex: true,
              }),
            }),
            appearance: new Cesium.PolylineColorAppearance(),
          })
        );
  
        ////////////////////////////////////////////////
        // Create and prepare particles for movement
        /////////////////////////////////////////////////
        let streamDist = individual_particle_pt_distance.reduce(function (a, b) {
          return a + b;
        }, 0);
      //   console.log(streamDist);
  
        let t = 0;
        let dt = (individual_particle_pt_distance[0] / individual_particle_avg_velo[0])/ 20;
      //   let dt = streamDist / individual_particle_avg_velo[0] / 500;
        let temp_pos = [];
  
        for (i = 0; i < positionsInDegrees.length; i++) {
          if (i === 0) {
            temp_pos.push(
              0,
              positionsInDegrees[i][0],
              positionsInDegrees[i][1],
              positionsInDegrees[i][2]
            );
          } else {
            temp_pos.push(
              t,
              positionsInDegrees[i][0],
              positionsInDegrees[i][1],
              positionsInDegrees[i][2]
            );
            dt = individual_particle_pt_distance[i] /individual_particle_avg_velo[i] / 20;
            // console.log(individual_particle_pt_distance[i] + "/" + individual_particle_avg_velo[i] );
            // console.log(dt);
          }
  
          t += dt;
        }
        particle_czml[1].id = "point" + String(line);
        particle_czml[1].position.cartographicDegrees = temp_pos; 
        
      //   czmlArray.push(particle_czml);
        viewer.dataSources.add(Cesium.CzmlDataSource.load(particle_czml));
      }
      
      // for (p = 0; p < czmlArray.length; p++) {
      // 	let temp = czmlArray[p];
      // 	viewer.dataSources.add(Cesium.CzmlDataSource.load(temp));
      //   }
  
    });
  
    
  
    // This adds a large arrow to the viewer. Works fine. for testing
  
    // var purpleArrow = viewer.entities.add({
    // 	name: "Purple straight arrow at height",
    // 	polyline: {
    // 	  positions: Cesium.Cartesian3.fromDegreesArrayHeights([
    // 		9.187290, 48.784567, 400,
    // 		9.195991, 48.790575, 400
    // 	  ]),
    // 	  width: 50,
    // 	  arcType: Cesium.ArcType.NONE,
    // 	  material: new Cesium.PolylineArrowMaterialProperty(
    // 		Cesium.Color.PURPLE
    // 	  ),
    // 	},
    //   });
  
    // var f = new File([""], "results/singlePolyline.csv", {type: "text/plain", lastModified: Date()})
  
    // var temp = text.split(',');
    //   for(var i = 0; i < temp.length; i+=6) {
    //     pos.push([parseFloat(temp[i+1]), parseFloat(temp[i+2]), parseFloat(temp[i+3])]);
    //     colors.push([parseInt(temp[i+4]),parseInt(temp[i+5]),parseInt(temp[i+6])])
    //   }
  
    console.log("Position data imported.");
  
    //// the following codes will actually generate multicolor polylines
    /// just need a away to get the actual data into there...
    ///
    ///
    // for (var line=0; line < 10; line++){
    // 	// Example 2: Draw a polyline with per vertex colors
    // 	positions = [];
    // 	colors = [];
    // 	for (i = 0; i < 12; ++i) {
    // 	  positions.push(Cesium.Cartesian3.fromDegrees(-124.0 + line*5 + 5 * i, 35.0+line));
    // 	  colors.push(Cesium.Color.fromRandom({ alpha: 1.0 }));
    // 	}
    // 	// For per segment coloring, supply the colors option with
    // 	// an array of colors for each vertex.  Also set the
    // 	// colorsPerVertex option to true.
    // 	scene.primitives.add(
    // 	  new Cesium.Primitive({
    // 		geometryInstances: new Cesium.GeometryInstance({
    // 		  geometry: new Cesium.PolylineGeometry({
    // 			positions: positions,
    // 			width: 5.0,
    // 			vertexFormat: Cesium.PolylineColorAppearance.VERTEX_FORMAT,
    // 			colors: colors,
    // 			colorsPerVertex: true,
    // 		  }),
    // 		}),
    // 		appearance: new Cesium.PolylineColorAppearance(),
    // 	  })
    // 	);
    // 	}
  
    // HTML overlay for showing feature name on mouseover
    var 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 = "green";
  
    var scene = viewer.scene;
    var longitude;
    var latitude;
    var fid;
    var featuretype;
    var gmlid;
    var selID = new Array();
    var cnt = 0;
    var lastPickedObject;
  
    var viewModel = {
      rightClickAction: "properties",
      middleClickAction: "hide",
    };
  
    Cesium.knockout.track(viewModel);
  
    var handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
  
    handler.setInputAction(function (movement) {
      // makes camera go to a certain position given by the coordinates below
  
      var feature = viewer.scene.pick(movement.position);
      if (!Cesium.defined(feature)) {
        console.log("no feature defined");
        return;
      }
      var propertyNames = feature.getPropertyNames();
      var lat = feature.getProperty("Latitude");
      var lon = feature.getProperty("Longitude");
      var tmp = feature.getProperty("YearOfConstruction");
  
      viewer.camera.flyTo({
        destination: Cesium.Cartesian3.fromDegrees(lon, lat, 900),
        maximumHeight: 1500.0,
        orientation: {
          heading: Cesium.Math.toRadians(0.0),
          pitch: Cesium.Math.toRadians(-90.0),
          roll: Cesium.Math.toRadians(45.0),
        },
        duration: 2,
      });
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
  
    handler.setInputAction(function (movement) {
      var feature = viewer.scene.pick(movement.position);
      if (!Cesium.defined(feature)) {
        return;
      }
      var action = viewModel.rightClickAction;
      action === "properties";
      printProperties(movement, feature);
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
  
    function printProperties(movement, feature) {
      console.log("Properties:");
      var propertyNames = feature.getPropertyNames();
      var length = propertyNames.length;
      for (var i = 0; i < length; ++i) {
        var propertyName = propertyNames[i];
        if (
          propertyName == "gmlIdALKISLageBezeichnung_1" ||
          propertyName == "gmlIdALKISLageBezeichnung_2" ||
          propertyName == "gmlIdALKISLageBezeichnung_3" ||
          propertyName == "gmlIdALKISLageBezeichnung_4" ||
          propertyName == "gmlIdALKISLageBezeichnung_5" ||
          propertyName == "gmlIdALKISLageBezeichnung_6"
        )
          console.log("  " + propertyName + ": " + "zensiert");
        else
          console.log(
            "  " + propertyName + ": " + feature.getProperty(propertyName)
          );
      }
  
      // Evaluate feature description
      //console.log('Description : ' + tileset.style.meta.description.evaluate(scene.frameState, feature));
    }
  
    handler.setInputAction(function (movement) {
      var feature = viewer.scene.pick(movement.position);
      if (!Cesium.defined(feature)) {
        return;
      }
  
      var action = viewModel.middleClickAction;
      if (action === "hide") {
        feature.show = false;
      } else {
        feature.show = true;
      }
    }, Cesium.ScreenSpaceEventType.MIDDLE_CLICK);
  
    function showLegend() {
      $("#legend").css("display", "block");
    }
    function hideLegend() {
      $("#legend").css("display", "none");
    }
  
    // Legend - Colour Table
    function emptyColourTable() {
      $(".inner").empty();
    }
  
    function setHeightTable() {
      $(".inner").append(
        "<table>" +
          "<tr><td class='outlined' bgcolor='red'>&nbsp;&nbsp;&nbsp;&nbsp;</td><td> > 3.5 </td></tr>" +
          "<tr><td class='outlined' bgcolor='#ff6b21'></td><td> 3 </td></tr>" +
          "<tr><td class='outlined' bgcolor='#ffb400'></td><td> 2.5 </td></tr>" +
          "<tr><td class='outlined' bgcolor='yellow'></td><td> 2</td></tr>" +
          "<tr><td class='outlined' bgcolor='#89FF8F'></td><td> 1.5 </td></tr>" +
          "<tr><td class='outlined' bgcolor='cyan'></td><td> 1 </td></tr>" +
          "<tr><td class='outlined' bgcolor='blue'></td><td> 0.5 </td></tr>" +
          "</table>"
      );
    }
  
    return Cesium.when(tileset.readyPromise).then(function (tileset) {
      tileset.style = new Cesium.Cesium3DTileStyle({
        color: "color('white',1)",
      });
      showLegend();
      setHeightTable();
    });
  });
  