/* Bakalarska prace
   Tema: Automaticka identifikace manevru ze zaznamu letovych dat
   Autor: Vit Morkovsky (xmorko03)
   Datum: 29.04.2023*/

//autorizacni token k Cesium
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI5ZDY1ODhhMS0wNzc0LTQ1YTItOWJhYy1iYWNlMTE5NTA2OWEiLCJpZCI6MTA1NDc1LCJpYXQiOjE2NjExNTExMTl9.zWu_uUEVl7Dz6DpSAvrvkYkZP5diMN73aZhHiNqw5nU';
var gliderModel = 1276075; //ID kluzaku


//nejdrive je vzdy nactena scenerie s mapou
const viewer = new Cesium.Viewer('cesiumContainer', {
  terrainProvider: Cesium.createWorldTerrain(),
  shouldAnimate: true,
  maximumRenderTimeChange: Infinity
});
var flightCount = 0;

//funkce pro zpracovani a pridani jednoho letu
document.getElementById('flightAddCall').addEventListener('click', function () {
  flightCount = flightCount + 1;
  flightAdd();
})


//funkce pro oddelani letu, ktera aktualizuje stranku
document.getElementById('flightRemoveCall').addEventListener('click', function () {
  location.reload();
})


//vybrani dokumentu a prevedeni formatu igc na format JSON
async function flightAdd() {
  //specifikovani typu
  const fileType = {
    types: [
      {
        description: "Soubor IGC",
        accept: {
          "igc/*": [".igc"],
        },
      },
    ],
    excludeAcceptAllOption: true,
    multiple: false, //lety jsou pridavane po jednom
  };

  //nacteni souboru igc do promene
  let [fileHandle] = await window.showOpenFilePicker(fileType);
  let fileData = await fileHandle.getFile();
  let text = await fileData.text();
  //data pripravena v retezci
  parse(text);
}

/**
 * Hlavni funkce odkud jsou volané vsechny podfunkce pro nastaveni cesiumJS a pripraveni vstupnich dat
 * 
 * @param {string} text vstupni igc soubor v retezci 
 */

