Index: trunk/webapps/cptms/CameraDisplay.html
===================================================================
--- trunk/webapps/cptms/CameraDisplay.html	(revision 614)
+++ trunk/webapps/cptms/CameraDisplay.html	(revision 616)
@@ -1,5 +1,6 @@
 <html>
 <head>
-<title>UI Prototype - CPTMS Camera Display Controller</title>
+<meta charset="UTF-8">
+<title>CPTMS Camera Display Controller V1</title>
 <style>
 .toprow {
@@ -18,5 +19,69 @@
 }
 </style>
+<script  src="../common/js/fileutils.js"></script>
 <script>
+/* Camera Controller for CPTMS
+ * @author jdalbey   Apr 2020
+ */
+var kVDSstatusFile = "../dynamicdata/highway_status.json"; // dynamic json data file 
+var kCCTVfile = "data_layers/cctv_locations_D12.gjson"; // CCTV locations
+var vdsList;
+var cctvList;
+var routeCameras = {};  // for each route, a list of cameras on that route
+var cameraDict = {};    // for each cameraid, the associated nearVDS and locationName properties
+function init()
+{
+    loadJSON(kVDSstatusFile, function(response)
+    {
+        // Parse JSON string into list of VDS's
+        vdsList = JSON.parse(response);
+
+    });
+    loadJSON(kCCTVfile, function(response)
+    {
+        // Parse JSON string into list of cctv's
+        cctvList = JSON.parse(response);
+        cctvList.features.forEach(buildDict);
+        // Build the route dropdowns using routeCameras keys
+        for (var quadrant = 1; quadrant <= 4; quadrant++)
+        {
+            routecombo = document.getElementById("R"+quadrant)
+            removeOptions(routecombo);
+            routecombo.add(document.createElement('option')); // an empty entry
+            // Get all the routes and sort them
+            var routeList =  Object.keys(routeCameras);
+            routeList.sort()
+            // Add all the routes to the route dropdown box
+            for (var route of routeList)
+            {
+                opt1 = document.createElement('option')
+                opt1.text = opt1.value = route
+                routecombo.add(opt1);
+            }
+        }
+    });
+
+    // Start a timer to refresh the traffic colors every 30 seconds
+    var myTimer = setInterval(updateVDSlist, 30000);
+}
+
+// Build a lookup dictionary that maps route to camera id's
+function buildDict(cctvItem)
+{
+    id = cctvItem.id
+    route = id.substring(3,6); // extract 3 character route number
+    if (route in routeCameras)
+    {
+        routeCameras[route].push(id); // add the camera id to the list for the route
+    }
+    else
+    {
+        routeCameras[route] = [id]; // special case for first occurrence of route
+    }
+    // Add a camera's info to the cameraDict
+    cameraDict[id] = {'nearVDS':cctvItem.properties["nearVDS"],
+                      'locationName':cctvItem.properties["locationName"]}
+}
+
 /* When a route is selected from the combobox, filter the
    list of cameras for just those on that route. */
@@ -30,5 +95,6 @@
   fillOptions(currentRoute, cameraselect);
 }
