From 4136546b927f78a475cb36b442c051ecaadb605e Mon Sep 17 00:00:00 2001
From: Jacek Kowalski <Jacek@jacekk.info>
Date: Mon, 27 Jan 2020 23:39:17 +0000
Subject: [PATCH] Show when the vehicles were last seen in TTSS

---
 regenerate.php          |    6 +
 parse.php               |   12 ++--
 config.php              |    7 +-
 lib/Database.php        |   42 ++++++++++----
 lib/Mapper.php          |   24 +++++--
 lib/Output.php          |   29 ++++++++-
 composer.json           |    3 
 templates/vehicles.html |   22 +++++++
 8 files changed, 109 insertions(+), 36 deletions(-)

diff --git a/composer.json b/composer.json
index 21ddca9..85d257d 100644
--- a/composer.json
+++ b/composer.json
@@ -7,6 +7,7 @@
     "require": {
         "google/gtfs-realtime-bindings": "^0.0.2",
         "monolog/monolog": "^1.24",
-        "twig/twig": "^2.0"
+        "twig/twig": "^2.0",
+        "twig/extensions": "^1.5"
     }
 }
diff --git a/config.php b/config.php
index 3bb0f3a..3b1ce68 100644
--- a/config.php
+++ b/config.php
@@ -1,5 +1,4 @@
 <?php
-$tramTypes = new TramTypes();
 $sources = [
 	'bus' => [
 		'gtfsrt' => 'ftp://zdmk.krakow.pl/VehiclePositions_A.pb',
@@ -9,18 +8,18 @@
 		'database' => 'mapping_A.sqlite3',
 		'result' => 'mapping_A.json',
 		'result_vehicles' => 'vehicles_A.html',
-		'mapper' => new BusTypes(),
+		'vehicle_types' => new BusTypes(),
 		'prefix' => 'b',
 	],
 	'tram' => [
-		'gtfsrt' => 'ftp://zdmk.krakow.pl/VehiclePositions_T.pb',
+		'gtfsrt' => 'http://gtfs.ztp.krakow.pl/VehiclePositions_T.pb',
 		'gtfsrt_file' => 'VehiclePositions_T.pb',
 		'ttss' => 'http://www.ttss.krakow.pl/internetservice/geoserviceDispatcher/services/vehicleinfo/vehicles?positionType=CORRECTED',
 		'ttss_file' => 'vehicles_T.json',
 		'database' => 'mapping_T.sqlite3',
 		'result' => 'mapping_T.json',
 		'result_vehicles' => 'vehicles_T.html',
-		'mapper' => $tramTypes,
+		'vehicle_types' => new TramTypes(),
 		'prefix' => 't',
 	],
 ];
diff --git a/lib/Database.php b/lib/Database.php
index 22cc51c..e83f4ab 100644
--- a/lib/Database.php
+++ b/lib/Database.php
@@ -10,13 +10,23 @@
 		$this->pdo = new PDO('sqlite:'.$file);
 		$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
 		
-		$this->pdo->query('CREATE TABLE IF NOT EXISTS vehicles (
+		$this->pdo->query('CREATE TABLE IF NOT EXISTS vehicles2 (
 			id INT PRIMARY KEY,
 			num INT UNIQUE,
-			weight INT
+			weight INT,
+			line VARCHAR,
+			date INT
 		)');
+		try {
+			$this->beginTransaction();
+			$this->pdo->query('INSERT INTO vehicles2 SELECT id, num, weight, \'?\', \''.time().'\' FROM vehicles');
+			$this->commit();
+			$this->pdo->query('DROP TABLE vehicles');
+		} catch(PDOException $e) {
+			$this->rollback();
+		}
 		
-		$this->addStatement = $this->pdo->prepare('INSERT OR REPLACE INTO vehicles (id, num, weight) VALUES (:id, :num, :weight)');
+		$this->addStatement = $this->pdo->prepare('INSERT OR REPLACE INTO vehicles2 (id, num, weight, line, date) VALUES (:id, :num, :weight, :line, :date)');
 		
 		$this->_cacheClear();
 	}