function parse(text) {
  var line = text.split("\n")
  var text2 = [];
  var textMarkov = [];
  var turnpoints = [];
  var radiusArray = [];
  let TRTindexStart, TRTindexEnd, TRTinMeter = 0;
  let TASIndexStart, TASIndexEnd = 0;
  let pointPosition = 0;
  let pointCounter = -2;
  let date1 = 0;

  let pevTime = 0;
  let countB = 0;
  let timeStamp = 0;
  let GSPindexStart, GSPindexEnd = 0;
  var gliderId, compationId, pilot, recorderType = "";


  if (line[1].indexOf("HFDTEDATE") == 0) {
    date1 = line[1].substring(10, 16);
  } else {
    date1 = line[1].substring(5, 11);
  }
  //rozparsovani igc a vybrani B zaznam a preveden na JSON 
  for (var i = 0; i < line.length; i++) {

    //zpracovani zasoveho posunu automaticky nastaven na UTC

    if (line[i][0] === "H" & line[i][2] === "T") {
      let timeStampPosition = line[i].indexOf("E:");
      timeStamp = line[i].substring(timeStampPosition + 2, timeStampPosition + 5);
      timeStamp = timeStamp * 3600;
    }

    if (line[i][0] === "H" & line[i].indexOf("COMPETITIONID") == 5) {
      compationId = line[i].substring(19);
    } else if (line[i][0] === "H" & line[i].indexOf("GLIDERID") == 5) {
      gliderId = line[i].substring(14);
    } else if (line[i][0] === "H" & line[i].indexOf("GLIDERTYPE") == 5) {
      gliderType = line[i].substring(16);
    } else if (line[i][0] === "H" & line[i].indexOf("PILOT") == 5) {
      pilot = line[i].substring(line[i].indexOf(":") + 1);
    } else if (line[i][0] === "H" & line[i].indexOf("FFTYFRTYPE") == 1) {
      recorderType = line[i].substring(line[i].indexOf(",") + 1);
    }


    //zpracovani I
    if (line[i][0] === "I") {
      TRTPosition = line[i].indexOf("TRT");
      TRTindexStart = line[i].substring(TRTPosition - 4, TRTPosition - 2);
      TRTindexEnd = line[i].substring(TRTPosition - 2, TRTPosition);


      TASPosition = line[i].indexOf("TAS");
      TASIndexStart = line[i].substring(TASPosition - 4, TASPosition - 2);
      TASIndexEnd = line[i].substring(TASPosition - 2, TASPosition);

      GSPposition = line[i].indexOf("GSP");
      GSPindexStart = line[i].substring(GSPposition - 4, GSPposition - 2);
      GSPindexEnd = line[i].substring(GSPposition - 2, GSPposition);
      var GSPRange = GSPindexEnd - GSPindexStart;
      if (GSPRange == 2) {
        GSPRange = 1
      } else {
        GSPRange = 100
      }


      OATPosition = line[i].indexOf("OAT");
      OATIndexStart = line[i].substring(OATPosition - 4, OATPosition - 2);
      OATIndexEnd = line[i].substring(OATPosition - 2, OATPosition);

      ENLPosition = line[i].indexOf("ENL");
      ENLIndexStart = line[i].substring(ENLPosition - 4, ENLPosition - 2);
      ENLIndexEnd = line[i].substring(ENLPosition - 2, ENLPosition);

    }

    //definice deklarace
    if (line[i][0] === "C") {
      if (pointCounter > -1) {
        let pointLatitude = ", \"latitude\":";
        let sign = 1;
        pointPosition = line[i].indexOf("N"); //severni polokoule
        if (pointPosition === -1) {
          pointPosition = line[i].indexOf("S"); //jizni polokoule
          sign = -1;
        }
        let latitudeDegrres = line[i].substring(pointPosition - 7, pointPosition - 5);
        if (line[i].substring(pointPosition - 7, pointPosition - 5) === "0") {
          latitudeDegrres = line[i].substring(pointPosition - 6, pointPosition - 4);
        } else {
          latitudeDegrres = line[i].substring(pointPosition - 7, pointPosition - 5);
        }
        let zero = "0.";
        let latitudeDegrresDot;
        if (parseInt(line[i].substring(pointPosition - 7, pointPosition - 5)) > 0) {
          latitudeDegrresDot = zero.concat(line[i].substring(pointPosition - 5, pointPosition)) / 0.6;
          latitudeDegrresDot = latitudeDegrresDot.toString();
          latitudeDegrresDot = latitudeDegrresDot.substring(1, 7);
          latitudeDegrres = latitudeDegrres.concat(latitudeDegrresDot) * sign;
          pointLatitude = pointLatitude.concat(latitudeDegrres, latitudeDegrresDot.substring(1, 7), ", \"number\": -2, \"radius\": 0}");

        } else {
          latitudeDegrresDot = 0;
          pointLatitude = pointLatitude.concat(parseInt(latitudeDegrres), ", \"number\": -2 }");

        }
        let pointLongitude = "{\"longitude\":";
        sign = 1;
        pointPosition2 = line[i].indexOf("E"); //zapadni
        if (pointPosition2 === -1) {
          pointPosition2 = line[i].indexOf("W"); //vychodni
          sign = -1;
        }

        let longitudeDegrres = line[i].substring(pointPosition2 - 8, pointPosition2 - 5);


        if (line[i].substring(pointPosition2 - 8, pointPosition2 - 7) === "0") {
          if (line[i].substring(pointPosition2 - 7, pointPosition2 - 6) === "0") {
            longitudeDegrres = line[i].substring(pointPosition2 - 6, pointPosition2 - 5);
          } else {
            longitudeDegrres = line[i].substring(pointPosition2 - 7, pointPosition2 - 5);
          }
        } else {
          longitudeDegrres = line[i].substring(pointPosition2 - 8, pointPosition2 - 5);
        }

        //let longitudeDegrres = line[i].substring(pointPosition2 - 7, pointPosition2 - 5);
        let longitudeDegrresDot;
        if (parseInt(line[i].substring(pointPosition - 7, pointPosition - 5)) > 0) {
          longitudeDegrresDot = zero.concat(line[i].substring(pointPosition2 - 5, pointPosition2)) / 0.6;
          longitudeDegrresDot = longitudeDegrresDot.toString();
          longitudeDegrresDot = longitudeDegrresDot.substring(1, 7);
          longitudeDegrres = longitudeDegrres.concat(longitudeDegrresDot) * sign;

          pointLongitude = pointLongitude.concat(longitudeDegrres, longitudeDegrresDot.substring(2, 7));
        } else {
          pointLongitude = "{\"longitude\": 0";
        }
        pointLongitude = pointLongitude.concat(pointLatitude);
        turnpoints.push(pointLongitude);
      }
      pointCounter++;
    }

    //definice polomeru otocnych bodu
    if (line[i][0] === "L" & line[i][6] === "=") {
      let radiusTurnPointStart = line[i].indexOf("R1=");
      let radiusTurnPointEnd = line[i].indexOf("A1=");
      let radiusTurnPoint = line[i].substring(radiusTurnPointStart + 3, radiusTurnPointEnd - 2);
      radiusArray.push(radiusTurnPoint);
    }
    if (line[i][0] === "E") {
      pevTime = line[i].substring(1, 7);
    }


    //zpracovani B zaznamu 
    if (line[i][0] === "B") {
      countB++;
      let number = ",\"number\":";
      number = number.concat(countB);

      //vybrani a zpracovani zemepisne delky
      let longitude = "{\"longitude\":";
      let longitudeDegrres = line[i].substring(16, 18);

      if (line[i].substring(15, 16) === "0") {
        if (line[i].substring(16, 17) === "0") {
          longitudeDegrres = line[i].substring(17, 18);
        } else {
          longitudeDegrres = line[i].substring(16, 18);
        }
      } else {
        longitudeDegrres = line[i].substring(15, 18);
      }
      let zero = "0.";
      let longitudeDegrresDot = zero.concat(line[i].substring(18, 23)) / 0.6;
      longitudeDegrresDot = longitudeDegrresDot.toString();
      longitudeDegrresDot = longitudeDegrresDot.substring(1, 7);
      longitudeDegrres = longitudeDegrres.concat(longitudeDegrresDot);
      if (line[i].substring(23, 24) === "W") {
        longitudeDegrres = longitudeDegrres * -1;
      }

      //vybrani a zpracovani zemepisne sirky
      let latitude = ",\"latitude\":";
      let latitudeDegrres = line[i].substring(7, 9);
      if (line[i].substring(7, 8) === "0") {
        latitudeDegrres = line[i].substring(8, 9);
      } else {
        latitudeDegrres = line[i].substring(7, 9);
      }
      let latitudeDegrresDot = zero.concat(line[i].substring(9, 14)) / 0.6;
      latitudeDegrresDot = latitudeDegrresDot.toString();
      latitudeDegrresDot = latitudeDegrresDot.substring(1, 7);
      latitudeDegrres = latitudeDegrres.concat(latitudeDegrresDot);
      if (line[i].substring(14, 15) === "S") {
        latitudeDegrres = latitudeDegrres * -1;
      }
      latitudeDegrres = latitude.concat(latitudeDegrres);

      //nastaveni vysky
      let altitude = ",\"altitude\":";
      let altitudeMeter = "";
      if (line[i][31] === "0") {
        if (line[i][32] === "0") {
          if (line[i][33] === "0") {
            altitudeMeter = line[i].substring(34, 35);
          } else {
            altitudeMeter = line[i].substring(33, 35);
          }
        } else {
          altitudeMeter = line[i].substring(32, 35);
        }
      } else {
        altitudeMeter = line[i].substring(31, 35);
      }
      altitude = altitude.concat(altitudeMeter);

      let timeParsed = line[i].substring(1, 7);
      let century = ",\"time\": \"20"; //v zaznamu dat neni stoleti
      //nastaveni formatu casu letu
      let timeRecord = century.concat(date1.substring(4, 6), "-", date1.substring(2, 4), "-", date1.substring(0, 2), "T", (timeParsed.substring(0, 2)), ":", timeParsed.substring(2, 4), ":", timeParsed.substring(4, 6), "\"");


      let eventJSON = ",\"event\": \"nill\""; 
      let direct = ",\"direct\": 1.0";

      let direction = ",\"direction\": -1";
      if (TRTPosition !== -1) {
        direction = ",\"direction\": ";
        TRTinMeter = line[i].substring(TRTindexStart - 1, TRTindexEnd) / 1;
        TRTinMeter = TRTinMeter.toString();
        direction = direction.concat(TRTinMeter);
      }

      let speedTAS = ",\"TAS\": 100.0";
      if (TASPosition !== "-1") {
        speedTAS = ",\"TAS\": ";
        TASInKm = line[i].substring(TASIndexStart - 1, TASIndexEnd) / 100;
        TASInKm = TASInKm.toString();
        speedTAS = speedTAS.concat(TASInKm);
      }

      let speedGSP = ",\"GSP\": 100.0";
      if (GSPposition !== "-1") {
        speedGSP = ",\"GSP\": ";
        GSPKm = line[i].substring(GSPindexStart - 1, GSPindexEnd) / GSPRange;
        GSPKm = GSPKm.toString();
        speedGSP = speedGSP.concat(GSPKm);
      }

      let temperaturOAT = ",\"OAT\": 100.0";
      if (OATPosition !== "-1") {
        temperaturOAT = ",\"OAT\": ";
        OATCelsium = line[i].substring(OATIndexStart - 1, OATIndexEnd) / 10;
        OATCelsium = OATCelsium.toString();
        temperaturOAT = temperaturOAT.concat(OATCelsium);
      }

      let ENLNoise = ",\"ENL\": 100.0";
      if (ENLPosition !== "-1") {
        ENLNoise = ",\"ENL\": ";
        ENLdB = line[i].substring(ENLIndexStart - 1, ENLIndexEnd) / 1;
        ENLdB = ENLdB.toString();
        ENLNoise = ENLNoise.concat(ENLdB);
      }
      let countSIU = ",\"trackTrueChange\": 0";

      let timePEV = ",\"PEV\": ";
      timePEV = timePEV.concat(parseInt(pevTime));

      let altitudeChange = ",\"altitudeChange\": 0";
      let eventCount = ",\"eventCount\": 0";
      let overallEvent = ",\"overallEvent\": 0";
      let eventColorJson = ",\"color\": 0";
      let directionChange = ",\"directionChange\": 0";
      let TASChange = ",\"TASChange\": 0";
      let GSPChange = ",\"GSPChange\": 0";
      let eventID = ",\"eventID\": 1";
      text2.push(longitude.concat(longitudeDegrres, latitudeDegrres, altitude,
        timeRecord, direction, speedTAS, speedGSP, eventJSON, timePEV, direct, ENLNoise, temperaturOAT,
        number, altitudeChange, countSIU, eventCount, overallEvent, eventColorJson, directionChange, "}"));

      textMarkov.push(longitude.concat(longitudeDegrres, latitudeDegrres, timeRecord, number, altitude,
        altitudeChange, direction, directionChange, speedTAS, TASChange, speedGSP, GSPChange, eventID, "}"));

    }
    //konec zpracovani B zaznamu
  }

  let brackets = "[";
  let brackets2 = "]";
  turnpoints = brackets.concat(turnpoints, brackets2);
  text2 = brackets.concat(text2, brackets2);
  textMarkov = brackets.concat(textMarkov, brackets2);
  const flightData = JSON.parse(text2);
  const markov = JSON.parse(textMarkov);
  const flightTurnpoints = JSON.parse(turnpoints);
  //dopocitani nadmorske vysky zacatku
  var altitudeGround = [];
  altitudeGround.push(Cesium.Cartographic.fromDegrees(flightData[10].longitude, flightData[10].latitude));
  var promise1 = Cesium.sampleTerrainMostDetailed(viewer.terrainProvider, altitudeGround);
  Promise.resolve(promise1, altitudeGround)
  loadHeight(altitudeGround, flightData, gliderId, compationId, gliderType, pilot, recorderType, date1, markov, flightTurnpoints, radiusArray);
}