-// Remove all the options from a combo box
+
+// Helper: Remove all the options from a combo box
 function removeOptions(selectbox)
 {
@@ -41,106 +107,141 @@
 
 // Fill the selectbox with items from the lookup table that match route
+// route param may be empty if the first item in the combo box was chosen
 function fillOptions(route,cameraselect)
 {
-  var cameracombo = document.getElementById(cameraselect)
-  items = lookup[route];  // grab cameras from lookup table
-  // Create a new select OPTION for each camera
-  for (idx = 0; idx < items.length; idx++)
+  // IF the route is not empty
+  if (route.length > 0)
   {
-    opt1 = document.createElement('option')
-    opt1.text = opt1.value = items[idx]
-    cameracombo.add(opt1);
-  }
-}
-// A dictionary that maps routes to cameras on that route
-var lookup = {
-"5":["SB 5 N/O MAGNOLIA AVE (S/O 91)","NB 5 HARBOR BLVD","NB 5 RTE 22","NB 5 GRAND AVE","SB 5 17TH ST (7TH)","NB 5 BAKE PKWY (LAKE FOREST)","SB 5 ENTERPRISE ST /12-405 (235)","NB 5 ORTEGA HWY","NB 5 JUNIPERO SERRA RD ","NB 5 CROWN VALLEY PKWY (MV)","NB 5 N/O LA PAZ RD (S/O ALICIA)","NB 5 OSO PKWY O/C (MV)","NB 5 N/O OSO PKWY","NB 5 LA PAZ RD ( MV)","NB 5 ALICIA PKWY ON ( MV)","NB 5 ALICIA PKWY","NB 5 EL TORO RD","NB 5 NO EL TORO RD (CARLOTA)","NB 5 ALTON PKWY","NB 5 JEFFREY RD","NB 5 YALE AVE","NB 5 CULVER DR","NB 5 JAMBOREE RD","NB 5 TUSTIN RANCH RD","NB 5 S/O NEWPORT AVE","SB 5 22 FWY","NB 5 STATE COLLEGE BLVD","SB 5 ORANGEWOOD AVE","NB 5 KATELLA AVE","NB 5 WEST ST","NB 5 LINCOLN AVE","NB 5 EUCLID AVE","NB 5 BROOKHURST ST","NB 5 GILBERT ST","NB 5 MAGNOLIA AVE","NB 5 N/O ORANGETHORPE BLVD","NB 5 ANAHEIM BL","NB 5 MANCHESTER AVE (S/O STANTON)","WB 91 GILBERT ST","NB 5 N/O BEACH BLVD","NB 5 AVERY PKWY","NB 5 N/O YALE AVE","NB 5 S/O REDHILL AVE","NB 5 S/O ARTESIA BLVD","NB 5 CHRISTIANITOS RD","NB 5 PRESIDIO DR ON","NB 5 AVENIDA PALIZADA ON","NB 5 VIA HERMOSA","NB 5 S/O AVENIDA VAQUERO ON","NB 5 CAMINO DE ESTRELLA ON","NB 5 STONEHILL DR (CAPISTRANO/STONEHILL)","NB 5 AVENIDA AEROPUERTO","NB 5 VALLE RD ON (SAN JUAN CREEK)","NB 5 S/O ORTEGA HWY (SAN JUAN CREEK)","NB 5 73 FWY (NO LOC DESC)"],
-"22":["EB 22 7TH ST","WB 22 BROOKHURST ST","WB 22 EUCLID ST","WB 22 HARBOR BLVD","WB 22 CITY DRIVE","WB 22 CAMBRIDGE ST","EB 22 GLASSELL ST","WB 22 MAIN ST","EB 22 MAGNOLIA ST","WB 22 MAGNOLIA ST","WB 22 BEACH BLVD","EB 22 KNOTT AVE","WB 22 KNOTT AVE","EB 22 VALLEY VIEW AVE","EB 22 LOS ALISOS ST"],
-"55":["SB 55 DEL MAR AVE","NB 55 4TH ST","NB 55 MCFADDEN AVE","NB 55 EDINGER AVE","NB 55 WARNER AVE ","SB 55 @RTE405","SB 55 RTE 22 ","NB 55 CHAPMAN AVE ","NB 55 WALNUT ST","NB 55 COLLINS AVE","NB 55 KATELLA AVE","NB 55 S/O MEATS AVE","NB 55 17TH ST","NB 55 WILSON ST","NB 55 DEL MAR AVE EXT","NB 55 RTE 73","NB 55 N/O BAKER ST"],
-"57":["NB 57 BALL ROAD","NB 57 KATELLA AVE","NB 57 LINCOLN AVE","NB 57 ORANGETHORPE AVE","NB 57 IMPERIAL HWY","NB 57 LAMBERT ST","NB 57 CHAPMAN AVE (ORANGE)","NB 57 ORANGEWOOD AVE ON","NB 57 N/O WAGNER AVE","NB 57 S/O MIRALOMA OC","NB 57 NUTWOOD ST","NB 57 YORBA LINDA BLVD","NB 57 BASTANCHURY RD U/C","NB 57 ROLLING HILLS RD U/C","NB 57 S/O OF TONNER CYN RD","NB 57 N/O OF TONNER CYN RD"],
-"73":["NB 73 MAINLINE S/O BIRCH ST OC","NB 73 MAINLINE N/O CAMPUS DR OC","NB 73 MAINLINE N/O REDHILL AVE OC","NB 73 MAINLINE N/O PASEO DE COLINAS UC","NB 73 MAINLINE N/O CROWN VALLEY PKWY UC","SB 73 MAINLINE N/O GREENFIELD DR UC","SB 73 MAINLINE S/O MOULTON PKWY UC","SB 73 MAINLINE N/O MOULTON PKWY UC","NB 73 MAINLINE N/O LA PAZ RD UC","SB 73 MAINLINE AT ALICIA PKWY OC",
-"SB 73 AT ALICIA CREEK RD","SB 73 MAINLINE S/O LAGUNA HILLS DR OC","SB 73 MAINLINE N/O LAGUNA HILLS DR OC","SB 73 MAINLINE AT GLENWOOD DR OC","NB 73 OFF-RAMP EL ORO RD","SB 73 MAINLINE N/O EL TORO RD UC","NB 73 CD N/O LAGUNA CYN RD UC","SB 73 MAINLINE N/O LAGUNA CYN RD UC","SB 73 MAINLINE N/O LAGUNA CYN RD UC","SB 73 MAINLINE S/O MAINLINE TOLL PLAZA","SB 73 MAINLINE MAINLINE TOLL PLAZA","SB 73 MAINLINE N/O MAINLINE TOLL PLAZA","SB 73 MAINLINE N/O MAINLINE TOLL PLAZA","SB 73 MAINLINE N/O NEWPORT COAST DR","SB 73 MAINLINE S/O NEWPORT COAST DR","SB 73 MAINLINE S/O NEWPORT COAST DR","NB 73 MAINLINE S/O BISON AVE OC","SB 73 MAINLINE S/O BISON AVE OC","NB 73 MAINLINE S/O UNIVERSITY DR UC","NB 73 MAINLINE JAMBOREE RD"],
-"91":["WB 91 BEACH BLVD","WB 91 FROM NB 57 FWY","EB 91 SCALE HOUSE","EB 91 BROOKHURST ST","EB 91 HARBOR BLVD","WB 91 W/O 57 FWY","EB 91 RAYMOND AVE","WB 91 STATE COLLEGE BLVD","WB 91 WEST / KRAEMER BLVD","WB 91 KRAEMER BLVD","EB 91 E/O GLASSELL ST","EB 91 EUCLID AVE","EB 91 LEMON ST","WB 91 MAGNOLIA ST","WB 91 STANTON AVE"],
-"133":["NB 133 MAINLINE S/O MARINE WAY UC","NB 133 MAINLINE S/O TRABUCO RD OC","NB 133 MAINLINE N/O TRABUCO RD OC","NB 133 	MAINLINE N/O IRVINE BLVD OC","NB 133 	MAINLINE S/O TOLL PLAZA"],
-"241":["NB 241 MAINLINE N/O ANTONIO PKWY OC","NB 241 MAINLINE 530M N/O ANTONIO PKWY UC","NB 241 MAINLINE N/O SANTA MARGARITA PKWY UC","NB 241 MAINLINE 30M S/O MELINDA ROAD UC","NB 241 MAINLINE 50M S/O EL TORO ROAD UC","NB 241 MAINLINE 80M S/O PORTOLA PKWY UC","NB 241 MAINLINE 40M S/O LAKE FOREST DRIVE UC","NB 241 MAINLINE 310M N/O BAKE PKWY OC","NB 241 MAINLINE 80M S/O ALTON PKWY OC","NB 241 MAINLINE 780M S/O PORTOLA PKWY OC","NB 241 MAINLINE 750M S/O BEE CANYON ROAD","NB 241 MAINLINE 50M S/O BEE CANYON ROAD","NB 241 MAINLINE 800M S/O HAUL ROAD","NB 241 MAINLINE 180M N/O HAUL ROAD","NB 241 MAINLINE 500M S/O SOUTH CULVER DR","NB 241 MAINLINE 400M N/O SOUTH CULVER DR","NB 241 MAINLINE 600M S/O NORTH CULVER DR","NB 241 MAINLINE 430M N/O NORTH CULVER DR","NB 241 MAINLINE 1400M N/O NORTH CULVER DR","NB 241 MAINLINE 230M S/O SANTIAGO CANYON ROAD OC","NB 241 MAINLINE 900M N/O SANTIAGO CANYON ROAD OC","NB 241 MAINLINE 1700M N/O SANTIAGO CANYON ROAD OC","NB 241 MAINLINE 2600M N/O SANTIAGO CANYON ROAD OC","NB 241 MAINLINE 2000M S/O WINDY RIDGE TOLL PLAZA","NB 241 MAINLINE 920M S/O WINDY RIDGE TOLL PLAZA","NB 241 MAINLINE 600M N/O WINDY RIDGE TOLL PLAZA","NB 241 MAINLINE 1200M N/O WINDY RIDGE TOLL PLAZA","NB 241 MAINLINE 2300M N/O WINDY RIDGE TOLL PLAZA","NB 241 MAINLINE 1100M S/O STATE ROUTE 91","EB 91 TO SB 241 CONNECTOR",
-"NB 241 TO EB 91 CONNECTOR","NB 241 MAINLINE 40M N/O PORTOLA PKWY"],
-"261":["SB 261 MAINLINE 200M S/O 5 ","NB 261 MAINLINE 100M S/O BRYAN AVE OC","NB 261 MAINLINE 70M S/O IRVINE BLVD OC","NB 261 MAINLINE 370M N/O IRVINE BLVD NB TOLL PLAZA","NB 261 MAINLINE 80M S/O PORTOLA PKWY (WEST) OC","NB 261 MAINLINE 940M N/O PORTOLA PKWY (WEST) OC","NB 261 MAINLINE 1900M N/O PORTOLA PKWY (WEST) OC","NB 261 MAINLINE 1500M S/O HANDY CREEK RD","NB 261 MAINLINE 290 M N/O HANDY CREEK RD"],
-"405":["SB 405 N/O BRISTOL ST","NB 405 SEAL BEACH BLVD","NB 405 S/O 605 ","NB 405 S/O EUCLID ST","NB 405 BROOKHURST ST","NB 405 WARNER AVE","NB 405 S/O NEWLAND ST","NB 405 GOLDENWEST AVE"],
-"605":["NB 605 S/O KATELLA AVE"]
-};
+      var cameracombo = document.getElementById(cameraselect)
+      // grab cameras from lookup table
+      cameranames = routeCameras[route];
+      //console.log(cameranames.length + " cameras for route " + route);
+      // Create a new select OPTION for each camera
+      for (var idx = 0; idx < cameranames.length; idx++)
+      {
+        var opt1 = document.createElement('option')
+        opt1.value = cameranames[idx]
+        opt1.text = cameraDict[cameranames[idx]].locationName
+        cameracombo.add(opt1);
+      }
+   } 
+}
+
+// Display the image requested from a camera dropdrown box
+function showView(cameraselect)
+{
+    var quadrant = cameraselect.charAt(1)  // extract numeric part of camera identifier
+    var imgElement = document.getElementById("img"+quadrant)    
+    var e = document.getElementById(cameraselect);
+    // if no camera was selected
+    if (e.selectedIndex == -1)
+    {
+        imgElement.src="" // remove the image
+    }
+    else
+    {
+        var chosenCamera = e.options[e.selectedIndex].value;
+        nearvds = cameraDict[chosenCamera].nearVDS
+        // Search for the vds that is nearest
+        var idx = 0; 
+        while (idx < vdsList.features.length && vdsList.features[idx].id != nearvds)
+        {
+            idx++;
+        }
+        // If we found the nearVDS
+        if (idx < vdsList.features.length)
+        {
+            // Obtain color and convert to speed
+            var foundVDS = vdsList.features[idx]
+            var color =  foundVDS.properties['color']
+            var speed = "freeflow"
+            if (color == "yellow")
+            {
+                speed = "slow"
+            }
+            if (color == "red")
+            {
+                speed = "stopped"
+            }
+            // construct filename
+            var filename =  chosenCamera + "-day-"+speed+".jpg"
+            //console.log("Found " + foundVDS.id + " " + foundVDS.properties['color'] + " " + filename)
+            // Load the desired image
+            var preload = new Image();
+            preload.onload = function() {
+                if (imgElement) 
+                { 
+                    imgElement.src = preload.src; // image
+                    imgElement.title=chosenCamera // tooltip
+                }
+            };
+            // if couldn't load show as unavailable
+            preload.onerror = function() {
+                if (imgElement) { imgElement.src = "images/CCTV/video_unavailable.jpg" }
+            };
+            // attempt to load the image
+            preload.src = "images/CCTV/"+filename;  
+    //Reference: https://www.daniweb.com/programming/web-development/threads/272293/javascript-test-for-file-existence
+        }
+    }
+}
+// Execute periodically to reload the vds list with current data
+function updateVDSlist()
+{
+    loadJSON(kVDSstatusFile, function(response)
+    {
+        // Reload the vds list with current data
+        vdsList = JSON.parse(response);
+        // Refresh each camera view
+        var views = document.getElementsByClassName("camcombo");
+        for (var quadrant of views)
+        {
+            showView(quadrant);
+        }
+    });
+    
+}
 </script>
 </head>
