210 lines
6.3 KiB
PHP
210 lines
6.3 KiB
PHP
<?php
|
|
|
|
namespace germanairlinesva\file\logbook;
|
|
|
|
require_once "Recording.php";
|
|
|
|
class Logbook
|
|
{
|
|
private const file_name = "/logbook.bin";
|
|
private const recordings_directory = "/recordings/";
|
|
private const ident = "VGAL";
|
|
private const header_unpack = "a4ident/Cversion";
|
|
private const variable_string_size_unpack = "Clength";
|
|
private const flight_start_unpack = "a10date/a1flightType/a4flightNumber/a4aircraftType/a6aircraftRegistration";
|
|
private const flight_middle_unpack = "a5offBlockTime/a5outTime/a5inTime/a5onBlockTime/gtotalFlightTime/" .
|
|
"gtaxiOutFuel/ginFlightFuel/gtaxiInFuel/gtotalFuel/gtaxiOutDistance/ginFlightDistance/gtaxiInDistance/" .
|
|
"gtotalDistance/gmaxLandingRate/Ctouchdowns/gmaxLandingGees";
|
|
private const flight_end_unpack = "gpoints/Cflags";
|
|
|
|
private string $directory_name = "";
|
|
|
|
private array $flights = [];
|
|
private int $total_flights = 0;
|
|
private float $total_points = 0;
|
|
private float $total_distance = 0;
|
|
private float $total_fuel = 0;
|
|
private array $landing_rates = [];
|
|
|
|
public function __construct(string $directory)
|
|
{
|
|
$this->directory_name = $directory;
|
|
|
|
$this->read();
|
|
}
|
|
|
|
/**
|
|
* Generates a json string representation
|
|
*
|
|
* @return string Json string representation
|
|
*/
|
|
public function to_json(): string
|
|
{
|
|
$retVal = [
|
|
"flights" => $this->flights,
|
|
"aggregates" => $this->get_aggregates(),
|
|
];
|
|
|
|
return json_encode($retVal);
|
|
}
|
|
|
|
/**
|
|
* Generates a json string representation of one flight
|
|
*
|
|
* @return string Json string representation of one flight
|
|
*/
|
|
public function get_flight_json($id): string
|
|
{
|
|
return json_encode($this->get_flight($id));
|
|
}
|
|
|
|
private function get_aggregates(): array
|
|
{
|
|
$retVal = [
|
|
"totalFlights" => $this->total_flights,
|
|
"totalPoints" => number_format(doubleval($this->total_points), 2, '.', ','),
|
|
"totalDistance" => number_format(doubleval($this->total_distance), 0, '.', ','),
|
|
"totalFuel" => number_format(doubleval($this->total_fuel), 1, '.', ','),
|
|
];
|
|
|
|
if (count($this->landing_rates) > 0) {
|
|
$rate = 0;
|
|
$lastIndex = count($this->landing_rates) - 1;
|
|
if ($lastIndex % 2 == 0) {
|
|
// Two elements
|
|
$lowerIndex = floor($lastIndex / 2);
|
|
$upperIndex = ceil($lastIndex / 2);
|
|
$lowerRate = $this->landing_rates[$lowerIndex];
|
|
$upperRate = $this->landing_rates[$upperIndex];
|
|
$rate = ($lowerRate + $upperRate) / 2;
|
|
} else {
|
|
// One Element
|
|
$lowerIndex = floor($lastIndex / 2);
|
|
$lowerRate = $this->landing_rates[$lowerIndex];
|
|
$rate = $lowerRate;
|
|
}
|
|
$retVal["landingRate"] = number_format(doubleval($rate), 0, '.', ',');
|
|
} else {
|
|
$retVal["landingRate"] = "N/A";
|
|
}
|
|
|
|
return $retVal;
|
|
}
|
|
|
|
/**
|
|
* Get a specific flight
|
|
*
|
|
* @return array The flight
|
|
*/
|
|
private function get_flight(int $id): array
|
|
{
|
|
$flight = $this->flights[$id];
|
|
try {
|
|
$rec = new \germanairlinesva\file\recording\Recording($this->directory_name .
|
|
Logbook::recordings_directory . $flight["recordingFilename"] . ".rec");
|
|
$flight["recording"] = $rec->to_json();
|
|
} catch (\InvalidArgumentException) {
|
|
}
|
|
|
|
return $flight;
|
|
}
|
|
|
|
/**
|
|
* Reads logbook
|
|
*/
|
|
private function read()
|
|
{
|
|
$file = fopen($this->directory_name . Logbook::file_name, "rb");
|
|
flock($file, LOCK_SH);
|
|
|
|
$version = $this->read_header($file);
|
|
|
|
if ($version == 1) {
|
|
while ($this->read_flight_1($file) != false);
|
|
}
|
|
rsort($this->landing_rates);
|
|
|
|
flock($file, LOCK_UN);
|
|
fclose($file);
|
|
}
|
|
|
|
/**
|
|
* Reads one flight 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_flight_1($file): bool
|
|
{
|
|
if (false === is_resource($file)) {
|
|
throw new \InvalidArgumentException(sprintf('Argument must be a valid resource type. %s given.', gettype($file)));
|
|
}
|
|
|
|
$retVal = [];
|
|
$data = fread($file, 25);
|
|
if ($data) {
|
|
$retVal = array_merge($retVal, unpack(Logbook::flight_start_unpack, $data));
|
|
|
|
$size = unpack(Logbook::variable_string_size_unpack, fread($file, 1))["length"];
|
|
$retVal["departureAirport"] = fread($file, $size);
|
|
$size = unpack(Logbook::variable_string_size_unpack, fread($file, 1))["length"];
|
|
$retVal["departureGate"] = fread($file, $size);
|
|
$size = unpack(Logbook::variable_string_size_unpack, fread($file, 1))["length"];
|
|
$retVal["departureRunway"] = fread($file, $size);
|
|
$size = unpack(Logbook::variable_string_size_unpack, fread($file, 1))["length"];
|
|
$retVal["arrivalAirport"] = fread($file, $size);
|
|
$size = unpack(Logbook::variable_string_size_unpack, fread($file, 1))["length"];
|
|
$retVal["arrivalGate"] = fread($file, $size);
|
|
$size = unpack(Logbook::variable_string_size_unpack, fread($file, 1))["length"];
|
|
$retVal["arrivalRunway"] = fread($file, $size);
|
|
|
|
$retVal = array_merge($retVal, unpack(Logbook::flight_middle_unpack, fread($file, 65)));
|
|
|
|
$size = unpack(Logbook::variable_string_size_unpack, fread($file, 1))["length"];
|
|
$retVal["recordingFilename"] = fread($file, $size);
|
|
|
|
$retVal = array_merge($retVal, unpack(Logbook::flight_end_unpack, fread($file, 5)));
|
|
|
|
array_push($this->flights, $retVal);
|
|
$this->total_flights++;
|
|
$this->total_points += $retVal["points"];
|
|
$this->total_distance += $retVal["totalDistance"];
|
|
$this->total_fuel += $retVal["totalFuel"];
|
|
array_push($this->landing_rates, $retVal["maxLandingRate"]);
|
|
|
|
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(Logbook::header_unpack, fread($file, 5));
|
|
|
|
if ($header["ident"] !== Logbook::ident) {
|
|
throw
|
|
new \UnexpectedValueException(sprintf("Ident mismatch. Got %s, expected %s", $header["ident"], Logbook::ident));
|
|
}
|
|
|
|
return $header["version"];
|
|
}
|
|
}
|