/**
* nastaveni vysky
* 
* @param {number} altitudeGround vyska v miste startu
* @param {JSON} flightData letova data v JSON formatu
* @param {string} informace nasleduji informace o letu a letadle
* @param {JSON} markov letova data ve formatu JSON pro dalsi zpracovani
* @param {JSON} flightTurnpoints otocne body ve formatu JSON
* @param {aray} radiusArray pole s informacemi o otocnych bodech
*/

//nastaveni vysky kluzaku podle vysky terenu mista vzletu
function loadHeight(altitudeGround, flightData, gliderId, compationId, gliderType, pilot, recorderType, date1, markov, flightTurnpoints, radiusArray) {
  if (altitudeGround[0].height > 10) {
    setTimeout(() => { stepTwo(flightData, gliderId, compationId, gliderType, pilot, recorderType, date1, altitudeGround, markov, flightTurnpoints, radiusArray); }, 400);
  } else {
    setTimeout(() => { loadHeight(altitudeGround, flightData, gliderId, compationId, gliderType, pilot, recorderType, date1, markov, flightTurnpoints, radiusArray); }, 20);
  }
}

/**
* nastaveni vysky
* 
* @param {JSON} flightData letova data v JSON formatu
* @param {string} informace nasleduji informace o letu a letadle
* @param {number} altitudeGround vyska v miste startu
* @param {JSON} markov letova data ve formatu JSON pro dalsi zpracovani
* @param {JSON} flightTurnpoints otocne body ve formatu JSON
* @param {aray} radiusArray pole s informacemi o otocnych bodech
*/

