<?php

class Recording
{
  private const ident = "VGAR";

  private const header_unpack = "Z5ident/Cversion";

  private const segment_unpack = "Vtime/Saltitude/Sgroundspeed/elatitude/elongitude";

  private string $file_name;

  public function __construct(string $file)
  {
    $this->file_name = $file;
  }

  public function geoJSON()
  {
    $geoJSON = [
      "type" => "FeatureCollection",
      "features" => [
        0 => [
          "type" => "Feature",
          "properties" => [
            "stroke" => "#ff0000",
            "stroke-width" => 2,
            "stroke-opacity" => 1
          ],
          "geometry" => [
            "type" => "LineString",
            "coordinates" => []
          ]
        ]
      ]
    ];
    $segments = $this->read();
    $geoJSON["features"][0]["geometry"]["coordinates"] = array_map(function ($segment) {
      return array($segment["longitude"], $segment["latitude"]);
    }, $segments);

    return $geoJSON;
  }

  /**
   * Reads recording
   * 
   * Array of objects with
   * @return time Segment time (number)
   * @return altitude Altitude
   * @return groundspeed Ground speed
   * @return latitude Latitude
   * @return longitude Longitude
   */
  public function read()
  {
    $file = fopen($this->file_name, "rb");
    flock($file, LOCK_SH);

    $segments = [];

    $version = $this->read_header($file);

    if ($version == 1) {
      while (($segment = $this->read_segment_1($file)) != false) {
        array_push($segments, $segment);
      }
    }

    flock($file, LOCK_UN);
    fclose($file);

    return $segments;
  }

  /**
   * Reads one segment entry
   * 
   * @param resource $file File handle
   * 
   * If not EOF
   * @return time Segment time (number)
   * @return altitude Altitude
   * @return groundspeed Ground speed
   * @return latitude Latitude
   * @return longitude Longitude
   * Else
   * @return false
   * 
   * @throws InvalidArgumentException If file is not a resource
   */
  private function read_segment_1($file)
  {
    if (false === is_resource($file)) {
      throw new InvalidArgumentException(sprintf('Argument must be a valid resource type. %s given.', gettype($file)));
    }
    $data = fread($file, 24);
    if ($data) {
      return unpack(Recording::segment_unpack, $data);
    }
    return false;
  }

  /**
   * Reads the file header
   * 
   * @param resource file File handle
   * 
   * @return version File version
   * 
   * @throws InvalidArgumentException If file is not a resource
   * @throws UnexpectedValueException If ident mismatches
   */
  private function read_header($file)
  {
    if (false === is_resource($file)) {
      throw new InvalidArgumentException(sprintf('Argument must be a valid resource type. %s given.', gettype($file)));
    }

    $header = unpack(Recording::header_unpack, fread($file, 6));

    if ($header["ident"] !== Recording::ident) {
      throw
      new UnexpectedValueException(sprintf("Ident mismatch. Got %s, expected %s", $header["ident"], Recording::ident));
    }

    return $header["version"];
  }
}

$r = new Recording("/mnt/f/X-Plane 11/Resources/plugins/GAConnector/flight.rec");
print_r(json_encode($r->geoJSON()));