-<body>
-<div style="text-align: center">
+<body onload="init()">
+<div style="text-align: center; width:80%">
 CPTMS Camera Controller
 </div>
-<table>
+<table width="80%">
   <tr>
-    <td class="caption"><img src="images/CCTV/12-005-CCTV-0029-day-slow.jpg"/>
-  Choose Route
-  <select id="R1">
-    <option value="0"></option>
-    <option value="1">1</option>
-    <option value="2" selected>5</option>
-    <option value="3">73</option>
-    <option value="4">405</option>
-  </select>
-  Choose Camera
-  <select id="C1">
-    <option value="0"></option>
-    <option value="1" selected>SB 17th St</option>
-    <option value="2">NB 5 Ortega Hwy</option>
-    <option value="3">NB 5 Crown Valley Pkwy</option>
-    <option value="4">NB 5 Alicia Pkwy</option>
+    <td class="caption" width="50%"><img id="img1" src=""/><br>
+  Choose Route
+  <select id="R1" onchange='routechanged("R1","C1")'>
+    <option value="0"></option>
+  </select>
+  <br>Choose Camera
+  <select id="C1" class="camcombo" onchange='showView("C1")'>
   </select></td>
-    <td class="caption"><img src="images/CCTV/12-005-CCTV-0084-day-slow.jpg"/>
-  Choose Route
-  <select id="R2">
-    <option value="0"></option>
-    <option value="1">1</option>
-    <option value="2" selected>5</option>
-    <option value="3">73</option>
-    <option value="4">405</option>
-  </select>
-  Choose Camera
-  <select id="C2">
-    <option value="0"></option>
-    <option value="1">SB 17th St</option>
-    <option value="2" selected>NB 5 Ortega Hwy</option>
-    <option value="3">NB 5 Crown Valley Pkwy</option>
-    <option value="4">NB 5 Alicia Pkwy</option>
+    <td class="caption"><img  id="img2"src=""/><br>
+  Choose Route
+  <select id="R2" onchange='routechanged("R2","C2")'>
+    <option value="0"></option>
+  </select>
+  <br>Choose Camera
+  <select id="C2" class="camcombo" onchange='showView("C2")'>
   </select></td>
   </tr>
   <tr>