function stepTwo(flightData, gliderId, compationId, gliderType, pilot, recorderType, date1, altitudeGround, markov, flightTurnpoints, radiusArray) {
  //nastaveni casovace
  var timeNotUTC = Cesium.JulianDate.fromIso8601(flightData[0].time);
  var timeUTC = Cesium.JulianDate.addSeconds(timeNotUTC, 7200, new Cesium.JulianDate());
  const start = timeUTC;
  var timeNotUTC2 = Cesium.JulianDate.fromIso8601(flightData[flightData.length - 1].time);
  var timeUTC2 = Cesium.JulianDate.addSeconds(timeNotUTC2, 7200, new Cesium.JulianDate());
  const stop = timeUTC2
  viewer.clock.startTime = start.clone();
  viewer.clock.stopTime = stop.clone();
  viewer.clock.currentTime = start.clone();

  viewer.timeline.zoomTo(start, stop);
  viewer.clock.shouldAnimate = true;

  const positionProperty = new Cesium.SampledPositionProperty();
  let temp = 0;
  let trackTrueChange = 0;
  let temp2 = 0;
  let position = 0;
  var graphDataAltitude = [];
  var altitudeGround2 = [];
  var graphTime;
  var colortyp;
  let altitude1, altitude2 = 0;

  let altitudeError = altitudeGround[0].height - flightData[10].altitude;
  flightData[0].altitude = flightData[2].altitude + altitudeError;
  flightData[1].altitude = flightData[2].altitude + altitudeError;
  for (let i = 0; i < (flightData.length - 2); i++) {
    altitude2 = altitude1;
    altitude1 = flightData[i].altitude;
    if (i > 1 & i < (flightData.length - 2)) {
      flightData[i].altitude = flightData[i].altitude + altitudeError;
      if (i > 2 & i < (flightData.length - 2)) {
        flightData[i].altitude = (0.05 * altitude2 + 0.2 * altitude1 + 0.5 * flightData[i].altitude + 0.2 * flightData[i + 1].altitude + 0.05 * flightData[i + 2].altitude);
        flightData[i].altitudeChange = (flightData[i].altitude - flightData[i - 1].altitude);
      }
    }

    if (flightData[i].direction === -1 && i < flightData.length - 1) {
      flightData[i].direction = bearing(flightData[i].latitude, flightData[i + 1].latitude, flightData[i].longitude, flightData[i + 1].longitude);
    }

    if (i > 0) {
      trackTrueChange = (flightData[i].direction - flightData[i - 1].direction);
      if (trackTrueChange > 300) {
        temp2 = 1;
        trackTrueChange = trackTrueChange - 360
      }
      if (trackTrueChange < -300) {
        temp2 = 2;
        trackTrueChange = 360 + trackTrueChange
      }
      flightData[i].trackTrueChange = trackTrueChange;
      if (temp2 === 1) {
        trackTrueChange = trackTrueChange + 360;
        temp2 = 0;
      }
      if (temp2 === 2) {
        trackTrueChange = trackTrueChange - 360;
        temp2 = 0;
      }

    }

  }
  let horizontalEventCount = 0;
  var eventColor2 = 1;
  var filtLongitude, filtLatitude, filtAltitude = 0;
  var filtLongitudeOld, filtLatitudeOld, filtAltitudeOld = 0;

  for (let i = 0; i < flightData.length; i++) {
    const dataPoint = flightData[i];

    //naplneni pole pro dopocitani vysky nad terenem
    altitudeGround2.push(Cesium.Cartographic.fromDegrees(flightData[i].longitude, flightData[i].latitude));

    let eventColor = Cesium.Color.WHITE;
    //specifikace barev 
    if (flightData[i].altitudeChange > 0.5) { //stoupe a neni v rozmezi pro horizontalni let
      eventColor2 = 1; //zelena
    } else if (flightData[i].altitudeChange < -0.5) { //klesa a neni v rozmezi pro horizontalni let
      eventColor2 = 2; //cervena
    } else {
      for (let j = 0; j < 5; j++) {
        if (i + j + 3 < flightData.length & i > 2) {
          if (flightData[i + j].altitudeChange >= -0.5 & flightData[i + j].altitudeChange <= 0.5) {
            horizontalEventCount = horizontalEventCount + 1;
          }
        }
      }
      if (horizontalEventCount >= 5 - flightData[i].eventCount & i < (flightData.length - 1)) { //horizontalni let o delce minimalne 5 sekund(zaznamu) 
        eventColor2 = 3;
        flightData[i + 1].eventCount = flightData[i].eventCount + 1;
        horizontalEventCount = 0;
      } else { //stoupe nebo klesa v rozmezi pro horizontalni let, ale kratkou dobu
        if (flightData[i].altitudeChange >= 0) {
          eventColor2 = 1;
        } else {
          eventColor2 = 2;
        }
        horizontalEventCount = 0;
      }
    }
    if (i > 0) {
      flightData[i - 1].eventColorJson = eventColor2;
    } else {
      flightData[i].eventColorJson = eventColor2;
    }


    //identifikace manevru zatacka a rovny letu
    if (i > 2 & i < (flightData.length + 2)) {
      if (flightData[i].trackTrueChange > -2 && flightData[i].trackTrueChange < 2) {
        flightData[i].event = "rovny let";
        eventColor = Cesium.Color.TRANSPARENT;
      } else if (flightData[i].trackTrueChange <= -2) {
        if (flightData[i + 1].trackTrueChange <= -2 & flightData[i - 1].trackTrueChange <= -2) {
          flightData[i].event = "leva zatacka";
          eventColor = Cesium.Color.WHITE;
        } else if (flightData[i + 1].trackTrueChange <= -2 & flightData[i + 2].trackTrueChange <= -2) {
          flightData[i].event = "leva zatacka";
          eventColor = Cesium.Color.WHITE;
        } else if (flightData[i - 2].trackTrueChange <= -2 & flightData[i - 1].trackTrueChange <= -2) {
          flightData[i].event = "leva zatacka";
          eventColor = Cesium.Color.WHITE;
        } else {
          flightData[i].event = "rovny let";
          eventColor = Cesium.Color.TRANSPARENT;
        }
      } else {
        if (flightData[i + 1].trackTrueChange >= 2 & flightData[i - 1].trackTrueChange >= 2) {
          flightData[i].event = "prava zatacka";
          eventColor = Cesium.Color.BLACK;
        } else if (flightData[i + 1].trackTrueChange >= 2 & flightData[i + 2].trackTrueChange >= 2) {
          flightData[i].event = "prava zatacka";
          eventColor = Cesium.Color.BLACK;
        } else if (flightData[i - 2].trackTrueChange >= 2 & flightData[i - 1].trackTrueChange >= 2) {
          flightData[i].event = "prava zatacka";
          eventColor = Cesium.Color.BLACK;
        } else {
          flightData[i].event = "rovny let";
          eventColor = Cesium.Color.TRANSPARENT;
        }
      }
    }
    //konec identifikace zatacek a rovneho letu

    //identifikace manevru pristani
    if (flightData[i].altitude < (flightData[flightData.length - 3].altitude + 15.2) & temp == 1 & i > (flightData.length / 4)) {
      if (flightData[i].TAS < 90) {
        flightData[i].event = "dojezd";
        flightData[i].overallEvent = "dojezd";
        markov[i].eventID = "12";
        eventColor2 = 6;
        eventColor = Cesium.Color.TRANSPARENT;
      } else {
        flightData[i].event = "pristani - vzdusna cast pristani";
        flightData[i].overallEvent = "přistání - vzdušná část přistání";
        markov[i].eventID = "13";
        eventColor2 = 7;
        eventColor = Cesium.Color.TRANSPARENT;
      }
    }

    //identifikace manevru start 
    if (flightData[i].altitude <= (flightData[1].altitude + 10.7) & temp == 0) {
      if (flightData[i].TAS < 90) {
        if (i == 0) {
          flightData[i].event = "na startu";
          flightData[i].overallEvent = "na startu"
        } else {
          flightData[i].event = "rozjezd";
          flightData[i].overallEvent = "rozjezd"
          markov[i].eventID = "1";
          eventColor2 = 4;
          eventColor = Cesium.Color.TRANSPARENT;

        }
      } else {
        flightData[i].event = "vzlet vzdusna cast";
        flightData[i].overallEvent = "vzlet vzdusna cast";
        markov[i].eventID = "2";
        eventColor2 = 5;
        eventColor = Cesium.Color.TRANSPARENT;
        flightData[i].direct = flightData[i - 1].direct + 1.0;
      }
    } else {
      temp = 1; //start muze nastat jen jednou
    }

    //identifikace smerovych manevru 
    if (flightData[i].event === "leva zatacka") {

      if (eventColor2 == 1) {
        flightData[i].overallEvent = "levá stoupavá zatáčka";
        markov[i].eventID = "9";
      } else if (eventColor2 == 2) {
        flightData[i].overallEvent = "levá klesavá zatáčka"
        markov[i].eventID = "3";
      } else {
        flightData[i].overallEvent = "levá horizontální zatáčka"
        markov[i].eventID = "6";
      }
    } else if (flightData[i].event === "prava zatacka") {
      if (eventColor2 == 1) {
        flightData[i].overallEvent = "pravá stoupavá zatáčka"
        markov[i].eventID = "11";
      } else if (eventColor2 == 2) {
        flightData[i].overallEvent = "pravá klesavá zatáčka"
        markov[i].eventID = "5";
      } else {
        flightData[i].overallEvent = "pravá horizontální zatáčka"
        markov[i].eventID = "8";
      }
    } else if (flightData[i].event === "rovny let") {
      if (eventColor2 == 1) {
        flightData[i].overallEvent = "přímočarý stoupavý let"
        markov[i].eventID = "10";
      } else if (eventColor2 == 2) {
        flightData[i].overallEvent = "přímočarý klesavý let"
        markov[i].eventID = "4";
      } else {
        flightData[i].overallEvent = "přímočarý horizontální let"
        markov[i].eventID = "7";
      }
    }


    //pridani filtru pro souradnice

    filtLongitudeOld = filtLongitude;
    filtLatitudeOld = filtLatitude;
    filtAltitudeOld = filtAltitude;

    if (i > 5 & i < (flightData.length - 5)) {
      filtAltitude = flightData[i].altitude;
      if (flightData[i + 2].event !== "prava zatacka" & flightData[i + 1].event !== "prava zatacka" & flightData[i].event !== "prava zatacka") {
        filtLongitude = 0.1 * flightData[i - 2].longitude + 0.2 * flightData[i - 1].longitude + 0.4 * flightData[i].longitude + 0.2 * flightData[i + 1].longitude + 0.1 * flightData[i + 2].longitude;
        filtLatitude = 0.1 * flightData[i - 2].latitude + 0.2 * flightData[i - 1].latitude + 0.4 * flightData[i].latitude + 0.2 * flightData[i + 1].latitude + 0.1 * flightData[i + 2].latitude;
        position = Cesium.Cartesian3.fromDegrees(filtLongitude, filtLatitude, filtAltitude);
      } else if (flightData[i + 2].event !== "leva zatacka" & flightData[i + 1].event !== "leva zatacka" & flightData[i].event !== "leva zatacka") {
        filtLongitude = 0.1 * flightData[i - 2].longitude + 0.2 * flightData[i - 1].longitude + 0.4 * flightData[i].longitude + 0.2 * flightData[i + 1].longitude + 0.1 * flightData[i + 2].longitude;
        filtLatitude = 0.1 * flightData[i - 2].latitude + 0.2 * flightData[i - 1].latitude + 0.4 * flightData[i].latitude + 0.2 * flightData[i + 1].latitude + 0.1 * flightData[i + 2].latitude;
        position = Cesium.Cartesian3.fromDegrees(filtLongitude, filtLatitude, filtAltitude);
      } else {
        filtLongitude = flightData[i].longitude;
        filtLatitude = flightData[i].latitude;
        position = Cesium.Cartesian3.fromDegrees(filtLongitude, filtLatitude, filtAltitude);
      }
    } else {
      filtLongitude = flightData[i].longitude;
      filtLatitude = flightData[i].latitude;
      position = Cesium.Cartesian3.fromDegrees(filtLongitude, filtLatitude, filtAltitude);
      if (i <= 5) {
        filtAltitude = flightData[i].altitude;
      }
    }

    //pridani obarvene propojeni zaznamu letu
    if (i > 1 & i < flightData.length) {
      viewer.entities.add({
        name: "Spojnice otočných bodů",
        polyline: {
          positions: Cesium.Cartesian3.fromDegreesArrayHeights([filtLongitudeOld, filtLatitudeOld, filtAltitudeOld, filtLongitude, filtLatitude, filtAltitude]),
          width: 6,
          material: new Cesium.PolylineOutlineMaterialProperty({
            color: (eventColor2 === 1) ? Cesium.Color.GREEN :
              (eventColor2 === 2) ? Cesium.Color.RED :
                (eventColor2 === 4) ? Cesium.Color.BROWN :
                  (eventColor2 === 5) ? Cesium.Color.OLIVE :
                    (eventColor2 === 6) ? Cesium.Color.VIOLET :
                      (eventColor2 === 7) ? Cesium.Color.DARKORANGE :
                        Cesium.Color.BLUE,
            outlineWidth: 3,
            outlineColor: eventColor
          })
        },
      });
    }

    //nastaveni hodnot pro vyhodnoceni
    markov[i].altitudeChange = flightData[i].altitudeChange.toFixed(2);
    markov[i].directionChange = flightData[i].trackTrueChange.toFixed(0);
    if (i > 0) {
      markov[i].TASChange = (flightData[i].TAS - flightData[i - 1].TAS).toFixed(2);
      markov[i].GSPChange = (flightData[i].GSP - flightData[i - 1].GSP).toFixed(2);
    }

    //doplneni hodnot pro graf s letem
    const time = Cesium.JulianDate.addSeconds(start, i, new Cesium.JulianDate());
    let recordTime = 0;
    //prevod casu
    let tmp1 = flightData[i].time.substring(11, 12);
    let tmp2 = flightData[i].time.substring(12, 13);
    if (tmp1 == 0 & tmp2 >= 8) {
      let tmp3 = parseInt(tmp2) + 2;
      recordTime = flightData[i].time.substring(0, 11) + tmp3 + flightData[i].time.substring(13);
    } else if (tmp1 == 1 & tmp2 >= 8) {
      let tmp3 = parseInt(tmp2) + 2;
      recordTime = flightData[i].time.substring(0, 11) + tmp3 + flightData[i].time.substring(13);
    } else {
      tmp2 = parseInt(tmp2) + 2;
      recordTime = flightData[i].time.substring(0, 11) + tmp1 + tmp2 + flightData[i].time.substring(13);
    }
    graphTime = flightData[i].time;
    if (eventColor2 === 2) {
      colortyp = "red";
    } else if (eventColor2 === 1) {
      colortyp = "green";
    } else {
      colortyp = "blue";
    }
    graphDataAltitude.push({
      x: new Date(graphTime.substring(0, 4), graphTime.substring(5, 7), graphTime.substring(8, 10), graphTime.substring(11, 13), graphTime.substring(14, 16), graphTime.substring(17, 19)),
      y: flightData[i].altitude,
      lineColor: colortyp,
      markerBorderColor: colortyp
    });

    positionProperty.addSample(recordTime, position); //pridani ramci cas a pozici


    //zobrazeni okenka s informaci
    viewer.entities.add({
      name: `Informace o konkrétním záznamu`,
      description: ` 
      Rejstříková značka: ${gliderId} 
      \<p>  Zeměpisná šířka ${dataPoint.latitude.toFixed(3)}°  
      \<p>  Zeměpisná délka ${dataPoint.longitude.toFixed(3)}°
      \<p>  Výška nad mořem ${dataPoint.altitude.toFixed(1)} m n. m. 
      \<p>  Rychlost vůči Zemi ${dataPoint.GSP} km/h.
      \<p>  Venkovni teplota ${dataPoint.OAT} °C
      \<p>  Hlučnost ${dataPoint.OAT} dB
      \<p>  Identifikovaný manévr: ${dataPoint.overallEvent}`,
      position: position,
      point: {
        pixelSize: ((dataPoint.event == "rovny let") ? 7 : 12),
        color: (eventColor2 === 1) ? Cesium.Color.GREEN :
          (eventColor2 === 2) ? Cesium.Color.RED :
            (eventColor2 === 4) ? Cesium.Color.BROWN :
              (eventColor2 === 5) ? Cesium.Color.OLIVE :
                (eventColor2 === 6) ? Cesium.Color.VIOLET :
                  (eventColor2 === 7) ? Cesium.Color.DARKORANGE :
                    Cesium.Color.BLUE,
        outlineColor: eventColor, outlineWidth: 2
      }
    });



    if (temp2 === 1) {
      trackTrueChange = trackTrueChange + 360;
      temp2 = 0;
    }
    if (temp2 === 2) {
      trackTrueChange = trackTrueChange - 360;
      temp2 = 0;
    }
  }




  //vykresleni trate a otocnych bodu, vykresleni se provede jen u prvniho nacteneho letu
  if (flightCount == 1) {
    for (let i = 1; i < (flightTurnpoints.length - 1); i++) {
      viewer.entities.add({
        name: "Otocny bod",
        position: Cesium.Cartesian3.fromDegrees(flightTurnpoints[i].longitude, flightTurnpoints[i].latitude),
        ellipse: {
          semiMinorAxis: radiusArray[i],
          semiMajorAxis: radiusArray[i],
          material: Cesium.Color.BLUE.withAlpha(0.5),
        },
      });
      viewer.entities.add({
        name: "Spojnice otočných bodů",
        polyline: {
          positions: Cesium.Cartesian3.fromDegreesArray([flightTurnpoints[i - 1].longitude, flightTurnpoints[i - 1].latitude, flightTurnpoints[i].longitude, flightTurnpoints[i].latitude]),
          material: {
            solidColor: {
              color: {
                rgba: [255, 255, 255, 255],
              },
            },
          },
          width: 5,
          clampToGround: true,
        },
      });

    }
  }


  // Zjisteni vysky nad terenem
  var promise = Cesium.sampleTerrainMostDetailed(viewer.terrainProvider, altitudeGround2);
  Promise.resolve(promise, altitudeGround2)

  //nacteni modelu letadla
  loadModel(gliderId, compationId, gliderType, pilot, gliderModel);


  //vykresleni grafu
  grafRender(graphDataAltitude);
  //aktivace tlacitek pro export souboru
  exportButton(flightData, gliderType, gliderId, compationId, pilot, recorderType, date1, markov);
  const dataDisplay = document.createElement("div");
  const dataDisplay2 = document.createElement("div");
  viewer.clock.onTick.addEventListener(function (clock) {

    var x;
    x = Cesium.JulianDate.addSeconds(clock.currentTime, 0, new Cesium.JulianDate());
    x = x.toString();
    let x2 = x.substring(0, 19);

    for (var q = 1; q < (flightData.length - 3); q++) {
      let x3 = (flightData[q].time).toString();
      if (x2.localeCompare(x3) === 0) {
        let agl = (flightData[q].altitude - altitudeGround2[q].height);
        if (agl < 0) {
          agl = 0;
        }
        dataDisplay.setAttribute('style', 'white-space: pre-line;');
        dataDisplay.textContent = "Rejstříková značka: " + gliderId + "\r\n";
        if (flightData[q].TAS !== 0) {
          dataDisplay.textContent += "Rychlost vůči vzduchu: " + flightData[q].TAS.toFixed(0) + " km/h \r\n";
        }
        if (flightData[q].GSP !== 0) {
          dataDisplay.textContent += "Rychlost vůči zemi: " + flightData[q].GSP.toFixed(0) + " km/h \r\n";
        }
        dataDisplay.textContent += "Nadmořská výška: " + (flightData[q].altitude.toFixed(0) - 42) + " m n. m.  \r\n";
        dataDisplay.textContent += "Výška nad zemí: " + agl.toFixed(0) + "m \r\n";
        dataDisplay.textContent += "Variometr: " + flightData[q + 1].altitudeChange.toFixed(1) + " m/s  \r\n"; //dopocitany
        dataDisplay.textContent += "Kurz: " + flightData[q].direction.toFixed(0) + "°  \r\n";
        //nastaveni aktualniho manevru
        dataDisplay2.setAttribute('style', 'white-space: pre-line;');
        dataDisplay2.textContent = gliderId + ": " + flightData[q + 1].overallEvent + "  \r\n"; //
      }
    }
    q = 0;
  });

  document.getElementById("info2").appendChild(dataDisplay);
  document.getElementById("info3").appendChild(dataDisplay2);

  /**
 * nacteni a zobrazeni modelu letadla a vykresleni trate
 * 
 * @param {string} gliderId registracni znacka letadla
 * @param {string} compationId startovni znak letadla
 * @param {string} gliderType typ letadla
 * @param {string} pilot jmeno pilota
 */

  async function loadModel(gliderId, compationId, gliderType, pilot, gliderModel) {

    //nacteni modelu letadla podle id z Cesium ion
    const planeModel = await Cesium.IonResource.fromAssetId(gliderModel);
    //pridani letadla
    const gliderState = viewer.entities.add({
      availability: new Cesium.TimeIntervalCollection([new Cesium.TimeInterval({ start: start, stop: stop })]),
      name: "Pohled na aktuální polohu letadla",
      description: `Typ letadla: ${gliderType} \<p> Startovní znak letadla: ${compationId} \<p> Rejstříková značka letadla: ${gliderId} `,
      position: positionProperty,
      model: {
        uri: planeModel,
        minimumPixelSize: 120,
      },
      orientation: new Cesium.VelocityOrientationProperty(positionProperty),
      //pridani imatrikulace nad letadlo, ktera je zobrazena jen pri urcitem priblizeni
      label: {
        text: `${gliderId}`,
        font: "18px sans-serif",
        showBackground: true,
        distanceDisplayCondition: new Cesium.DistanceDisplayCondition(
          50.0,
          300.0
        ),
        eyeOffset: new Cesium.Cartesian3(0, 4, 0),
      },

    });
    viewer.trackedEntity = gliderState; //nastaveni kamery na letadlo
  }


}

