MyWay timeliness study data collection
MyWay timeliness study data collection

--- a/include/common-db.inc.php
+++ b/include/common-db.inc.php
@@ -11,6 +11,9 @@
 if (!$conn) {
 	die("A database error occurred.\n");
 }
+if (isDebug()) {
+  $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+}
 function databaseError($errMsg)
 {
 	die($errMsg);

--- a/include/common-geo.inc.php
+++ b/include/common-geo.inc.php
@@ -3,6 +3,7 @@
 $suburbs = explode(",", "Acton,Ainslie,Amaroo,Aranda,Banks,Barton,Belconnen,Bonner,Bonython,Braddon,Bruce,Calwell,Campbell,Chapman,Charnwood,Chifley,Chisholm,City,Conder,Cook,Curtin,Deakin,Dickson,Downer,Duffy,Dunlop,Evatt,Fadden,Farrer,Fisher,Florey,Flynn,Forrest,Franklin,Fraser,Fyshwick,Garran,Gilmore,Giralang,Gordon,Gowrie,Greenway,Griffith,Gungahlin,Hackett,Hall,Harrison,Hawker,Higgins,Holder,Holt,Hughes,Hume,Isaacs,Isabella Plains,Kaleen,Kambah,Kingston,Latham,Lawson,Lyneham,Lyons,Macarthur,Macgregor,Macquarie,Mawson,McKellar,Melba,Mitchell,Monash,Narrabundah,Ngunnawal,Nicholls,Oaks Estate,O'Connor,O'Malley,Oxley,Page,Palmerston,Parkes,Pearce,Phillip,Pialligo,Red Hill,Reid,Richardson,Rivett,Russell,Scullin,Spence,Stirling,Symonston,Tharwa,Theodore,Torrens,Turner,Wanniassa,Waramanga,Watson,Weetangera,Weston,Yarralumla");
 function staticmap($mapPoints, $zoom = 0, $markerImage = "iconb", $collapsible = true)
 {
+	global $labsPath;
 	$width = 300;
 	$height = 300;
 	$metersperpixel[9] = 305.492 * $width;
@@ -47,7 +48,7 @@
 	}
 	$output = "";
 	if ($collapsible) $output.= '<div class="map" data-role="collapsible" data-collapsed="true"><h3>Open Map...</h3>';
-	$output.= '<img class="map" src="' . curPageURL() . '/lib/staticmaplite/staticmap.php?center=' . $center . '&amp;zoom=' . $zoom . '&amp;size=' . $width . 'x' . $height . '&amp;markers=' . 
+	$output.= '<img class="map" src="' . curPageURL() . '/'. $labsPath. '/lib/staticmaplite/staticmap.php?center=' . $center . '&amp;zoom=' . $zoom . '&amp;size=' . $width . 'x' . $height . '&amp;markers=' . 
 $markers . '" width=' . $width . ' height=' . $height . '>';
 	if ($collapsible) $output.= '</div>';
 	return $output;

--- a/include/common-template.inc.php
+++ b/include/common-template.inc.php
@@ -23,9 +23,6 @@
 	$url.= "&guid=ON";
 	return str_replace("&", "&amp;", $url);
 }
-
-$labsPath = "";
-if (strstr($_SERVER['PHP_SELF'],"labs")) $labsPath = "../";
 
 function include_header($pageTitle, $pageType, $opendiv = true, $geolocate = false, $datepicker = false)
 {

--- a/include/common-transit.inc.php
+++ b/include/common-transit.inc.php
@@ -5,16 +5,16 @@
 	'weekday'
 );
 
