<?php

namespace germanairlinesva\file\recording;

class Recording
{
  private const ident = "VGAR";
  private const header_unpack = "a4ident/Cversion";
  private const segment_unpack = "Vtime/Saltitude/Sgroundspeed/elatitude/elongitude";

  private string $file_path = "";

  private array $segments = [];

  public function __construct(string $path)
  {
    $this->file_path = $path;

    $this->read();
  }

  /**
   * Generates a json representation
   * 
   * @return array Json representation with path as geoJSON and profile as array
   */
  public function to_json(): array
  {
    $path = [
      "type" => "FeatureCollection",
      "features" => [
        0 => [
          "type" => "Feature",
          "properties" => [
            "stroke" => "#ff0000",
            "stroke-width" => 2,
            "stroke-opacity" => 1
          ],
          "geometry" => [
            "type" => "LineString",
            "coordinates" => []
          ]
        ]
      ]
    ];
    $path["features"][0]["geometry"]["coordinates"] = array_map(function ($segment) {
      return array($segment["longitude"], $segment["latitude"]);
    }, $this->segments);

    $profile = array_map(function ($segment) {
      return array("altitude" => $segment["altitude"], "groundspeed" => $segment["groundspeed"]);
    }, $this->segments);

    return ["path" => $path, "profile" => $profile];
  }

  /**
   * Generates a json string representation
   * 
   * @return string Json string representation with path as geoJSON and profile as array
   */
  public function to_json_string(): string
  {
    return json_encode($this->to_json());
  }

  /**
   * Reads recording
   */
  private function read()
  {
    if (!file_exists($this->file_path)) {
      throw new \InvalidArgumentException("File not found");
    }

    $file = fopen($this->file_path, "rb");
    if ($file) {
      flock($file, LOCK_SH);

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

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

      flock($file, LOCK_UN);
      fclose($file);
    } else {
      throw new \Exception("fopen Error");
    }
  }

  /**
   * Reads one segment entry
   * 
   * @param resource $file File handle
   * 
   * @return true If not EOF
   * @return false If EOF
   * 
   * @throws InvalidArgumentException If file is not a resource
   */
  private function read_segment_1($file): bool
  {
    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) {
      array_push($this->segments, unpack(Recording::segment_unpack, $data));

      return true;
    }
    return false;
  }

  /**
   * Reads the file header
   * 
   * @param resource $file File handle
   * 
   * @return string File version
   * 
   * @throws InvalidArgumentException If file is not a resource
   * @throws UnexpectedValueException If ident mismatches
   */
  private function read_header($file): string
  {
    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, 5));

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

    return $header["version"];
  }
}