/**
 * Aktivace tlacitek pro vyexportovani souboru se statistikou a zaznamem ve formatu JSON pro dalsi zpracovani
 * 
 * @param {JSON} flightData zpracovane data
 * @param {string} gliderType typ letadla
 * @param {string} gliderId rejstrikova znacka
 * @param {string} compationId startovni znak
 * @param {string} pilot jmeno pilota
 * @param {string} recorderType nazev zaznamoveho zarizeni
 * @param {string} date1 datum letu
 * @param {string} markov vystupni JSON pro dalsi analyzu
 * 
 */
function exportButton(flightData, gliderType, gliderId, compationId, pilot, recorderType, date1, markov) {
  document.getElementById('JSONCall').addEventListener('click', function () {
    printJSON(markov);
  })

  document.getElementById('statisticCall').addEventListener('click', function () {
    statistic(flightData, gliderType, gliderId, compationId, pilot, recorderType, date1);
  })
}


//doplneni statistiky s celkovým časem manevru
/**
 * Export statistiky z letovych dat a ulozeni souboru do stazenych souboru
 * 
 * @param {JSON} flightData vstupni data ze zaznamu letu
 * @param {string} gliderType typ letadla
 * @param {string} gliderId rejstrikova znacka
 * @param {string} compationId startovni znak
 * @param {string} pilot jmeno pilota
 * @param {string} recorderType nazev zaznamoveho zarizeni
 * @param {string} date1 datum letu
 */