@@ -35,7 +45,7 @@
 	
 	protected function _cachePopulate() {
 		if($this->cacheId === NULL) {
-			$st = $this->pdo->prepare('SELECT * FROM vehicles');
+			$st = $this->pdo->prepare('SELECT * FROM vehicles2');
 			$st->execute();
 			$result = $st->fetchAll(PDO::FETCH_ASSOC);
 			
@@ -58,9 +68,14 @@
 		$this->cacheNum = NULL;
 	}
 	
-	public function getAll() {
+	public function getAllById() {
 		$this->_cachePopulate();
 		return $this->cacheId;
+	}
+	
+	public function getAllByNum() {
+		$this->_cachePopulate();
+		return $this->cacheNum;
 	}
 	
 	public function getById($id) {
@@ -74,25 +89,28 @@
 	}
 	
 	public function clear() {
-		$this->pdo->query('DELETE FROM vehicles');
+		$this->pdo->query('DELETE FROM vehicles2');
 		$this->_cacheClear();
 	}
 	
-	public function add($id, $num, $weight) {
+	public function add($id, $num, $weight, $line = NULL, $date = NULL) {
 		$vehicle = [
 			'id' => (string)$id,
 			'num' => (string)$num,
-			'weight' => (string)$weight
+			'weight' => (string)$weight,
+			'line' => (string)($line ?? ''),
+			'date' => (string)($date ?? time()),
 		];
 		$this->addStatement->execute($vehicle);
 		$this->_cacheAdd($vehicle);
 	}
 	
-	public function addMapping($mapping) {
+	public function addMapping($vehiclesMapping, Mapper $mapper) {
 		$this->beginTransaction();
-		$weight = count($mapping);
-		foreach($mapping as $id => $num) {
-			$this->add($id, $num, $weight);
+		$weight = count($vehiclesMapping);
+		foreach($vehiclesMapping as $id => $num) {
+			$trip = $mapper->getTTSSVehicleTrip($id);
+			$this->add($id, $num, $weight, ($trip['line'] ?? '?') . ' ' . ($trip['direction'] ?? '?'));
 		}
 		$this->commit();
 	}
diff --git a/lib/Mapper.php b/lib/Mapper.php
index a36b4ef..7f0e701 100644
--- a/lib/Mapper.php
+++ b/lib/Mapper.php
@@ -4,6 +4,7 @@
 class Mapper {
 	private $ttssDate = NULL;
 	private $ttssTrips = [];
+	private $ttssVehicleToTrip = [];
 	private $gtfsrtDate = NULL;
 	private $gtfsrtTrips = [];
 	private $logger = NULL;
@@ -35,18 +36,15 @@
 			if(!isset($vehicle->latitude) || !$vehicle->latitude) continue;
 			if(!isset($vehicle->longitude) || !$vehicle->longitude) continue;
 			list($line, $direction) = explode(' ', $vehicle->name, 2);
-			foreach($this->specialNames as $specialName) {
-				if(substr($vehicle->name, -strlen($specialName)) == $specialName) {
-					continue;
-				}
-			}
-			$this->ttssTrips[(string)$vehicle->tripId] = [
+			$trip = [
 				'id' => (string)$vehicle->id,
 				'line' => $line,
 				'direction' => $direction,
 				'latitude' => (float)$vehicle->latitude / 3600000.0,
 				'longitude' => (float)$vehicle->longitude / 3600000.0,
 			];
+			$this->ttssTrips[(string)$vehicle->tripId] = $trip;
+			$this->ttssVehicleToTrip[(string)$vehicle->id] = $trip;
 		}
 		ksort($this->ttssTrips);
 	}
@@ -57,6 +55,18 @@
 	
 	public function getTTSSTrips() {
 		return $this->ttssTrips;
+	}
+	
+	public function getTTSSVehicleToTrip() {
+		return $this->ttssVehicleToTrip;
+	}
+	
+	public function getTTSSTrip($id) {
+		return $this->ttssTrips[$id] ?? NULL;
+	}
+	
+	public function getTTSSVehicleTrip($id) {
+		return $this->ttssVehicleToTrip[$id] ?? NULL;
 	}
 	
 	public function loadGTFSRT($file) {
@@ -130,7 +140,7 @@
 		return $bestOffset;
 	}
 	
-	public function mapUsingOffset($offset) {
+	public function mapVehicleIdsUsingOffset($offset) {
 		$result = [];
 		foreach($this->gtfsrtTrips as $gtfsTripId => $gtfsTrip) {
 			$ttssTripId = $gtfsTripId + $offset;
diff --git a/lib/Output.php b/lib/Output.php
index 2944625..0fda9ab 100644
--- a/lib/Output.php
+++ b/lib/Output.php
@@ -1,9 +1,19 @@
 <?php
 class Output {
-	static function createMapping($db, VehicleTypes $vehicleTypes, $saveConfig = FALSE) {
+	private $db;
+	private $mapper;
+	private $vehicleTypes;
+	
+	function __construct(Database $db, Mapper $mapper, VehicleTypes $vehicleTypes) {
+		$this->db = $db;
+		$this->mapper = $mapper;
+		$this->vehicleTypes = $vehicleTypes;
+	}
+	
+	function createMapping($saveConfig = FALSE) {
 		$mapping = [];
-		foreach($db->getAll() as $vehicle) {
-			$mapping[$vehicle['id']] = $vehicleTypes->getByNumber($vehicle['num']);
+		foreach($this->db->getAllById() as $vehicle) {
+			$mapping[$vehicle['id']] = $this->vehicleTypes->getByNumber($vehicle['num']);
 		}
 		
 		if($saveConfig) {
@@ -17,11 +27,13 @@
 		return $mapping;
 	}
 	
-	function createVehiclesList($trips, $mapping, $saveConfig = FALSE) {
+	function createVehiclesList($fullMapping, $saveConfig = FALSE) {
+		$trips = $this->mapper->getTTSSTrips();
+		
 		$lines = [];
 		$vehicles = [];
 		foreach($trips as $trip) {
-			$vehicle = $mapping[$trip['id']] ?? [];
+			$vehicle = $fullMapping[$trip['id']] ?? [];
 			$vehicle += ['trip' => $trip['id']];
 			$lines[$trip['line']][] = [
 				'trip' => $trip,
@@ -29,6 +41,7 @@
 			];
 			$vehicles[$vehicle['type'] ?? '?'][] = $vehicle;
 		}
+		
 		foreach($lines as &$line) {
 			usort($line, function($a, $b) {
 				return (substr($a['vehicle']['num'] ?? '', 2) <=> substr($b['vehicle']['num'] ?? '', 2)); 
@@ -36,6 +49,7 @@
 		}
 		unset($line);
 		ksort($lines);
+		
 		foreach($vehicles as &$vehicle) {
 			usort($vehicle, function($a, $b) {
 				return (substr($a['num'] ?? '', 2) <=> substr($b['num'] ?? '', 2));
@@ -44,14 +58,19 @@
 		unset($vehicle);
 		ksort($vehicles);
 		
+		$dbMapping = $this->db->getAllByNum();
+		ksort($dbMapping);
+		
 		if($saveConfig) {
 			$twigLoader = new \Twig\Loader\FilesystemLoader(__DIR__.'/../templates');
 			$twig = new \Twig\Environment($twigLoader);
+			$twig->addExtension(new Twig_Extensions_Extension_Date());
 			
 			$vehiclesHtml = $twig->render('vehicles.html', [
 				'lines' => $lines,
 				'vehicles' => $vehicles,
 				'prefix' => $saveConfig['prefix'],
+				'mapping' => $dbMapping,
 			]);
 			if(!file_put_contents($saveConfig['result_vehicles_temp'], $vehiclesHtml)) {
 				throw new Exception('Vehicles save failed');
diff --git a/parse.php b/parse.php
index 3252150..c54f19d 100644
--- a/parse.php
+++ b/parse.php
@@ -39,7 +39,7 @@
 		}
 		
 		$logger->info('Got offset '.$offset.', creating mapping...');
-		$mapping = $mapper->mapUsingOffset($offset);
+		$mapping = $mapper->mapVehicleIdsUsingOffset($offset);
 		
 		$logger->info('Checking the data for correctness...');
 		$weight = count($mapping);
@@ -72,17 +72,17 @@
 			throw new Exception('Ignoring result due to better data already present');
 		}
 		
+		$output = new Output($db, $mapper, $source['vehicle_types']);
 		
-		$logger->info('Creating mapping...');
+		$logger->info('Saving mapping...');
 		
-		$db->addMapping($mapping);
+		$db->addMapping($mapping, $mapper);
 		
-		$finalMapping = Output::createMapping($db, $source['mapper'], $source);
-		
+		$fullMapping = $output->createMapping($source);
 		
 		$logger->info('Creating vehicle list...');
 		
-		Output::createVehiclesList($mapper->getTTSSTrips(), $finalMapping, $source);
+		$output->createVehiclesList($fullMapping, $source);
 		
 		$logger->info('Finished');
 	} catch(Throwable $e) {
diff --git a/regenerate.php b/regenerate.php
index aaa821f..643a9f0 100644
--- a/regenerate.php
+++ b/regenerate.php
@@ -7,7 +7,11 @@
 	try {
 		$logger->info('Regenerating '.$name.'...');
 		$db = new Database($source['database']);
-		Output::createMapping($db, $source['mapper'], $source);
+		$mapper = new Mapper();
+		$mapper->loadTTSS($source['ttss_file']);
+		$output = new Output($db, $mapper, $source['vehicle_types']);
+		$fullMapping = $output->createMapping($source);
+		$output->createVehiclesList($fullMapping, $source);
 		$logger->info('Finished');
 	} catch(Throwable $e) {
 		$logger->error($e->getMessage(), ['exception' => $e, 'exception_string' => (string)$e]);
diff --git a/templates/vehicles.html b/templates/vehicles.html
index 9c9d4e7..2302e8a 100644
--- a/templates/vehicles.html
+++ b/templates/vehicles.html
@@ -80,6 +80,28 @@
 {% endfor %}
 </table>
 
+<table>
+<caption>Vehicles in TTSS</caption>
+<thead>
+<tr>
+<th>Vehicle</th> <th>Line</th> <th>Last seen</th>
+</tr>
+</thead>
+{% for map in mapping %}
+<tr>
+<td>
+{{ map.num | e }}
+</td>
+<td>
+{{ map.line | default('?') | e }}
+</td>
+<td>
+{{ map.date | time_diff | default('now') }}
+</td>
+</tr>
+{% endfor %}
+</table>
+
 Generated at {{ "now" | date("Y-m-d H:i:s P") }}
 
 </table>

--
Gitblit v1.9.1