edd1b398a602afff7e23aa734d892ee5de6c8a1f
[frank.git] / prod / net / jaekl / frank / Schedule.java
1 package net.jaekl.frank;
2
3 import java.io.PrintWriter;
4 import java.text.DateFormat;
5 import java.text.MessageFormat;
6 import java.text.SimpleDateFormat;
7 import java.util.Date;
8 import java.util.Locale;
9 import java.util.TimeZone;
10
11 import net.jaekl.frank.octranspo.Route;
12 import net.jaekl.frank.octranspo.StopInfo;
13 import net.jaekl.frank.octranspo.Trip;
14
15 public class Schedule {
16         Locale m_locale;
17         FrankBundle m_bundle;
18         DateFormat m_hourMinFmt;
19         DateFormat m_hourMinSecFmt;
20         
21         public Schedule(Locale locale) {
22                 m_locale = locale;
23                 m_bundle = FrankBundle.getInst(locale);
24                 m_hourMinFmt = new SimpleDateFormat("hh:mma", locale);
25                 m_hourMinSecFmt = new SimpleDateFormat("hh:mm:ssa", locale);
26                 
27                 // We always display times in Ottawa (local) time, because that's the only 
28                 // time that makes sense for a user who wants to know when to catch a bus.
29                 // In the (unlikely?) event that our server is in a different timezone,
30                 // we need to explicitly specify the time zone that we want to use.
31                 TimeZone tz = TimeZone.getTimeZone("America/Toronto");
32                 m_hourMinFmt.setTimeZone(tz);
33                 m_hourMinSecFmt.setTimeZone(tz);
34         }
35         
36         String trans(String key) {
37                 return m_bundle.get(key);
38         }
39         
40         String mapUrl(double latitude, double longitude) {
41                 return "http://www.openstreetmap.org/?mlat=" + latitude + "&mlon=" + longitude + "&zoom=15";
42         }
43         
44         void writeStyle(PrintWriter pw) {
45                 pw.println("<STYLE>");
46                 pw.println("  body {background-color: #F0F0C0; font-size: 1.5em; }");
47                 pw.println("  #trips {border-collapse: collapse; font-size: 1.5em; }");
48                 pw.println("  #trips td, #trips th {border: 1px solid #600000; padding: 3px 3px 3px 3px; text-align: center;}");
49                 pw.println("  #trips th {background-color: #800000; color: #FFFFFF; }");
50                 pw.println("  #trips tr.ghost td {background-color: #C0C0C0;}");
51                 pw.println("</STYLE>");
52         }
53         
54         // Countdown timer that updates time remaining until each bus is expected.
55         void writeScript(PrintWriter pw, String remainArray, int remainCount) {
56                 String min = trans(FrankBundle.MINUTES);
57                 String sec = trans(FrankBundle.SECONDS);
58                 
59                 pw.println("<SCRIPT>");
60             pw.println("var start; var interval; var remain;");
61             pw.println("window.onload = function() { start = new Date(); interval = setInterval(\"Tick()\", 1000); remain = " + remainArray + "; }");
62             pw.println("function Tick() { ");
63             pw.println("  var now = new Date(); var delta = Math.floor((now.getTime() - start.getTime()) / 1000); ");
64             pw.println("  var secs = delta % 60; var mins = Math.floor(delta / 60);");
65             pw.println("  document.getElementById(\"elapsed\").innerHTML = mins + \"" + min + " \" + secs + \"" + sec + "\";");
66             pw.println("  for (var i = 0; i < " + remainCount + "; ++i) {");
67             pw.println("    var id = \"in_\" + i;");
68             pw.println("    var element = document.getElementById(id);");
69             pw.println("    var remain_delta = (remain[i] * 60) + 30 - delta;");
70             pw.println("    if (remain_delta <= 0) {");
71             pw.println("      element.innerHTML = \"----\";");
72             pw.println("    } else {");
73             pw.println("      element.innerHTML = (Math.floor(remain_delta / 60)) + \"" + trans(min) + "\";");
74             pw.println("    }");
75             pw.println("  }");
76             pw.println("}");
77             pw.println("</SCRIPT>");
78
79         }
80         
81         void writeHeader(PrintWriter pw, String title) {
82                 pw.println("<HTML>");
83                 pw.println("<HEAD>");
84                 pw.println("<TITLE>" + title + "</TITLE>");
85                 writeStyle(pw);
86                 pw.println("</HEAD>");
87         }
88         
89         void writePage(PrintWriter pw, StopInfo stopInfo)
90         {
91                 StringBuilder remainArray = new StringBuilder("[ ");
92                 int           remainCount = 0;
93                 
94                 String title = stopInfo.getDescr() + " (" + stopInfo.getStopNo() + ")";
95                 String min = trans(FrankBundle.MINUTES);
96                 
97                 writeHeader(pw, trans(FrankBundle.FRANK) + ": " + title);
98                 
99                 pw.println("<BODY>");
100                 pw.println("  <TABLE ID=\"trips\">");
101                 pw.println("    <TR><TH COLSPAN=\"5\">" + title + "</TH></TR>");
102                 pw.println("    <TR><TH>" +
103                         trans(FrankBundle.ROUTE) + 
104                                 "</TH><TH>" +
105                                 trans(FrankBundle.DESTINATION) +
106                                 "</TH><TH>" +
107                                 trans(FrankBundle.ETA) +
108                                 "</TH><TH>" +
109                                 trans(FrankBundle.REMAIN) +  
110                                 "</TH><TH>" +
111                                 trans(FrankBundle.GPS_READ) +
112                                 "</TH>");
113                 
114                 for (int routeIdx = 0; routeIdx < stopInfo.getNumRoutes(); ++routeIdx) {
115                         Route route = stopInfo.getRoute(routeIdx);
116                         for (int tripIdx = 0; tripIdx < route.getNumTrips(); ++tripIdx) {
117                                 Trip trip = route.getTrip(tripIdx);
118                                 boolean isGhost = ((-1) == trip.getAdjAge());
119                                 if (isGhost) {
120                                         // GPS is off.  This bus may not exist.
121                                         pw.println("    <TR CLASS=\"ghost\">");
122                                 } else {
123                                         pw.println("    <TR>");
124                                 }
125                                 pw.println("      <TD>" + route.getRouteNo() + "</TD>");
126                                 pw.println("      <TD>" + trip.getDest() + "</TD>");
127                                 pw.println("      <TD>" + m_hourMinFmt.format(trip.getETA()) + "</TD>");
128                                 
129                                 pw.println("      <TD><SPAN ID=\"in_" + remainCount + "\">"+ trip.getAdjTime()+min+"</SPAN></TD>");
130                                 if (remainCount > 0) {
131                                         remainArray.append(", ");
132                                 }
133                                 remainArray.append(trip.getAdjTime());
134                                 remainCount++;
135                                 
136                                 if (trip.getAdjAge() < 0) {
137                                         pw.println("      <TD>" + trans(FrankBundle.GPS_OFF) + "</TD>");
138                                 }
139                                 else {
140                                         pw.println("      <TD><A HREF=\"" + mapUrl(trip.getLatitude(), trip.getLongitude()) + 
141                                                            "\">" + m_hourMinSecFmt.format(trip.getGPSTime()) + "</A></TD>");
142                                 }
143                                 pw.println("    </TR>");
144                         }
145                 }
146                 
147                 pw.println("  </TABLE>");
148                 
149                 String dataCollectedFormat = trans(FrankBundle.DATA_COLLECTED);
150                 String dataCollected = MessageFormat.format(dataCollectedFormat, m_hourMinSecFmt.format(new Date()));
151                 pw.println("  <P>" + dataCollected + "</P>");
152                 
153                 remainArray.append(" ]");
154                 writeScript(pw, remainArray.toString(), remainCount);
155                 pw.println("</BODY></HTML>");
156         }
157 }