-function service_period()
+function service_period($date = "")
 {
 	
 	if (isset($_SESSION['service_period'])) return $_SESSION['service_period'];
-	$override = getServiceOverride();
+	$override = getServiceOverride($date);
 	if ($override['service_id']){
 		return $override['service_id'];
 	}
 
-	switch (date('w')) {
+	switch (date('w',($date != "" ? $date : time()))) {
 	case 0:
 		return 'sunday';
 	case 6:

--- a/include/common.inc.php
+++ b/include/common.inc.php
@@ -26,6 +26,8 @@
 		$otpAPIurl = 'http://10.0.1.135:8080/opentripplanner-api-webapp/';
 }
 if (isDebug("phperror")) error_reporting(E_ALL ^ E_NOTICE);
+$labsPath = "";
+if (strstr($_SERVER['PHP_SELF'],"labs")) $labsPath = "../";
 
 include_once ("common-geo.inc.php");
 include_once ("common-net.inc.php");

--- a/include/db/route-dao.inc.php
+++ b/include/db/route-dao.inc.php
@@ -14,6 +14,21 @@
 	return $query->fetch(PDO::FETCH_ASSOC);
 }
 
+function getRouteByFullName($routeFullName)
+{
+	global $conn;
+	$query = "Select * from routes where route_short_name||route_long_name = :routeFullName LIMIT 1";
+	debug($query, "database");
+	$query = $conn->prepare($query);
+	$query->bindParam(":routeFullName", $routeFullName);
+	$query->execute();
+	if (!$query) {
+		databaseError($conn->errorInfo());
+		return Array();
+	}
+	return $query->fetch(PDO::FETCH_ASSOC);
+}
+
 function getRoutes()
 {
 	global $conn;
@@ -32,7 +47,8 @@
 	global $conn;
 	if ($routeNumber != "") {
 		$query = "Select distinct routes.route_id,routes.route_short_name,routes.route_long_name,service_id from routes  join trips on trips.route_id =
-routes.route_id join stop_times on stop_times.trip_id = trips.trip_id where route_short_name = :routeNumber order by route_short_name;";
+routes.route_id join stop_times on stop_times.trip_id = trips.trip_id
+where route_short_name = :routeNumber OR route_short_name LIKE :routeNumber2 order by route_short_name;";
 	}
 	else {
 		$query = "SELECT DISTINCT route_short_name from routes order by route_short_name";
@@ -41,6 +57,8 @@
 	$query = $conn->prepare($query);
 	if ($routeNumber != "") {
 		$query->bindParam(":routeNumber", $routeNumber);
+                $routeNumber2 = "% ".$routeNumber;
+		$query->bindParam(":routeNumber2", $routeNumber2);
 	}
 	$query->execute();
 	if (!$query) {

--- a/include/db/servicealert-dao.inc.php
+++ b/include/db/servicealert-dao.inc.php
@@ -1,10 +1,10 @@
 <?php
-function getServiceOverride() {
+function getServiceOverride($date="") {
 	global $conn;
 	$query = "Select * from calendar_dates where date = :date and exception_type = '1' LIMIT 1";
 	 debug($query,"database");
 	$query = $conn->prepare($query); // Create a prepared statement
-	$query->bindParam(":date", date("Ymd"));
+	$query->bindParam(":date", date("Ymd",($date != "" ? $date : time())));
 	$query->execute();
 	if (!$query) {
 		databaseError($conn->errorInfo());

--- a/include/db/stop-dao.inc.php
+++ b/include/db/stop-dao.inc.php
@@ -13,12 +13,13 @@
 	}
 	return $query->fetch(PDO::FETCH_ASSOC);
 }
-function getStops($timingPointsOnly = false, $firstLetter = "")
+function getStops($timingPointsOnly = false, $firstLetter = "", $startsWith = "")
 {
 	global $conn;
 	$conditions = Array();
 	if ($timingPointsOnly) $conditions[] = "substr(stop_code,1,2) != 'Wj'";
 	if ($firstLetter != "") $conditions[] = "substr(stop_name,1,1) = :firstLetter";
+	if ($startsWith != "") $conditions[] = "stop_name like :startsWith";
 	$query = "Select * from stops";
 	if (sizeof($conditions) > 0) {
 		if (sizeof($conditions) > 1) {
@@ -31,6 +32,11 @@
 	$query.= " order by stop_name;";
 	$query = $conn->prepare($query);
         if ($firstLetter != "") $query->bindParam(":firstLetter", $firstLetter);
+        
+        if ($startsWith != "") {
+            $startsWith = $startsWith."%";
+            $query->bindParam(":startsWith", $startsWith);
+        }
 	$query->execute();
 	if (!$query) {
 		databaseError($conn->errorInfo());
@@ -72,6 +78,29 @@
 	}
 	return $query->fetchAll();
 }
+function getStopsByStopCode($stop_code,$startsWith = "")
+{
+	global $conn;
+	$query = "Select * from stops where stop_code = :stop_code OR stop_code LIKE :stop_code2";
+                if ($startsWith != "") $query .= " AND stop_name like :startsWith";
+
+	debug($query, "database");
+	$query = $conn->prepare($query);
+        
+	$query->bindParam(":stop_code", $stop_code);
+        $stop_code2 = $stop_code . "%";
+	$query->bindParam(":stop_code2", $stop_code2);
+ if ($startsWith != "") {
+            $startsWith = $startsWith."%";
+            $query->bindParam(":startsWith", $startsWith);
+        }
+	$query->execute();
+	if (!$query) {
+		databaseError($conn->errorInfo());
+		return Array();
+	}
+	return $query->fetchAll();
+}
 function getStopRoutes($stopID, $service_period)
 {
 	if ($service_period == "") $service_period = service_period();
@@ -90,9 +119,10 @@
 	}
 	return $query->fetchAll();
 }
-function getStopTrips($stopID, $service_period = "", $afterTime = "")
+function getStopTrips($stopID, $service_period = "", $afterTime = "", $limit = "")
 {
 	if ($service_period == "") $service_period = service_period();
+        	if ($limit != "") $limitSQL = " LIMIT :limit ";
 	global $conn;
 	if ($afterTime != "") {
 		$query = " SELECT stop_times.trip_id,stop_times.arrival_time,stop_times.stop_id,stop_sequence,service_id,trips.route_id,route_short_name,route_long_name, end_times.arrival_time as end_time
@@ -105,7 +135,7 @@
 AND stop_times.trip_id = end_times.trip_id
 AND service_id=:service_period
 AND end_times.arrival_time > :afterTime
-ORDER BY end_time";
+ORDER BY end_time $limitSQL";
 	}
 	else {
 		$query = "SELECT stop_times.trip_id,arrival_time,stop_times.stop_id,stop_sequence,service_id,trips.route_id,route_short_name,route_long_name
@@ -115,12 +145,13 @@
 join routes on trips.route_id = routes.route_id
 WHERE stop_times.stop_id = :stopID
 AND service_id=:service_period
-ORDER BY arrival_time";
+ORDER BY arrival_time $limitSQL";
 	}
 	debug($query, "database");
 	$query = $conn->prepare($query);
 	$query->bindParam(":service_period", $service_period);
 	$query->bindParam(":stopID", $stopID);
+        if ($limit != "") $query->bindParam(":limit", $limit);
         if ($afterTime != "") $query->bindParam(":afterTime", $afterTime);
 	$query->execute();
 	if (!$query) {

--- a/include/db/trip-dao.inc.php
+++ b/include/db/trip-dao.inc.php
@@ -144,7 +144,10 @@
 	// limit interpolation to between nearest actual points.
 	$prevTimePoint = getTripPreviousTimePoint($tripID, $stop_sequence);
 	$nextTimePoint = getTripNextTimePoint($tripID, $stop_sequence);
-	$range = "AND stop_sequence >= '{$prevTimePoint['stop_sequence']}' AND stop_sequence <= '{$nextTimePoint['stop_sequence']}'";
+	//echo " prev {$lowestDelta['stop_sequence']} next {$nextTimePoint['stop_sequence']} ";
+	$range = "";
+	if ($prevTimePoint != "") $range .= " AND stop_sequence >= '{$prevTimePoint['stop_sequence']}'";
+	if ($nextTimePoint != "") $range .= " AND stop_sequence <= '{$nextTimePoint['stop_sequence']}'";
 	foreach (getTimeInterpolatedTrip($tripID, $range) as $tripStop) {
 		if ($tripStop['stop_sequence'] == $stop_sequence) return $tripStop;
 	}

--- a/labs/myway_api.json.php
+++ b/labs/myway_api.json.php
@@ -17,6 +17,7 @@
 }*/
 //set POST variables
 $url = 'https://www.action.act.gov.au/ARTS/use_Funcs.asp';
+//$url = 'http://localhost/myway.htm';
 $field_mapping = Array(
 	"card_number" => "SRNO",
 	"DOBmonth" => "month",
@@ -75,7 +76,7 @@
 }
 
 if (!isset($return['error'])) {
-	include_once ('lib/simple_html_dom.php');
+	include_once ('../lib/simple_html_dom.php');
 	//print_r($pageHTML);
 	$page = str_get_html($pageHTML);
 	$pageAlerts = $page->find(".smartCardAlert");
@@ -101,8 +102,19 @@
 			foreach ($table->find("tr") as $tr) {
 				$tableColumnNum = 0;
 				foreach ($tr->find("td") as $td) {
-					if ($tableNum == 1) $return[$tableName[$tableNum]][$tableColumns[$tableColumnNum]] = cleanString($td->plaintext);
-					else $return[$tableName[$tableNum]][$tableRowNum][$tableColumns[$tableColumnNum]] = cleanString($td->plaintext);
+					if ($tableNum == 1) {
+						// first table has card/cardholder details
+						$return[$tableName[$tableNum]][$tableColumns[$tableColumnNum]] = cleanString($td->plaintext);
+					} else {
+						// second table has transactions
+						
+						if ($tableColumns[$tableColumnNum] == "TX Reference No / Type") {
+							$return[$tableName[$tableNum]][$tableRowNum]["TX Reference No"] = substr(cleanString($td->plaintext), 0,6);
+							$return[$tableName[$tableNum]][$tableRowNum]["TX Type"] = substr(cleanString($td->plaintext), 7);
+						} else {
+							$return[$tableName[$tableNum]][$tableRowNum][$tableColumns[$tableColumnNum]] = cleanString($td->plaintext);
+						}
+					}
 					//print_r($return);
 					$tableColumnNum++;
 				}

--- /dev/null
+++ b/labs/myway_timeliness_calculate.php
@@ -1,1 +1,131 @@
+<?php
+include ('../include/common.inc.php');
+include_header("MyWay Delta Calculate", "mywayDeltaCalc");
+function abssort($a, $b)
+{
+	if ($a['timeDiff'] == $b['timeDiff']) {
+		return 0;
+	}
+	return (abs($a['timeDiff']) < abs($b['timeDiff'])) ? -1 : 1;
+}
+//collect all observation not in delta
+$query = "select * from myway_observations INNER JOIN myway_stops
+ON myway_observations.myway_stop=myway_stops.myway_stop INNER JOIN myway_routes
+ON myway_observations.myway_route=myway_routes.myway_route
+ WHERE observation_id NOT IN
+(
+SELECT  observation_id
+FROM myway_timingdeltas
+)";
+debug($query, "database");
+$query = $conn->prepare($query);
+$query->execute();
+if (!$query) {
+	databaseError($conn->errorInfo());
+	return Array();
+}
+$uncalcdObservations = $query->fetchAll();
+//Display count
+echo "<h3>" . sizeof($uncalcdObservations) . " observations not yet processed</h2>";
+//foreach observation not in delta
+foreach ($uncalcdObservations as $obsv) {
+	//var_dump($obsv);
+	echo "<h3>Observation {$obsv['observation_id']}:</h1>
+<small>{$obsv['myway_stop']} @ {$obsv['time']} on {$obsv['myway_route']}</small><br>";
+	if ($obsv["stop_code"] == "") {
+		echo "error, stop '{$obsv['myway_stop']}' unknown";
+		continue;
+	}
+	if ($obsv["route_full_name"] == "") {
+		echo "error, route '{$obsv['myway_route']}' unknown";
+		continue;
+	}
+	//		:convert timestamp into time of day and date
+	$time = date("H:i:s", strtotime($obsv['time']));
+	$date = date("c", strtotime($obsv['time']));
+	$timing_period = service_period(strtotime($date));
+	$potentialStops = getStopsByStopCode($obsv["stop_code"], $obsv["stop_street"]);
+	//:get myway_stops records
+	//:search by starts with stopcode and starts with street if street is not null
+	//no result, skip and display error
+	if (sizeof($potentialStops) < 1) {
+		echo "error, potential stops for stopcode {$obsv["stop_code"]} street {$obsv["stop_street"]} unknown";
+		continue;
+	}
+	//print out stops
+	echo "Matched stops: ";
+	foreach ($potentialStops as $potentialStop) echo $potentialStop['stop_code'] . " ";
+	echo "<br>";
+	//:get myway_route record
+	//no result, skip and display error
+	//print out route
+	$potentialRoute = getRouteByFullName($obsv["route_full_name"]);
+	if ($potentialRoute["route_short_name"] == "") {
+		echo "error, route '{$obsv["route_full_name"]}' unknown";
+		continue;
+	}
+	echo "Matched route: {$potentialRoute['route_short_name']}{$potentialRoute['route_long_name']}<br>";
+	$timeDeltas = Array();
+	foreach ($potentialStops as $potentialStop) {
+		$stopRoutes = getStopRoutes($potentialStop['stop_id'], $timing_period);
+		$foundRoute = Array();
+		foreach ($stopRoutes as $stopRoute) {
+			//Check if this route stops at each stop
+			if ($stopRoute['route_short_name'] . $stopRoute['route_long_name'] == $obsv["route_full_name"]) {
+				echo "Matching route found at {$potentialStop['stop_code']}<br>";
+				$foundRoute = $stopRoute;
+				//if does get tripstoptimes for this route
+				$trips = getStopTrips($potentialStop['stop_id'], $timing_period, $time);
+				foreach ($trips as $trip) {
+					//echo $trip['route_id']." ".$stopRoute['route_id'].";";
+					if ($trip['route_id'] == $stopRoute['route_id']) {
+						$timedTrip = getTimeInterpolatedTripAtStop($trip['trip_id'], $trip['stop_sequence']);
+						$actual_time = strtotime($time);
+						$trip_time = strtotime($timedTrip['arrival_time']);
+						$timeDiff = $actual_time - $trip_time;
+						//work out time delta, put into array with index of delta
+						$timeDeltas[] = Array(
+							"timeDiff" => $timeDiff,
+							"stop_code" => $potentialStop['stop_code']
+						);
+						echo "Found trip at {$timedTrip['arrival_time']}, difference of " . round($timeDiff / 60, 2) . " minutes<br>";
+					}
+				}
+				break; // because have found route
+				
+			}
+		}
+		if (sizeof($foundRoute) < 1) {
+			//print out that stops/does not stop
+			echo "No matching routes found at {$potentialStop['stop_code']}<br>";
+		}
+	}
+	//   lowest delta is recorded delta
+	usort($timeDeltas, "abssort");
+	$lowestDelta = $timeDeltas[0]["timeDiff"];
+	if (sizeof($timeDeltas) != 0) {
+		echo "Lowest difference of " . round($lowestDelta / 60, 2) . " minutes will be recorded for this observation<br>";
+		$observation_id = $obsv['observation_id'];
+		$route_full_name = $obsv['route_full_name'];
+		$myway_route = $obsv['myway_stop'];
+		$stop_code = $timeDeltas[0]["stop_code"];
+		$stmt = $conn->prepare("insert into myway_timingdeltas (observation_id, route_full_name, myway_route, stop_code, timing_delta, time, date, timing_period)
+				      values (:observation_id, :route_full_name, :myway_route, :stop_code, :timing_delta, :time, :date, :timing_period)");
+		$stmt->bindParam(':observation_id', $observation_id);
+		$stmt->bindParam(':route_full_name', $route_full_name);
+		$stmt->bindParam(':myway_route', $myway_route);
+		$stmt->bindParam(':stop_code', $stop_code);
+		$stmt->bindParam(':timing_delta', $lowestDelta);
+		$stmt->bindParam(':time', $time);
+		$stmt->bindParam(':date', $date);
+		$stmt->bindParam(':timing_period', $timing_period);
+		// insert a record
+		$stmt->execute();
+		if ($stmt->rowCount() > 0) {
+			echo "Recorded.<br>";
+		}
+		var_dump($conn->errorInfo());
+	}
+	flush();
+}
 

--- /dev/null
+++ b/labs/myway_timeliness_reconcile.php
@@ -1,1 +1,132 @@
+<?php
+include ('../include/common.inc.php');
+foreach ($_REQUEST as $key => $value) {
+	if (strstr($key, "route") && !strstr($value, "Select")) {
+		$myway_route = str_replace("route", "", $key);
+		$route_full_name = $value;
+		$query = "update myway_routes set route_full_name = :route_full_name where myway_route = :myway_route";
+		debug($query, "database");
+		$query = $conn->prepare($query);
+		$query->bindParam(":myway_route", $myway_route);
+		$query->bindParam(":route_full_name", $route_full_name);
+		$query->execute();
+		die(print_r($conn->errorInfo() , true));
+	}
+	if (strstr($key, "myway_stop")) {
+		$myway_stop = $value;
+                $stop_code = $_REQUEST['stop_code'];
+                $stop_street = $_REQUEST['stop_street'];
+		$query = "update myway_stops set stop_code = :stop_code, stop_street = :stop_street where myway_stop = :myway_stop";
+		debug($query, "database");
+		$query = $conn->prepare($query);
+		$query->bindParam(":myway_stop", $myway_stop);
+		$query->bindParam(":stop_code", $stop_code);
+                		$query->bindParam(":stop_street", $stop_street);
+		$query->execute();
+		die(print_r($conn->errorInfo() , true));
+	}
+}
+include_header("MyWay Data Reconcile", "mywayTimeRec");
+// initialise
+$count = $conn->exec("insert into myway_stops
+                     select distinct myway_stop from myway_observations
+                     WHERE myway_stop NOT IN
+        (
+        SELECT  myway_stop
+        FROM    myway_stops
+        )");
+echo "$count new stops.<br>";
+if (!$count) {
+	print_r($conn->errorInfo());
+}
+$count = $conn->exec("insert into myway_routes select distinct myway_route from myway_observations
+                     WHERE myway_route NOT IN
+        (
+        SELECT  myway_route
+        FROM    myway_routes
+        )");
+echo "$count new routes.<br>";
+if (!$count) {
+	print_r($conn->errorInfo());
+}
+echo "<h2>Stops</h2>";
+/*stops
+ search start of name, display map and table nuimbered, two text boxes */
+$query = "Select * from myway_stops where stop_code is NULL and stop_street is NUll;";
+debug($query, "database");
+$query = $conn->prepare($query);
+$query->execute();
+if (!$query) {
+	databaseError($conn->errorInfo());
+	return Array();
+}
+foreach ($query->fetchAll() as $myway_stop) {
+	echo "<h3>{$myway_stop[0]}</h3>";
+	$stopNameParts = explode(" ", $myway_stop[0]);
+	$markers = array();
+	$stopKey = 1;
+	$foundStops = getStops(false, "", $stopNameParts[0] . " " . $stopNameParts[1]);
+	if (sizeof($foundStops) > 0) {
+		echo "<table>";
+		foreach ($foundStops as $stopResult) {
+			$markers[] = array(
+				$stopResult['stop_lat'],
+				$stopResult['stop_lon']
+			);
+			echo "<tr><td>" . $stopKey++ . "</td><td>" . $stopResult['stop_name'] . "</td><td>" . $stopResult['stop_code'] . "</td></tr>";
+		}
+		echo '</table>';
+		echo "" . staticmap($markers, 0, "icong", false) . "<br>\n";
+	}
+        echo '<form id="inputform' .md5($myway_stop[0]).'">
+        <input type="hidden" name="myway_stop" value="' .$myway_stop[0].'">
+        <div data-role="fieldcontain">
+        <label for="stop_code">Stop Code</label>
+        <input type="text" name="stop_code" id="stop_code" value="' . $foundStops[0]['stop_code'] . '"  />
+    </div>
+        <div data-role="fieldcontain">
+        <label for="stop_street">Stop Street </label>
+        <input type="text" name="stop_street" id="stop_street" value="' . $foundStops[0]['stop_name'] . '"  />
+    </div>         <input type="button" onclick="$.post(\'myway_timeliness_reconcile.php\', $(\'#inputform' .md5($myway_stop[0]) . '\').serialize())" value="Go!"></form>
+';
+	echo '<hr>';
+}
+echo '<h2>Routes</h2>';
+/*routes
+ remove alpha char, search present dropdown*/
+$query = "Select * from myway_routes where route_full_name is NUll;";
+debug($query, "database");
+$query = $conn->prepare($query);
+$query->execute();
+if (!$query) {
+	databaseError($conn->errorInfo());
+	return Array();
+}
+foreach ($query->fetchAll() as $myway_route) {
+	echo "<h3>{$myway_route[0]}</h3>";
+	$query = "Select * from myway_observations where myway_route = :route order by time";
+	debug($query, "database");
+	$query = $conn->prepare($query);
+	$query->bindParam(":route", $myway_route[0]);
+	$query->execute();
+	if (!$query) {
+		databaseError($conn->errorInfo());
+		return Array();
+	}
+	foreach ($query->fetchAll() as $myway_obvs) {
+		echo $myway_obvs['myway_stop'] . $myway_obvs['time'] . "<br>";
+	}
+	$searchRouteNo = preg_replace("/[A-Z]/", "", $myway_route[0]);
+	echo $searchRouteNo;
+	echo '<form id="inputform' . $myway_route[0] . '">
+<select name="route' . $myway_route[0] . '" onchange=\'$.post("myway_timeliness_reconcile.php", $("#inputform' . $myway_route[0] . '").serialize())\'>
+<option>Select a from/to pair...</option>';
+	foreach (getRoutesByNumber($searchRouteNo) as $routeResult) {
+		echo "<option value=\"{$routeResult['route_short_name']}{$routeResult['route_long_name']}\"> {$routeResult['route_short_name']}{$routeResult['route_long_name']} </option>\n";
+	}
+	echo "</select></form>";
+	echo '<hr>';
+}
+include_footer();
+?>
 

--- a/labs/mywaybalance.php
+++ b/labs/mywaybalance.php
@@ -1,7 +1,7 @@
 <?php
 include ('../include/common.inc.php');
 include_header("MyWay Balance", "mywayBalance", false, false, true);
-		echo '<div data-role="page"> 
+echo '<div data-role="page"> 
 	<div data-role="header" data-position="inline">
 	<a href="' . $_SERVER["HTTP_REFERER"] . '" data-icon="arrow-l" data-rel="back" class="ui-btn-left">Back</a> 
 		<h1>MyWay Balance</h1>
@@ -9,36 +9,60 @@
 	</div><!-- /header -->
         <a name="maincontent" id="maincontent"></a>
         <div data-role="content"> ';
-	
 $return = Array();
-function logout() {
+function logout()
+{
 	setcookie("card_number", "", time() - 60 * 60 * 24 * 100, "/");
 	setcookie("date", "", time() - 60 * 60 * 24 * 100, "/");
 	setcookie("secret_answer", "", time() - 60 * 60 * 24 * 100, "/");
+	setcookie("contribute_myway", "", time() - 60 * 60 * 24 * 100, "/");
 }
-function printBalance($cardNumber, $date, $pwrd)
+function printBalance($mywayResult)
 {
-	global $return;
-	$return = json_decode(getPage(curPageURL() . "/myway_api.json.php?card_number=$cardNumber&DOBday={$date[0]}&DOBmonth={$date[1]}&DOByear={$date[2]}&secret_answer=$pwrd") , true);
-	if (isset($return['error'])) {
+	if (isset($mywayResult['error'])) {
 		logout();
-		echo '<h3><font color="red">' . $return['error'][0] . "</font></h3>";
+		echo '<h3><font color="red">' . $mywayResult['error'][0] . "</font></h3>";
 	}
 	else {
-		echo "<h2>Balance: " . $return['myway_carddetails']['Card Balance'] . "</h2>";
+		echo "<h2>Balance: " . $mywayResult['myway_carddetails']['Card Balance'] . "</h2>";
 		echo '<ul data-role="listview" data-inset="true"><li data-role="list-divider"> Recent Transactions </li>';
-		$txCount=0;
-		foreach ($return['myway_transactions'] as $transaction) {
+		$txCount = 0;
+		foreach ($mywayResult['myway_transactions'] as $transaction) {
 			echo "<li>";
 			if ($transaction["Deduction Type"] == "DEFAULT") echo '<img src="css/images/warning.png" alt="Failed to tap off: " class="ui-li-icon">';
-			echo"<b>" . $transaction["Date / Time"] . "</b>";
-			echo "<br><small>" .$transaction["Route"] ." at " . $transaction["Stop Name"]. "<br>". $transaction["TX Reference No / Type"] . "</small>";
+			echo "<b>" . $transaction["Date / Time"] . "</b>";
+			echo "<br><small>" . $transaction["Route"] . " at " . $transaction["Stop Name"] . "<br>";
+			echo $transaction["TX Reference No"] . " " . $transaction["TX Type"] . "</small>";
 			echo '<p class="ui-li-aside">' . $transaction["TX Amount"] . '</p>';
 			echo "</li>";
 			$txCount++;
 			if ($txCount > 10) break;
 		}
 		echo "</ul>";
+	}
+}
+function recordMyWayObservations($mywayResult)
+{
+	global $conn;
+	if (!isset($mywayResult['error'])) {
+		$stmt = $conn->prepare("insert into myway_observations (observation_id, myway_stop, time, myway_route)
+				      values (:observation_id, :myway_stop, :time, :myway_route)");
+		$stmt->bindParam(':observation_id', $observation_hash);
+		$stmt->bindParam(':myway_stop', $myway_stop);
+		$stmt->bindParam(':time', $timestamp);
+		$stmt->bindParam(':myway_route', $myway_route);
+		// insert a record
+		$resultCount = 0;
+		foreach ($mywayResult['myway_transactions'] as $transaction) {
+			if ($transaction["Stop Name"] != "" && $transaction["Deduction Type"] != "DEFAULT") {
+			$observation_hash = md5($mywayResult['myway_carddetails']['MyWay Number'] . $transaction["TX Reference No"]);
+			$timestamp = date("c", strtotime($transaction["Date / Time"]));
+			$myway_stop = $transaction["Stop Name"];
+			$myway_route = $transaction["Route"];
+			if ($stmt->execute()) $resultCount++;
+			}
+		}
+		echo "<h3>Thanks for participating in the study! $resultCount transactions were recorded</h3>";
 	}
 }
 if (isset($_REQUEST['card_number']) && isset($_REQUEST['date']) && isset($_REQUEST['secret_answer'])) {
@@ -48,9 +72,12 @@
 	if ($_REQUEST['remember'] == "on") {
 		setcookie("card_number", $cardNumber, time() + 60 * 60 * 24 * 100, "/");
 		setcookie("date", $_REQUEST['date'], time() + 60 * 60 * 24 * 100, "/");
+		setcookie("contribute_myway", $_REQUEST['contribute_myway'], time() + 60 * 60 * 24 * 100, "/");
 		setcookie("secret_answer", $pwrd, time() + 60 * 60 * 24 * 100, "/");
 	}
-	printBalance($cardNumber, $date, $pwrd);
+	$mywayResult = json_decode(getPage(curPageURL() . "/myway_api.json.php?card_number=$cardNumber&DOBday={$date[0]}&DOBmonth={$date[1]}&DOByear={$date[2]}&secret_answer=$pwrd") , true);
+	if ($_REQUEST['contribute_myway'] == "on") recordMyWayObservations($mywayResult);
+	printBalance($mywayResult);
 }
 else if (isset($_REQUEST['logout'])) {
 	echo '<center><h3> Logged out of MyWay balance </h3><a href="/index.php">Back to main menu...</a><center>';
@@ -59,7 +86,9 @@
 	$cardNumber = $_COOKIE['card_number'];
 	$date = explode("/", $_COOKIE['date']);
 	$pwrd = $_COOKIE['secret_answer'];
-	printBalance($cardNumber, $date, $pwrd);
+	$mywayResult = json_decode(getPage(curPageURL() . "/myway_api.json.php?card_number=$cardNumber&DOBday={$date[0]}&DOBmonth={$date[1]}&DOByear={$date[2]}&secret_answer=$pwrd") , true);
+	if ($_COOKIE['contribute_myway'] == "on") recordMyWayObservations($mywayResult);
+	printBalance($mywayResult);
 }
 else {
 	$date = (isset($_REQUEST['date']) ? filter_var($_REQUEST['date'], FILTER_SANITIZE_STRING) : date("m/d/Y"));
@@ -80,6 +109,10 @@
         <label for="remember"> Remember these details? </label>
         <input type="checkbox" name="remember" id="remember"  checked="yes"  />
     </div>
+    <div data-role="fieldcontain">
+        <label for="contribute_myway">Contribute MyWay records to timeliness study? </label>
+        <input type="checkbox" name="contribute_myway" id="contribute_myway" checked="no"  />
+    </div>
         <input type="submit" value="Go!"></form>';
 }
 include_footer();