const selColor = "#FF5C26";
let d = [{
  label:"Altitude,m",
  data:[], 
  yaxis: 2
},
{
  label:"Speed,km/h",
  data:[]
}];

let options = {
  xaxis: {
    mode: "time",
    tickLength: 5,
    zoomRange: [60 * 1000, 1000 * 3600 * 24 * 365]
  },
  /*selection: {
    mode: "x",
    color: selColor
  },*/
  yaxes: [{
    min: 0,
    zoomRange: false,
    panRange: false
  }, {
    position: "right",
    alignTicksWithAxis: 1,
    min: 0,
    zoomRange: false,
    panRange: false
  }],
  zoom: {
    interactive: true
  },
  pan: {
    interactive: true,
    cursor: "move",
    frameRate: 60
  }
};
let optO = {
  legend : {
    show: false
  },
  series: {
    lines: {
      show: true,
      lineWidth: 1
    },
    shadowSize: 0
  },
  xaxis: {
    //ticks: [],
    mode: "time"
  },
  yaxis: {
    ticks: [],
    autoscaleMargin: 0.1
  },
  selection: {
    mode: "x",
    color: selColor,
    minSize: 0
  }
};

let gps = new GPS();
let plot, overview;

window.onload = function() {
  fetch("secrets")
    .then(response => response.json())
    .then(secrets => {
      Cesium.Ion.defaultAccessToken = secrets.cesium_token
      
      var extent = {west: -0.2540382220862719, south: 0.6872565916005104, east: 0.6129855406042352, north: 0.9377043806513488};

      Cesium.Camera.DEFAULT_VIEW_RECTANGLE = extent;
      Cesium.Camera.DEFAULT_VIEW_FACTOR = 0;
      
      bingMapsProvider = new Cesium.BingMapsImageryProvider({
        url: 'https://dev.virtualearth.net',
        key: secrets.bing_maps_key,
        mapStyle: Cesium.BingMapsStyle.AERIAL_WITH_LABELS
      });

      viewer = new Cesium.Viewer('map', {
        fullscreenElement: "map",
        terrainProvider : Cesium.createWorldTerrain({
          requestVertexNormals: true,
          requestWaterMask: true
        }),
        //shadows: true
      });
      viewer.scene.globe.enableLighting = true;
      viewer.resolutionScale = 1.2;
      viewer.scene.screenSpaceCameraController.enableTilt = !('ontouchstart' in window);
      viewer.baseLayerPicker.viewModel.selectedImagery = new Cesium.ProviderViewModel({
        name: 'Bing Maps Aerial with Labels',
        iconUrl: Cesium.buildModuleUrl('Widgets/Images/ImageryProviders/bingAerialLabels.png'),
        tooltip: 'Bing Maps aerial imagery with labels',
        creationFunction: function () {
          return bingMapsProvider
        }
      });
      var paths = [];

      fetch("trips")
        .then(response => response.json())
        .then(jsonResponse => {
          gps.parse(jsonResponse);
          for(const t of gps.trips) {
            var desc = `Region: ${t.name}<br/>` +
                  `Start: <b>${timeFormat(t.startTime, "datetime")}</b><br/>` + 
                  `Finish: <b>${timeFormat(t.endTime, "datetime")}</b><br/>` +
                  `Track time (full): ${timeFormat(t.totalTime)}<br>` +
                  `Track time (mov.): ${timeFormat(t.movementTime)}<br>` +
                  `Alt: &uarr;${t.ascendHeight.toFixed(1)}m  &darr;${t.descendHeight.toFixed(1)}m<br/>` +
                  `Distance: ${(t.distance/1000).toFixed(1)}km<br/>` +
                  `top speed: ${t.topSpeed.toFixed(1)}km/h<br/>` +
                  `average speed: ${t.avgSpeed.toFixed(1)}km/h`;

            const col = Cesium.Color.fromCssColorString(t.color)
            var path = viewer.entities.add({
              name : `Track ${t.id}`,
              id: `track_${t.id}`,
              description: desc,
              polyline : {
                positions : t.path.map(p => Cesium.Cartesian3.fromDegrees(p.lng, p.lat, p.alt)),
                width : 5,
                material : new Cesium.PolylineOutlineMaterialProperty({
                  color : col,
                }),
                //clampToGround: true,
                depthFailMaterial: new Cesium.PolylineOutlineMaterialProperty({
                  color : Cesium.Color.fromAlpha(col, 0.6),
                }),
                shadows: Cesium.ShadowMode.ENABLED
              }
            });
            paths.push(path);
          }
          var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
          handler.setInputAction(function (movement) {
            var pick = viewer.scene.pick(movement.position);
            if (Cesium.defined(pick) && (pick.id._id.match(/track_([0-9]+)/))) {
              var id = parseInt(RegExp.$1);
              var path = paths[id];
              show(id);
            }
          }, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);

          viewer.flyTo(paths[paths.length - 1], { offset: new Cesium.HeadingPitchRange(0, -90, 0)});
          let regionIndex = 0;
          for(let r=0; r<gps.regions.length; r++) {
            addInfo(bingMapsProvider, viewer, regionIndex, gps.regions[r]);
            regionIndex++;
          }
          const i = gps.getInfo();
          var html =
            `Time (full): ${timeFormat(i.totalTime)}<br>` +
            `Time (mov.): ${timeFormat(i.movementTime)}<br>` +
            `Alt: &uarr;${(i.ascendHeight).toFixed(1)}m  &darr;${(i.descendHeight).toFixed(1)}m<br/>` +
            `Distance: <b>${(i.distance/1000).toFixed(1)}km</b><br/>` +
            `Top speed: <b>${i.topSpeed.toFixed(1)}km/h</b><br/>` +
            `Avg. speed: ${i.avgSpeed.toFixed(1)}km/h<br/>` +
            `Data points: ${i.points}<br/>` +
            `<a href='javascript:show(${(gps.trips.length-1)})'>Graph</a>`;
          
          $(".status").append(html);

        });
    });

  plot = $.plot("#placeholder", d, options);
  overview = $.plot("#overview", d, optO);
  // now connect the two

  $("#placeholder").bind("plotpan", updateOverview);
  $("#placeholder").bind("plotzoom", updateOverview);
  function updateOverview(event, ranges) {
    var axes = plot.getAxes();
    for(var axis in axes) {
      axes[axis].from = axes[axis].min;
      axes[axis].to = axes[axis].max;
    }
    overview.setSelection(axes, true);
  }
  $("#overview").bind("plotselected", function (event, ranges) {
    $.each(plot.getXAxes(), function(_, axis) {
      var opts = axis.options;
      opts.min = ranges.xaxis.from;
      opts.max = ranges.xaxis.to;
    });
    plot.setupGrid();
    plot.draw();
  });
  
  $("#whole").click(function () {
    setZoom(false,false);
  });
  $("#right").click(function () {
    var min = plot.getXAxes()[0].options.min;
    var max = plot.getXAxes()[0].options.max;
    if(min != null && max != null)
      setZoom((min+max)/2, max * 1.5 - min/2);
  });
  $("#left").click(function () {
    var min = plot.getXAxes()[0].options.min;
    var max = plot.getXAxes()[0].options.max;
    if(min != null && max != null)
      setZoom(min * 1.5 - max/2, (min+max)/2);
  });
}