function statistic(flightData, gliderType, gliderId, compationId, pilot, recorderType, date1) { 
  var takeOffSec = 0;
  var directSec = 0;
  var rightTurnSec = 0;
  var leftTurnSec = 0;
  var landSec = 0;
  var leftUp = 0;
  var leftDown = 0;
  var leftHorizontal = 0;
  var rightUp = 0;
  var rightDown = 0;
  var rightHorizontal = 0;
  var straightUp = 0;
  var straightDown = 0;
  var straightHorizontal = 0;

  for (var i = 0; i < flightData.length; i++) {
    if (flightData[i].event === "rozjezd") {
      takeOffSec++
    } else if (flightData[i].event === "rovny let") {
      directSec++
    } else if (flightData[i].event === "prava zatacka") {
      rightTurnSec++
    } else if (flightData[i].event === "leva zatacka") {
      leftTurnSec++
    } else if (flightData[i].event === "vzlet vzdusna cast") {
      takeOffSec++
    } else if (flightData[i].event === "dojezd") {
      landSec++
    } else if (flightData[i].event === "pristani - vzdusna cast pristani") {
      landSec++
    }
    if (flightData[i].overallEvent === "levá stoupavá zatáčka") {
      leftUp++
    } else if (flightData[i].overallEvent === "levá klesavá zatáčka") {
      leftDown++
    } else if (flightData[i].overallEvent === "levá horizontální zatáčka") {
      leftHorizontal++
    } else if (flightData[i].overallEvent === "pravá stoupavá zatáčka") {
      rightUp++
    } else if (flightData[i].overallEvent === "pravá klesavá zatáčka") {
      rightDown++
    } else if (flightData[i].overallEvent === "pravá horizontální zatáčka") {
      rightHorizontal++
    } else if (flightData[i].overallEvent === "přímočarý stoupavý let") {
      straightUp++
    } else if (flightData[i].overallEvent === "přímočarý klesavý let") {
      straightDown++
    } else if (flightData[i].overallEvent === "přímočarý horizontální let") {
      straightHorizontal++
    }

  }



  const takeOffTime = new Date(takeOffSec * 1000).toISOString().slice(11, 19);
  const directTime = new Date(directSec * 1000).toISOString().slice(11, 19);
  const rightTurnTime = new Date(rightTurnSec * 1000).toISOString().slice(11, 19);
  const leftTurnTime = new Date(leftTurnSec * 1000).toISOString().slice(11, 19);
  const landTime = new Date(landSec * 1000).toISOString().slice(11, 19);

  const leftUpTime = new Date(leftUp * 1000).toISOString().slice(11, 19);
  const leftDownTime = new Date(leftDown * 1000).toISOString().slice(11, 19);
  const leftHorizontalTime = new Date(leftHorizontal * 1000).toISOString().slice(11, 19);
  const rightUpTime = new Date(rightUp * 1000).toISOString().slice(11, 19);
  const rightDownTime = new Date(rightDown * 1000).toISOString().slice(11, 19);
  const rightHorizontalTime = new Date(rightHorizontal * 1000).toISOString().slice(11, 19);
  const straightUpTime = new Date(straightUp * 1000).toISOString().slice(11, 19);
  const straightDownTime = new Date(straightDown * 1000).toISOString().slice(11, 19);
  const straightHorizontalTime = new Date(straightHorizontal * 1000).toISOString().slice(11, 19);


  let fileStatistic = "Výstupní soubor se statistikou letu\r\n" +
    "jméno pilota: " + pilot +
    "typ letadla: " + gliderType +
    "\r\nrejstříková značka: " + gliderId +
    "\r\nstartovní znak: " + compationId +
    "\r\nnázev záznamového zařízení: " + recorderType +
    "\r\ndatum zaznamenaného letu: " + date1.substring(0, 2) + "/" + date1.substring(2, 4) + "/" + date1.substring(4, 6) +
    "\r\n\r\nFormát času jednotlivých manévrů je uváděn ve tvaru [HH:MM:SS].\r\n\r\n" +

    "1) celková doba trvaní vzletu:                           " + takeOffTime +
    "\r\n2) celková doba trvání levé zatáčky:                     " + leftTurnTime +
    "\r\n3) celková doba trvaní pravé zatáčky:                    " + rightTurnTime +
    "\r\n4) celková doba trvání přímočarého letu:                 " + directTime +
    "\r\n5) celková doba trvaní přistání:                         " + landTime + "\r\n\r\n" +

    "\r\n6) celková doba trvaní levé klesavé zatáčky:             " + leftDownTime +
    "\r\n7) celková doba trvaní levé horizontální zatáčky:        " + leftHorizontalTime +
    "\r\n8) celková doba trvaní levé stoupavé zatáčky:            " + leftUpTime +

    "\r\n\r\n9) celková doba trvaní přímočarého klesavého letu:       " + straightDownTime +
    "\r\n10) celková doba trvaní přímočarého horizontálního letu: " + straightHorizontalTime +
    "\r\n11) celková doba trvaní přímočarého stoupavého letu:     " + straightUpTime +


    "\r\n\r\n12) celková doba trvaní pravé klesavé zatáčky:           " + rightDownTime +
    "\r\n13) celková doba trvaní pravé horizontální zatáčky:      " + rightHorizontalTime +
    "\r\n14) celková doba trvaní pravé stoupavé zatáčky:          " + rightUpTime;


  const file = document.createElement("a");
  file.href = URL.createObjectURL(new Blob([fileStatistic], {
    type: "text/plain"
  }));
  file.setAttribute("download", "statistika.txt");
  document.body.appendChild(file);
  file.click();
  document.body.removeChild(file);
}