-    <td class="caption"><img src="images/CCTV/12-005-CCTV-0088-day-slow.jpg"/>
-  Choose Route
-  <select id="R3">
-    <option value="0"></option>
-    <option value="1">1</option>
-    <option value="2" selected>5</option>
-    <option value="3">73</option>
-    <option value="4">405</option>
-  </select>
-  Choose Camera
-  <select id="C3">
-    <option value="0"></option>
-    <option value="1">SB 17th St</option>
-    <option value="2">NB 5 Ortega Hwy</option>
-    <option value="3" selected>NB 5 Crown Valley Pkwy</option>
-    <option value="4">NB 5 Alicia Pkwy</option>
+    <td class="caption"><img id="img3" src=""/><br>
+  Choose Route
+  <select id="R3"  onchange='routechanged("R3","C3")'>
+    <option value="0"></option>
+  </select>
+  <br>Choose Camera
+  <select id="C3" class="camcombo" onchange='showView("C3")'>
   </select>
 </td>
-    <td class="caption">
+    <td class="caption"><img id="img4" src=""/><br>
   Choose Route
   <select id="R4" onchange='routechanged("R4","C4")'>
-    <option value="0" selected></option>
-    <option value="1">5</option>
-    <option value="2">22</option>
-    <option value="3">57</option>
-    <option value="4">73</option>
-  </select>
-  Choose Camera
-  <select id="C4">
-    <option value="0" selected></option>
+    <option value="0"></option>
+  </select>
+  <br>Choose Camera
+  <select id="C4" class="camcombo" onchange='showView("C4")'>
 </select>
 </td>