let firstShow = true;

function show(id) {
  if(firstShow) {
    firstShow = false;
    
    d[0].data = smoothOut(gps.data.map(v => v.alt), 0.85);
    d[1].data = smoothOut(gps.data.map(v => v.speed), 0.85);
    
    for(let i=0; i<gps.data.length; i++) {
      const cur = gps.data[i];
      if((cur.timeDiff > 60 && cur.speed < 0.5) || cur.speed === null) {
        d[0].data[i] = null;
        d[1].data[i] = null;
      }
      d[0].data[i] = [cur.timestamp*1000, d[0].data[i]];
      d[1].data[i] = [cur.timestamp*1000, d[1].data[i]];
    }
    let opts = plot.getXAxes()[0].options;
    opts.panRange = [
      gps.data[0].timestamp*1000,
      gps.data[gps.data.length-1].timestamp*1000
    ];
    
    plot.setData(d);
    plot.setupGrid(); //only necessary if your new data will change the axes or grid
    plot.draw();
    overview.setData(d);
    overview.setupGrid(); //only necessary if your new data will change the axes or grid
    overview.draw();
    
    for(let t of gps.trips) {
      $("#tracks").append(`<li><input type='button' onclick='setZoom(${t.startTime*1000}, ${t.endTime*1000})' value='${timeFormat(t.startTime, "date")} ${t.name} ${(t.distance/1000).toFixed(1)}km'</li>`);
    }
  }
  
  $("#shadow").css("visibility", "visible");
  $("#frame").css("visibility", "visible");
  console.log(id);
  
  let start = gps.trips[id].startTime*1000;
  let end = gps.trips[id].endTime*1000;
  
  setZoom(start,end);
  
  $("#track").click(function () {
    setZoom(start,end);
  });
};
function hide() {
  $(".popup").css("visibility", "hidden");
};
function setZoom(Xmin, Xmax) {
  var opts = plot.getXAxes()[0].options;
  if(Xmax==false) {
    Xmax = +new Date() - 60 * new Date().getTimezoneOffset() * 1000;
  }
  if(Xmin==false) {
    Xmin = d[0].data[0][0];
    overview.clearSelection();
  } else {
    overview.setSelection({ xaxis: { from: Xmin, to: Xmax}});
  }
  opts.min=Xmin;
  opts.max=Xmax;

  plot.setupGrid();
  plot.draw();
  plot.clearSelection();

  return false;
}

function addInfo(bingMapsProvider, viewer, id, data) {
  $('.sidebar').append(`<div class='info' id='info_${id}'>` + 
    timeFormat(data.timestamp, "short") + "<br>" +
    data.name + "<br><b>" +
    (data.distance/1000).toFixed(1) + " km</b></div>");
    
  $('#info_'+id).click(function() {
    viewer.camera.flyTo({
      destination: Cesium.Cartesian3.fromDegrees(data.lng, data.lat, data.distance),
      offset: new Cesium.HeadingPitchRange(0, -90, 0)
    });
  });
}
