Files
dev-chiefworks 47f4fad75c Added Other AP
2022-04-26 11:30:34 -04:00

555 lines
19 KiB
PHP

<?php
class MultiModal {
public function getLegById($db, $id) {
syslog(LOG_WARNING,"MultiModal::getLegById(\$db, $id)");
list($departure_time_zone,$arrival_time_zone) = self::getLegTimezones($db, $id);
$q = "SELECT a.*,b.timezone AS departure_timezone,c.timezone AS arrival_timezone FROM google_directions_legs a ";
$q.= " LEFT JOIN address_timezone b ON b.id=${departure_time_zone} ";
$q.= " LEFT JOIN address_timezone c ON c.id=${arrival_time_zone} ";
$q.= " WHERE a.id=".((int)$id);
syslog(LOG_WARNING,$q);
$r = pg_query($db, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
return [$f, NULL];
}
return [NULL, pg_last_error($db)];
}
public function getAdviceLegs($db, $advice_id) {
syslog(LOG_WARNING,"MultiModal::getAdviceLegs(\$db, $advice_id)");
list($departure_time_zone,$arrival_time_zone) = self::getLegTimezones($db, $advice_id);
$q = "SELECT a.*,b.timezone AS departure_timezone,c.timezone AS arrival_timezone FROM google_directions_legs a ";
$q.= " LEFT JOIN address_timezone b ON b.id=${departure_time_zone} ";
$q.= " LEFT JOIN address_timezone c ON c.id=${arrival_time_zone} ";
$q.= " WHERE a.parsedemail_item_advice_google_id=".((int)$advice_id);
$r = pg_query($db, $q);
if ($r && pg_num_rows($r)) {
$result = [];
while ($f=pg_fetch_assoc($r)) {
$result[$f['id']] = $f;
}
return [$result, NULL];
}
return [NULL, pg_last_error($db)];
}
public function getLegSteps($db, $id) {
$result = NULL;
$q = "SELECT a.id AS sid, a.*,b.*,c.* FROM google_directions_leg_steps a ";
$q.= " LEFT JOIN google_directions_leg_step_details b ON (b.google_directions_leg_step_id=a.id) ";
$q.= " LEFT JOIN leg_step_quote c ON (c.google_directions_leg_step_id=a.id) ";
$q.= " WHERE a.google_directions_leg_id=".((int)$id);
$r = pg_query($db, $q);
if ($r && pg_num_rows($r)) {
while ($f=pg_fetch_assoc($r)) {
if ($f["polyline"]=="") {
$f["polyline"] = self::getPolyline($db, $f);
}
$result[] = $f;
}
return [$result, NULL];
}
return [NULL, pg_last_error($db)];
}
public function getStepQuote($db, $id) {
$q = "SELECT * FROM leg_step_quote WHERE google_directions_leg_step_id=${id} ORDER BY id DESC LIMIT 1";
error_log($q);
$r = pg_query($db, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
return [$f, NULL];
}
return [NULL, pg_last_error($db)];
}
public function getLegAdviceGoogleById($db, $id) {
syslog(LOG_WARNING,"MultiModal::getLegAdviceGoogleById(\$db, $id)");
$q = "SELECT * FROM parsedemail_item_advice_google WHERE id=${id}";
$r = pg_query($db, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
return [$f, NULL];
}
return [NULL, pg_last_error($db)];
}
public function getLastGoogleAdviceByTrip($db, $id) {
$q = "SELECT *,EXTRACT(EPOCH FROM (NOW()-updated)) AS elapsed FROM parsedemail_item_advice_google WHERE parsedemail_item_id=${id} ORDER BY updated DESC LIMIT 1";
$r = pg_query($db, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
return [$f, NULL];
}
return [NULL, pg_last_error($db)];
}
public function getTimezoneById($db, $id) {
$q = "SELECT timezone FROM address_timezone WHERE id=".((int)$id);
$r = pg_query($db, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
return $f;
}
return $id;
}
public function create($db, $trip) {
list ($id, $err) = self::saveParsedemailItemAdviceGoogle($db, [
'parsedemail_item_id' => $trip['id'],
'routes' => count($trip['options']['legs'])
]);
if ($id && $id>0) {
$trip['options']['gid'] = $id;
error_log('New parsedemail_item_advice_google.id='.$id);
} else {
return [NULL, 'Failed to create advice record'];
}
$timezones = [];
$n = count($trip['options']['legs']);
for ($i=0; $i<$n; $i++) {
$leg = $trip['options']['legs'][$i];
$leg_id = $leg['id'];
$leg_steps = $trip['options']['leg_steps'][$leg_id];
$leg_fare = $trip['options']['leg_fare'][$leg_id];
// Timezones
foreach(array("departure","arrival") as $tzid) {
$key1 = "${tzid}_time_zone";
$key2 = "${tzid}_timezone";
if (array_key_exists($leg[$key1],$timezones)) {
$leg[$key2] = $timezones[$leg[$key1]];
} else {
$tz = self::getTimezoneById($db, $leg[$key1]);
$timezones[$leg[$key1]] = $tz;
$leg[$key2] = $tz;
}
}
//error_log(json_encode($leg));
list ($id, $err) = self::saveGoogleDirectionsLeg($db, [
'parsedemail_item_advice_google_id' => $trip['options']['gid'],
'arrival_time' => $leg["arrival_time"],
'arrival_time_zone' => $leg["arrival_time_zone"],
'departure_time' => $leg["departure_time"],
'departure_time_zone' => $leg["departure_time_zone"],
'distance' => $leg["distance"],
'duration' => $leg["duration"],
'steps' => $leg["steps"],
'fare_raw' => $leg["fare_raw"],
'polyline' => self::processPolyline($leg["polyline"])
]);
if ($id && $id>0) {
$old_leg_id = $leg_id;
$leg_id = $id;
$leg['parsedemail_item_advice_google_id'] = $trip['options']['gid'];
// Legs
$leg['id'] = $id;
$trip['options']['legs'][$i] = $leg;
// Leg steps
unset($trip["options"]["leg_steps"][$old_leg_id]);
$trip['options']['leg_steps'][$leg_id] = $leg_steps;
// Leg fare
unset($trip['options']['leg_fare'][$old_leg_id]);
$trip['options']['leg_fare'][$leg_id] = $leg_fare;
// ...
error_log('New google_directions_legs.id='.$id);
} else {
self::deleteAdviceGoogle($db, $trip['options']['gid']);
return [NULL, 'Failed to create leg record: '.$err];
}
$m = count($leg_steps);
for ($j=0; $j<$m; $j++) {
$step = $leg_steps[$j];
$data = [
'google_directions_leg_id' => $leg_id,
'distance' => $step["distance"],
'duration' => $step["duration"],
'travel_mode' => $step["travel_mode"],
'location_start_lat' => $step["location_start_lat"],
'location_start_lng' => $step["location_start_lng"],
'location_end_lat' => $step["location_end_lat"],
'location_end_lng' => $step["location_end_lng"],
'html_instructions' => $step["html_instructions"],
'polyline' => self::processPolyline($step["polyline"])
];
list($id, $err) = self::saveGoogleDirectionsLegStep($db, $data);
if ($id && $id>0) {
$sid = $id;
$step['sid'] = $id;
$leg_steps[$j] = $step;
if ($data['polyline']=="") { // We do not have a polyline - try get one...
$data['id'] = $id;
$data['sid'] = $sid;
$polyline = self::getPolyline($db, $data);
}
error_log('New google_directions_leg_steps.id='.$sid);
} else {
self::deleteAdviceGoogle($db, $trip['options']['gid']);
return [NULL, 'Failed to create leg step record'];
}
if (count($step)>20) {
list($id, $err) = self::saveGoogleDirectionsLegStepDetail($db, [
'google_directions_leg_step_id' => $sid,
'num_stops' => $step["num_stops"],
'line' => $step["line"],
'vehicle' => $step["vehicle"],
'departure_stop' => $step["departure_stop"],
'departure_stop_lat' => $step["departure_stop_lat"],
'departure_stop_lng' => $step["departure_stop_lng"],
'arrival_stop' => $step["arrival_stop"],
'arrival_stop_lat' => $step["arrival_stop_lat"],
'arrival_stop_lng' => $step["arrival_stop_lng"],
'headsign' => $step["headsign"],
'headway' => $step["headway"]
]);
if ($id && $id>0) {
$step['id'] = $id;
$leg_steps[$j] = $step;
error_log('New google_directions_leg_step_details.id='.$id);
error_log(json_encode($step));
if (array_key_exists("fare_raw",$step)) {
self::saveLegStepQuote($db, [
'google_directions_leg_step_id' => $sid,
'name' => $step["line"],
'service' => $step["agency"],
'board' => $step["departure_stop"],
'alight' => $step["arrival_stop"],
'distance' => sprintf("%0.02f",$step["distance"]/1000),
'fare' => $step["fare"],
'fare_raw' => $step["fare_raw"],
'distance_raw' => $step["distance"]
]);
}
} else {
self::deleteAdviceGoogle($db, $trip['options']['gid']);
return [NULL, 'Failed to create leg step detail record'];
}
} else {
error_log('Step #'.$sid.' does not have details');
}
} // for
$trip['options']['leg_steps'][$leg_id] = $leg_steps;
} // for
return [$trip, NULL];
}
public function getLegStepQuotes($db, $id) {
$q = "SELECT * FROM leg_step_quote WHERE google_directions_leg_step_id ";
$q.= " IN (SELECT id FROM google_directions_leg_steps WHERE google_directions_leg_id=${id})";
$r = pg_query($db, $q);
if ($r && pg_num_rows($r)) {
$quotes = [];
while ($f=pg_fetch_assoc($r)) {
$quotes[] = $f;
}
return [$quotes, NULL];
}
return [NULL, pg_last_error($db)];
}
public function delete($db, $id) {
$result = 0;
$q = "DELETE FROM leg_step_quote WHERE google_directions_leg_step_id ";
$q.= " IN (SELECT id FROM google_directions_leg_steps WHERE google_directions_leg_id ";
$q.= " IN (SELECT id FROM google_directions_legs WHERE parsedemail_item_advice_google_id ";
$q.= " IN (SELECT id FROM parsedemail_item_advice_google WHERE parsedemail_item_id=${id})))";
$r = pg_query($db, $q);
if ($r && pg_affected_rows($r)) {
$result++;
}
//error_log(pg_last_error());
$q = "DELETE FROM google_directions_leg_step_details WHERE google_directions_leg_step_id ";
$q.= " IN (SELECT id FROM google_directions_leg_steps WHERE google_directions_leg_id ";
$q.= " IN (SELECT id FROM google_directions_legs WHERE parsedemail_item_advice_google_id ";
$q.= " IN (SELECT id FROM parsedemail_item_advice_google WHERE parsedemail_item_id=${id})))";
$r = pg_query($db, $q);
if ($r && pg_affected_rows($r)) {
$result++;
}
//error_log(pg_last_error());
$q = "DELETE FROM google_directions_leg_steps WHERE google_directions_leg_id ";
$q.= " IN (SELECT id FROM google_directions_legs WHERE parsedemail_item_advice_google_id ";
$q.= " IN (SELECT id FROM parsedemail_item_advice_google WHERE parsedemail_item_id=${id}))";
$r = pg_query($db, $q);
if ($r && pg_affected_rows($r)) {
$result++;
}
//error_log(pg_last_error());
$q = "DELETE FROM google_directions_legs WHERE parsedemail_item_advice_google_id ";
$q.= " IN (SELECT id FROM parsedemail_item_advice_google WHERE parsedemail_item_id=${id})";
$r = pg_query($db, $q);
if ($r && pg_affected_rows($r)) {
$result++;
}
//error_log(pg_last_error());
$q = "DELETE FROM parsedemail_item_advice_google WHERE parsedemail_item_id=${id}";
$r = pg_query($db, $q);
if ($r && pg_affected_rows($r)) {
$result++;
}
//error_log(pg_last_error());
$q = "DELETE FROM parsedemail_item WHERE id=${id}";
$r = pg_query($db, $q);
if ($r && pg_affected_rows($r)) {
$result++;
}
//error_log(pg_last_error());
return $result;
}
public function deleteAdviceGoogle($db, $id) {
$result = 0;
$q = "DELETE FROM leg_step_quote WHERE google_directions_leg_step_id ";
$q.= " IN (SELECT id FROM google_directions_leg_steps WHERE google_directions_leg_id ";
$q.= " IN (SELECT id FROM google_directions_legs WHERE parsedemail_item_advice_google_id ";
$q.= " IN (SELECT id FROM parsedemail_item_advice_google WHERE parsedemail_item_id=${id})))";
$r = pg_query($db, $q);
if ($r && pg_affected_rows($r)) {
$result++;
}
$q = "DELETE FROM google_directions_leg_step_details WHERE google_directions_leg_step_id
IN (SELECT id FROM google_directions_leg_steps WHERE google_directions_leg_id
IN (SELECT id FROM google_directions_legs WHERE parsedemail_item_advice_google_id
IN (SELECT id FROM parsedemail_item_advice_google WHERE id=${id})))";
$r = pg_query($db, $q);
if ($r && pg_affected_rows($r)) {
$result++;
}
$q = "DELETE FROM google_directions_leg_steps WHERE google_directions_leg_id
IN (SELECT id FROM google_directions_legs WHERE parsedemail_item_advice_google_id
IN (SELECT id FROM parsedemail_item_advice_google WHERE id=${id}))";
$r = pg_query($db, $q);
if ($r && pg_affected_rows($r)) {
$result++;
}
$q = "DELETE FROM google_directions_legs WHERE parsedemail_item_advice_google_id
IN (SELECT id FROM parsedemail_item_advice_google WHERE id=${id})";
$r = pg_query($db, $q);
if ($r && pg_affected_rows($r)) {
$result++;
}
$q = "DELETE FROM parsedemail_item_advice_google WHERE id=${id}";
$r = pg_query($db, $q);
if ($r && pg_affected_rows($r)) {
$result++;
}
return $result;
}
public function saveParsedemailItem($db, $data) {
$fields = array(
'travel_date' => false,
'duration' => false,
'cost_raw' => false,
'trackedemail_item_id' => false,
'cost' => false,
'updated' => false,
'distance' => false,
'transport_provider_id' => false,
'scheduled' => false,
'travel_date_end' => false,
'dup_id' => false,
'location_start_id' => true,
'location_end_id' => true,
'private' => false
);
return self::saveGeneric($db, $fields, $data, 'parsedemail_item');
}
public function saveParsedemailItemAdviceGoogle($db, $data) {
$fields = array(
'parsedemail_item_id' => true,
'routes' => true
);
return self::saveGeneric($db, $fields, $data, 'parsedemail_item_advice_google');
}
public function saveGoogleDirectionsLeg($db, $data) {
$fields = array(
'parsedemail_item_advice_google_id' => true,
'arrival_time' => false,
'arrival_time_zone' => false,
'departure_time' => false,
'departure_time_zone' => false,
'distance' => false,
'duration' => false,
'steps' => false,
'fare_raw' => false,
'polyline' => false
);
return self::saveGeneric($db, $fields, $data, 'google_directions_legs');
}
public function saveGoogleDirectionsLegStep($db, $data) {
$fields = array(
'google_directions_leg_id' => true,
'distance' => false,
'duration' => false,
'travel_mode' => false,
'location_start_lat' => false,
'location_start_lng' => false,
'location_end_lat' => false,
'location_end_lng' => false,
'html_instructions' => false,
'polyline' => false
);
return self::saveGeneric($db, $fields, $data, 'google_directions_leg_steps');
}
public function saveGoogleDirectionsLegStepDetail($db, $data) {
$fields = array(
'google_directions_leg_step_id' => true,
'num_stops' => false,
'line' => false,
'vehicle' => false,
'departure_stop' => false,
'departure_stop_lat' => false,
'departure_stop_lng' => false,
'arrival_stop' => false,
'arrival_stop_lat' => false,
'arrival_stop_lng' => false,
'headsign' => false,
'headway' => false
);
return self::saveGeneric($db, $fields, $data, 'google_directions_leg_step_details');
}
public function saveLegStepQuote($db, $data) {
error_log('public function saveLegStepQuote($db, $data)');
$fields = array(
'google_directions_leg_step_id' => true,
'name' => false,
'service' => false,
'board' => false,
'alight' => false,
'distance' => false,
'fare' => false,
'fare_raw' => true,
'distance_raw' => false
);
return self::saveGeneric($db, $fields, $data, 'leg_step_quote');
}
private function saveGeneric($db, $fields, $data, $table) {
$q = "select column_name, data_type, character_maximum_length from INFORMATION_SCHEMA.COLUMNS where table_name = '${table}'";
$r = pg_query($db, $q);
$columns = [];
while ($f=pg_fetch_assoc($r)) {
$columns[$f['column_name']] = $f;
}
$field_key_list = [];
$field_val_list = [];
foreach ($fields as $key=>$required) {
if ($required && !isset($data[$key])) {
return [NULL, "Missing required field '${key}'"];
}
if (!isset($data[$key])) continue;
$field_key_list[] = "${key}";
if (isset($columns[$key]) && ($columns[$key]["data_type"]=='integer' || $columns[$key]["data_type"]=='bigint')) {
$field_val_list[] = ($data[$key]==NULL || strlen($data[$key])==0)?"NULL":((int)$data[$key]);
} else {
$field_val_list[] = (($data[$key]==NULL || $data[$key]=="")?"NULL":"'".pg_escape_string($data[$key])."'");
}
}
$q = "INSERT INTO ${table} (".implode(",",$field_key_list).") VALUES(".implode(",",$field_val_list).") RETURNING id";
//error_log($q);
$r = pg_query($db, $q);
if ($r && pg_num_rows($r)) {
$f = pg_fetch_row($r);
return [$f[0], NULL];
}
return [NULL, pg_last_error($db)];
}
public function processPolyline($data) {
if (!is_array($data)) {
return $data;
}
$points = [];
foreach ($data as $item) {
$points = array_merge($points, Polyline::decode($item));
}
return Polyline::encode($points);
}
public function getPolyline($db, $f) {
$q = "SELECT polyline FROM google_directions_leg_steps WHERE ";
$q.= " location_start_lat='".$f["location_start_lat"]."' AND ";
$q.= " location_start_lng='".$f["location_start_lng"]."' AND ";
$q.= " location_end_lat='".$f["location_end_lat"]."' AND ";
$q.= " location_end_lng='".$f["location_end_lng"]."' AND ";
$q.= " polyline<>'' ORDER BY ID desc LIMIT 1";
$r = pg_query($db, $q);
if ($r && pg_num_rows($r) && $polyline=pg_fetch_row($r)) {
$f["polyline"] = $polyline[0];
$q = "UPDATE google_directions_leg_steps SET polyline='".pg_escape_string($f["polyline"])."' WHERE id=".$f['sid']." RETURNING *";
$r = pg_query($db, $q); // Do not quite care...
return $f["polyline"];
}
$res = MultiModalApi::getPolyline($f["sid"]);
if (is_array($res) && isset($res["code"]) && $res["code"]==0) {
if (isset($res["data"]) && isset($res["data"]["polyline"])) {
return $res["data"]["polyline"]; // No need to update
}
}
return $f["polyline"];
}
public function getDate($country) {
$tz = 'Asia/Singapore';
if ($country=='US') {
$tz = 'America/Los_Angeles';
}
$timestamp = time();
$dt = new DateTime("now", new DateTimeZone($tz)); //first argument "must" be a string
$dt->setTimestamp($timestamp); //adjust the object to correct timestamp
return $dt->format('Y-m-d, H:i:s');
}
public function getLegTimezones($db, $id) {
$departure_time_zone = 1; // Asia/Singapore
$q = "SELECT departure_time_zone FROM google_directions_legs WHERE id=".((int)$id);
$r = pg_query($db, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
if (is_integer($f[0]) && $f[0]>0) {
$departure_time_zone = $f[0];
} else {
$q = "SELECT * FROM address_timezone WHERE lower(timezone)=lower('".$f[0]."')";
$r = pg_query($db, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
$departure_time_zone = $f[0];
}
}
}
$arrival_time_zone = 1; // Asia/Singapore
$q = "SELECT arrival_time_zone FROM google_directions_legs WHERE id=".((int)$id);
$r = pg_query($db, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
if (is_integer($f[0]) && $f[0]>0) {
$arrival_time_zone = $f[0];
} else {
$q = "SELECT * FROM address_timezone WHERE lower(timezone)=lower('".$f[0]."')";
$r = pg_query($db, $q);
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
$arrival_time_zone = $f[0];
}
}
}
return [$departure_time_zone, $arrival_time_zone];
}
public function getLegTimezonesForAdvice($db, $id) {
$result = [];
$q = "SELECT id FROM google_directions_legs WHERE parsedemail_item_advice_google_id=".((int)$id);
$r = pg_query($db, $q);
while ($f=pg_fetch_row($r)) {
$result[$f[0]] = self::getLegTimezones($db, $f[0]);
}
return $result;
}
}
// vi:ts=2