/**
 * Export upravenych letovych dat ve formatu JSON pro dalsi zpracovani 
 * a ulozeni souboru do stazenych souboru
 * 
 * @param {JSON} markov vystupni data ze zaznamu letu
 */

function printJSON(markov) {
  const file = document.createElement("a");
  file.href = URL.createObjectURL(new Blob([JSON.stringify(markov, null, 2)], {
    type: "text/plain"
  }));
  file.setAttribute("download", "data.txt");
  document.body.appendChild(file);
  file.click();
  document.body.removeChild(file);
}

/**
 * Vypocitani kurzu mezi aktualnim a nasledujicim zaznamenanym bodem
 * 
 * @param {number} latitude1 zemepisna sirka prvniho bodu (ve stupnich)
 * @param {number} latitude2 zemepisna sirka druheho bodu (ve stupnich)
 * @param {number} longitude1 zemepisna delka prvniho bodu (ve stupnich)
 * @param {number} longitude2 zemepisna delka prvniho bodu (ve stupnich)
 * @returns {number} hodnotu kurzu mezi body (ve stupnich)
 */

function bearing(latitude1, latitude2, longitude1, longitude2) {
  var pi = Math.PI;
  //prevod stupnu na radiany
  longitude1 = longitude1 * pi / 180;
  longitude2 = longitude2 * pi / 180;
  latitude1 = latitude1 * pi / 180;
  latitude2 = latitude2 * pi / 180;
  const a = Math.cos(latitude2) * Math.sin(longitude2 - longitude1);
  const b = Math.sin(latitude2) * Math.cos(latitude1) - Math.cos(latitude2) * Math.sin(latitude1) * Math.cos(longitude2 - longitude1);
  return (Math.atan2(a, b) * 180 / Math.PI + 360) % 360;
}

/**
 * funkce pro vykresleni grafu
 * 
 * @param {Array} graphDataAltitude  vstupni pole s nadmorskou vyskou letu
 */
function grafRender(graphDataAltitude) {
  //zobrazeni grafu
  var stockChart = new CanvasJS.StockChart("chartContainer", {
    backgroundColor: "white",
    title: {
      text: "Zaznamenaná nadmořská výška letu"
    },
    charts: [{
      toolTip: {
        shared: true
      },
      axisX: {
        title: "Čas [HH:MM]",
      }, axisY: {
        sufix: "m"
      },
      legend: {
        verticalAling: "top"
      },
      axisY: {
        title: "QNH [m MSL]",
        tickLength: 10
      },
      data: [
        {
          showInLegend: true,
          name: "Nadmořská výška (QNH) [m MSL]",
          yValueFormatString: "#,###",
          suffix: "m",
          type: "line",
          xValueType: "dateTime",
          xValueFormatString: " HH:mm:ss",
          legendMarkerType: "square",
          dataPoints: graphDataAltitude
        }
      ]
    }
    ],
    rangeSelector: {
      height: 100,
      enabled: false
    },
  });
  stockChart.render();
}

