001: /*
002: * Copyright 2001-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.tools.javazic;
027:
028: import java.io.BufferedReader;
029: import java.io.BufferedWriter;
030: import java.io.File;
031: import java.io.FileReader;
032: import java.io.FileWriter;
033: import java.io.IOException;
034: import java.util.ArrayList;
035: import java.util.Calendar;
036: import java.util.Date;
037: import java.util.HashMap;
038: import java.util.Iterator;
039: import java.util.LinkedList;
040: import java.util.List;
041: import java.util.Map;
042: import java.util.Set;
043: import java.util.SortedMap;
044: import java.util.StringTokenizer;
045: import java.util.TreeMap;
046: import java.util.TreeSet;
047: import sun.util.calendar.ZoneInfoFile;
048:
049: /**
050: * <code>GenDoc</code> is one of back-end classes of javazic, and generates
051: * index.html and other html files which prints the detailed time zone
052: * information for each zone.
053: */
054: class GenDoc extends BackEnd {
055:
056: private static final String docDir = "doc";
057:
058: private static final String header1 = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Frameset//EN\""
059: + "\"http://www.w3.org/TR/REC-html40/frameset.dtd\">\n"
060: + "<HTML>\n<HEAD>\n<!-- Generated by javazic on ";
061: private static final String header2 = "-->\n<TITLE>\n"
062: + "Java Platform, Standard Edition - TimeZone information based on ";
063: private static final String header3 = "-->\n<TITLE>\n"
064: + "Java Platform, Standard Edition TimeZone - ";
065: private static final String header4 = "</TITLE>\n" + "</HEAD>\n\n";
066:
067: private static final String body1 = "<BODY BGCOLOR=\"white\">\n";
068: private static final String body2 = "</BODY>\n";
069:
070: private static final String footer = "</HTML>\n";
071:
072: // list of time zone name and zonefile name/real time zone name
073: // e.g.
074: // key (String) : value (String)
075: // "America/Denver" : "America/Denver.html" (real time zone)
076: // "America/Shiprock" : "America/Denver" (alias)
077: TreeMap<String, String> timezoneList = new TreeMap<String, String>();
078:
079: // list of time zone's display name and time zone name
080: // e.g.
081: // key (String) : value (String)
082: // "Tokyo, Asia" : "Asia/Tokyo"
083: // "Marengo, Indiana, America" : "America/Indiana/Marengo"
084: // (aliases included)
085: TreeMap<String, String> displayNameList = new TreeMap<String, String>();
086:
087: // list of top level regions
088: // e.g.
089: // key (String) : value (String)
090: // "America" : "America.html"
091: // (including entries in America/Indiana/, America/Kentucky/, ...)
092: TreeMap<String, String> regionList = new TreeMap<String, String>();
093:
094: // mapping list from zone name to latitude & longitude
095: // This list is generated from zone.tab.
096: // e.g.
097: // key (String) : value (LatitudeAndLongitude object)
098: // "Asia/Tokyo" : latitude=35.3916, longitude=13.9444
099: // (aliases not included)
100: HashMap<String, LatitudeAndLongitude> mapList = null;
101:
102: // SortedMap of zone IDs sorted by their GMT offsets. If zone's GMT
103: // offset will change in the future, its last known offset is
104: // used.
105: SortedMap<Integer, Set<String>> zonesByOffset = new TreeMap<Integer, Set<String>>();
106:
107: /**
108: * Generates HTML document for each zone.
109: * @param Timezone
110: * @return 0 if no errors, or 1 if error occurred.
111: */
112: int processZoneinfo(Timezone tz) {
113: try {
114: int size;
115: int index;
116: String outputDir = Main.getOutputDir();
117: String zonename = tz.getName();
118: String zonefile = ZoneInfoFile.getFileName(zonename)
119: + ".html";
120: List<RuleRec> stz = tz.getLastRules();
121: timezoneList.put(zonename, zonefile);
122: displayNameList.put(transform(zonename), zonename);
123:
124: // Populate zonesByOffset. (Zones that will change their
125: // GMT offsets are also added to zonesByOffset here.)
126: int lastKnownOffset = tz.getRawOffset();
127: Set<String> set = zonesByOffset.get(lastKnownOffset);
128: if (set == null) {
129: set = new TreeSet<String>();
130: zonesByOffset.put(lastKnownOffset, set);
131: }
132: set.add(zonename);
133:
134: /* If outputDir doesn't end with file-separator, adds it. */
135: if (!outputDir.endsWith(File.separator)) {
136: outputDir += File.separatorChar;
137: }
138: outputDir += docDir + File.separatorChar;
139:
140: index = zonename.indexOf('/');
141: if (index != -1) {
142: regionList.put(zonename.substring(0, index), zonename
143: .substring(0, index)
144: + ".html");
145: }
146:
147: /* If zonefile includes file-separator, it's treated as part of
148: * pathname. And make directory if necessary.
149: */
150: index = zonefile.lastIndexOf('/');
151: if (index != -1) {
152: zonefile.replace('/', File.separatorChar);
153: outputDir += zonefile.substring(0, index + 1);
154: }
155: File outD = new File(outputDir);
156: outD.mkdirs();
157:
158: /* If mapfile is available, add a link to the appropriate map */
159: if ((mapList == null) && (Main.getMapFile() != null)) {
160: FileReader fr = new FileReader(Main.getMapFile());
161: BufferedReader in = new BufferedReader(fr);
162: mapList = new HashMap<String, LatitudeAndLongitude>();
163: String line;
164: while ((line = in.readLine()) != null) {
165: // skip blank and comment lines
166: if (line.length() == 0 || line.charAt(0) == '#') {
167: continue;
168: }
169: StringTokenizer tokens = new StringTokenizer(line);
170: String token = tokens.nextToken(); /* We don't use the first token. */
171: token = tokens.nextToken();
172: LatitudeAndLongitude location = new LatitudeAndLongitude(
173: token);
174: token = tokens.nextToken();
175: mapList.put(token, location);
176: }
177: in.close();
178: }
179:
180: /* Open zoneinfo file to write. */
181: FileWriter fw = new FileWriter(outputDir
182: + zonefile.substring(index + 1));
183: BufferedWriter out = new BufferedWriter(fw);
184:
185: out.write(header1 + new Date() + header3 + zonename
186: + header4);
187: out.write(body1 + "<FONT size=\"+2\"><B>" + zonename
188: + "</B></FONT>");
189: LatitudeAndLongitude location = (LatitudeAndLongitude) mapList
190: .get(zonename);
191: if (location != null) {
192: int deg, min, sec;
193:
194: deg = location.getLatDeg();
195: min = location.getLatMin();
196: sec = location.getLatSec();
197: if (deg < 0) {
198: min = -min;
199: sec = -sec;
200: } else if (min < 0) {
201: sec = -sec;
202: }
203: out
204: .write(" "
205: + "<A HREF=\"http://www.mapquest.com/maps/map.adp?"
206: + "latlongtype=degrees" + "&latdeg="
207: + deg + "&latmin=" + min + "&latsec="
208: + sec);
209:
210: deg = location.getLongDeg();
211: min = location.getLongMin();
212: sec = location.getLongSec();
213: if (deg < 0) {
214: min = -min;
215: sec = -sec;
216: } else if (min < 0) {
217: sec = -sec;
218: }
219: out.write("&longdeg=" + deg + "&longmin=" + min
220: + "&longsec=" + sec
221: + "\" target=\"_blank\">[map]</A>");
222: }
223: out.write("\n<P>\n");
224:
225: List<ZoneRec> zone = tz.getZones();
226: List<RuleRec> rule = tz.getRules();
227: if (rule != null && zone != null) {
228: out
229: .write("<TABLE BORDER=\"0\" WIDTH=\"100%\" CELLPADDING=\"1\" CELLSPACING=\"0\">\n"
230: + "<TR>\n"
231: + "<TD BGCOLOR=\"#EEEEFF\" WIDTH=\"50%\" ALIGN=\"CENTER\"><BR>"
232: + "<A HREF=\"#Rules\">Rules</A><BR></TD>\n"
233: + "<TD BGCOLOR=\"#EEEEFF\" WIDTH=\"50%\" ALIGN=\"CENTER\">"
234: + "<A HREF=\"#Zone\"><BR>Zone<BR></A></TD>\n"
235: + "</TR>\n</TABLE>\n");
236: }
237:
238: /* Output Rule records. */
239: if (rule != null) {
240: size = rule.size();
241: out
242: .write("<P>\n<A NAME=\"Rules\">"
243: + "<FONT SIZE=\"+1\"><B>Rules</B></FONT></A>\n"
244: + "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" CELLSPACING=\"0\">\n"
245: + "<TR BGCOLOR=\"#CCCCFF\">\n"
246: + "<TD>NAME</TD><TD>FROM</TD><TD>TO</TD><TD>TYPE</TD>"
247: + "<TD>IN</TD><TD>ON</TD><TD>AT</TD><TD>SAVE</TD>"
248: + "<TD>LETTER/S</TD><TD>NOTES</TD>\n</TR>\n");
249: for (int i = 0; i < size; i++) {
250: out.write("<TR BGCOLOR=\"#FFFFFF\">\n");
251: StringTokenizer st = new StringTokenizer(rule
252: .get(i).getLine());
253: String s;
254: if (st.hasMoreTokens()) { /* RULE - truncated */
255: st.nextToken();
256: }
257: if (st.hasMoreTokens()) { /* NAME */
258: out.write("<TD>" + st.nextToken() + "</TD>");
259: }
260: if (st.hasMoreTokens()) { /* FROM */
261: out.write("<TD>" + st.nextToken() + "</TD>");
262: }
263: if (st.hasMoreTokens()) { /* TO */
264: s = st.nextToken();
265: if (s.equals("min") || s.equals("max")) {
266: out.write("<TD><FONT COLOR=\"red\">" + s
267: + "</FONT></TD>");
268: } else {
269: out.write("<TD>" + s + "</TD>");
270: }
271: }
272: if (st.hasMoreTokens()) { /* TYPE */
273: out.write("<TD>" + st.nextToken() + "</TD>");
274: }
275: if (st.hasMoreTokens()) { /* IN */
276: out.write("<TD>" + st.nextToken() + "</TD>");
277: }
278: if (st.hasMoreTokens()) { /* ON */
279: out.write("<TD>" + st.nextToken() + "</TD>");
280: }
281: if (st.hasMoreTokens()) { /* AT */
282: out.write("<TD>" + st.nextToken() + "</TD>");
283: }
284: if (st.hasMoreTokens()) { /* SAVE */
285: out.write("<TD>" + st.nextToken() + "</TD>");
286: }
287: if (st.hasMoreTokens()) { /* LETTER/S */
288: out.write("<TD>" + st.nextToken() + "</TD>");
289: }
290: if (st.hasMoreTokens()) { /* NOTES */
291: s = st.nextToken();
292: while (st.hasMoreTokens()) {
293: s += " " + st.nextToken();
294: }
295: index = s.indexOf('#');
296: out.write("<TD>" + s.substring(index + 1)
297: + "</TD>\n");
298: } else {
299: out.write("<TD> </TD>\n");
300: }
301: out.write("</TR>\n");
302: }
303: out.write("</TABLE>\n<P> <P>\n");
304: }
305:
306: /* Output Zone records. */
307: if (zone != null) {
308: size = zone.size();
309: out
310: .write("<P>\n<A NAME=\"Zone\">"
311: + "<FONT SIZE=\"+1\"><B>Zone</B></FONT></A>\n"
312: + "<TABLE BORDER=\"1\" WIDTH=\"100%\" CELLPADDING=\"3\" CELLSPACING=\"0\">\n"
313: + "<TR BGCOLOR=\"#CCCCFF\">\n<TD>GMTOFF</TD>"
314: + "<TD>RULES</TD><TD>FORMAT</TD><TD>UNTIL</TD>"
315: + "<TD>NOTES</TD>\n</TR>\n");
316: for (int i = 0; i < size; i++) {
317: out.write("<TR>\n");
318: StringTokenizer st = new StringTokenizer(zone
319: .get(i).getLine());
320: String s = st.nextToken();
321: if (s.equals("Zone")) { /* NAME */
322: s = st.nextToken();
323: s = st.nextToken();
324: }
325: out.write("<TD>" + s + "</TD>"); /* GMTOFFSET */
326: if (st.hasMoreTokens()) { /* RULES */
327: out.write("<TD>" + st.nextToken() + "</TD>");
328: }
329: if (st.hasMoreTokens()) { /* FORMAT */
330: s = st.nextToken();
331: index = s.indexOf('#');
332: if (index != -1) {
333: if (index != 0) {
334: out.write("<TD>"
335: + s.substring(0, index - 1)
336: + "</TD>"); /* FORMAT */
337: s = s.substring(index + 1);
338: } else {
339: out.write("<TD> </TD>"); /* FORMAT */
340: }
341: while (st.hasMoreTokens()) {
342: s += " " + st.nextToken();
343: }
344: out.write("<TD> </TD>"); /* UNTIL */
345: out.write("<TD>" + s + "</TD>\n</TR>\n"); /* NOTES */
346: continue;
347: } else {
348: out.write("<TD>" + s + "</TD>"); /* FORMAT */
349: }
350: }
351:
352: if (st.hasMoreTokens()) { /* UNTIL */
353: s = st.nextToken();
354: while (st.hasMoreTokens()) {
355: s += " " + st.nextToken();
356: }
357: index = s.indexOf('#');
358: if (index != -1) {
359: if (index != 0) {
360: out.write("<TD>"
361: + s.substring(0, index - 1)
362: + "</TD>"); /* UNTIL */
363: } else {
364: out.write("<TD> </TD>"); /* UNTIL */
365: }
366: out.write("<TD>" + s.substring(index + 1)
367: + "</TD>\n"); /* NOTES */
368: } else {
369: out.write("<TD>" + s + "</TD>"); /* UNTIL */
370: out.write("<TD> </TD>\n"); /* NOTES */
371: }
372: } else {
373: out.write("<TD> </TD>"); /* UNTIL */
374: out.write("<TD> </TD>\n"); /* NOTES */
375: }
376: out.write("</TR>\n");
377: }
378: out.write("</TABLE>\n");
379: }
380: out.write(body2 + footer);
381:
382: out.close();
383: fw.close();
384: } catch (IOException e) {
385: Main.panic("IO error: " + e.getMessage());
386: return 1;
387: }
388:
389: return 0;
390: }
391:
392: /**
393: * Generates index.html and other top-level frame files.
394: * @param Mappings
395: * @return 0 if no errors, or 1 if error occurred.
396: */
397: int generateSrc(Mappings map) {
398: try {
399: int len;
400: Object o[];
401: String outputDir = Main.getOutputDir();
402: FileWriter fw1, fw2;
403: BufferedWriter out1, out2;
404:
405: /* Whether alias list exists or not. */
406: Map<String, String> a = map.getAliases();
407: if (a == null) {
408: Main.panic("Data not exist. (aliases)");
409: return 1;
410: }
411:
412: timezoneList.putAll(a);
413:
414: /* If outputDir doesn't end with file-separator, adds it. */
415: if (!outputDir.endsWith(File.separator)) {
416: outputDir += File.separatorChar;
417: }
418: outputDir += docDir + File.separatorChar;
419:
420: File outD = new File(outputDir);
421: outD.mkdirs();
422:
423: /* Creates index.html */
424: fw1 = new FileWriter(outputDir + "index.html", false);
425: out1 = new BufferedWriter(fw1);
426:
427: out1
428: .write(header1
429: + new Date()
430: + header2
431: + Main.getVersionName()
432: + header4
433: + "<FRAMESET cols=\"20%,80%\">\n"
434: + "<FRAMESET rows=\"30%,70%\">\n"
435: + "<FRAME src=\"overview-frame.html\" name=\"TimeZoneListFrame\">\n"
436: + "<FRAME src=\"allTimeZone-frame1.html\" name=\"allTimeZoneFrame\">\n"
437: + "</FRAMESET>"
438: + "<FRAME src=\"overview-summary.html\" name=\"rightFrame\">\n"
439: + "</FRAMESET>\n"
440: + "<NOFRAMES>\n"
441: + "<H2>\nFrame Alert\n</H2>\n\n"
442: + "<P>\n\n"
443: + "This document is designed to be viewed using the frames feature. If you see this\n"
444: + "message, you are using a non-frame-capable web client.\n"
445: + "<BR>\n"
446: + "Link to<A HREF=\"overview-summary.html\">Non-frame version.</A>\n"
447: + "</NOFRAMES>\n" + footer);
448:
449: out1.close();
450: fw1.close();
451:
452: /* Creates overview-frame.html */
453: fw1 = new FileWriter(outputDir + "overview-frame.html",
454: false);
455: out1 = new BufferedWriter(fw1);
456:
457: out1
458: .write(header1
459: + new Date()
460: + header2
461: + Main.getVersionName()
462: + header4
463: + body1
464: + "<TABLE BORDER=\"0\" WIDTH=\"100%\">\n<TR>\n"
465: + "<TD NOWRAP><FONT size=\"+1\">\n"
466: + "<B>Java<sup><font size=-2>TM</font></sup> Platform<br>Standard Ed.</B></FONT></TD>\n"
467: + "</TR>\n</TABLE>\n\n"
468: + "<TABLE BORDER=\"0\" WIDTH=\"100%\">\n<TR>\n<TD NOWRAP>"
469: + "<P>\n<FONT size=\"+1\">\nAll Time Zones Sorted By:</FONT>\n<BR>\n"
470: + " <A HREF=\"allTimeZone-frame1.html\" TARGET=\"allTimeZoneFrame\">GMT offsets</A></FONT>\n<BR>\n"
471: + " <A HREF=\"allTimeZone-frame2.html\" TARGET=\"allTimeZoneFrame\">Zone names</A></FONT>\n<BR>"
472: + " <A HREF=\"allTimeZone-frame3.html\" TARGET=\"allTimeZoneFrame\">City names</A></FONT>\n"
473: + "<P>\n<FONT size=\"+1\">\nContinents and Oceans</FONT>\n<BR>\n");
474:
475: for (String regionKey : regionList.keySet()) {
476: out1.write(" <A HREF=\""
477: + regionList.get(regionKey)
478: + "\" TARGET=\"allTimeZoneFrame\">" + regionKey
479: + "</A><BR>\n");
480:
481: fw2 = new FileWriter(outputDir
482: + regionList.get(regionKey), false);
483: out2 = new BufferedWriter(fw2);
484:
485: out2.write(header1 + new Date() + header3 + regionKey
486: + header4 + body1 + "<FONT size=\"+1\"><B>"
487: + regionKey
488: + "</B></FONT>\n<BR>\n<TABLE>\n<TR>\n<TD>");
489:
490: boolean found = false;
491: for (String timezoneKey : timezoneList.keySet()) {
492: int regionIndex = timezoneKey.indexOf('/');
493: if (regionIndex == -1
494: || !regionKey.equals(timezoneKey.substring(
495: 0, regionIndex))) {
496: if (found) {
497: break;
498: } else {
499: continue;
500: }
501: }
502:
503: found = true;
504: if (a.containsKey(timezoneKey)) {
505: Object realName = a.get(timezoneKey);
506: while (a.containsKey(realName)) {
507: realName = a.get(realName);
508: }
509: out2.write(timezoneKey + " (alias for "
510: + "<A HREF=\""
511: + timezoneList.get(realName)
512: + "\" TARGET=\"rightFrame\">"
513: + realName + "</A>)");
514: } else {
515: out2.write("<A HREF=\""
516: + timezoneList.get(timezoneKey)
517: + "\" TARGET=\"rightFrame\">"
518: + timezoneKey + "</A>");
519: }
520: out2.write("<BR>\n");
521: }
522: out2.write("</TD>\n</TR>\n</TABLE>\n" + body2 + footer);
523:
524: out2.close();
525: fw2.close();
526: }
527: out1
528: .write("</FONT></TD>\n</TR></TABLE>\n" + body2
529: + footer);
530:
531: out1.close();
532: fw1.close();
533:
534: /* Creates allTimeZone-frame1.html (Sorted by GMT offsets) */
535: fw1 = new FileWriter(outputDir + "allTimeZone-frame1.html",
536: false);
537: out1 = new BufferedWriter(fw1);
538:
539: out1
540: .write(header1
541: + new Date()
542: + header2
543: + Main.getVersionName()
544: + header4
545: + body1
546: + "<FONT size=\"+1\"><B>Sorted by GMT offsets</B></FONT>\n"
547: + "<BR>\n\n"
548: + "<TABLE BORDER=\"0\" WIDTH=\"100%\">\n"
549: + "<TR>\n<TD NOWRAP>\n");
550:
551: List<Integer> roi = map.getRawOffsetsIndex();
552: List<Set<String>> roit = map.getRawOffsetsIndexTable();
553:
554: int index = 0;
555: for (Integer offset : zonesByOffset.keySet()) {
556: int off = roi.get(index);
557: Set<String> perRO = zonesByOffset.get(offset);
558: if (offset == off) {
559: // Merge aliases into zonesByOffset
560: perRO.addAll(roit.get(index));
561: }
562: index++;
563:
564: for (String timezoneKey : perRO) {
565: out1.write("<TR>\n<TD><FONT SIZE=\"-1\">("
566: + Time.toGMTFormat(offset.toString())
567: + ")</FONT></TD>\n<TD>");
568:
569: if (a.containsKey(timezoneKey)) {
570: Object realName = a.get(timezoneKey);
571: while (a.containsKey(realName)) {
572: realName = a.get(realName);
573: }
574: out1.write(timezoneKey + " (alias for "
575: + "<A HREF=\""
576: + timezoneList.get(realName)
577: + "\" TARGET=\"rightFrame\">"
578: + realName + "</A>)");
579: } else {
580: out1.write("<A HREF=\""
581: + timezoneList.get(timezoneKey)
582: + "\" TARGET=\"rightFrame\">"
583: + timezoneKey + "</A>");
584: }
585: out1.write("</TD>\n</TR>\n");
586: }
587: }
588: out1.write("</FONT></TD>\n</TR>\n</TABLE>\n" + body2
589: + footer);
590:
591: out1.close();
592: fw1.close();
593:
594: /* Creates allTimeZone-frame2.html (Sorted by zone names) */
595: fw1 = new FileWriter(outputDir + "allTimeZone-frame2.html",
596: false);
597: out1 = new BufferedWriter(fw1);
598:
599: out1
600: .write(header1
601: + new Date()
602: + header2
603: + Main.getVersionName()
604: + header4
605: + body1
606: + "<FONT size=\"+1\"><B>Sorted by zone names</B></FONT>\n"
607: + "<BR>\n\n"
608: + "<TABLE BORDER=\"0\" WIDTH=\"100%\">\n"
609: + "<TR>\n<TD NOWRAP>\n");
610: o = timezoneList.keySet().toArray();
611: len = timezoneList.size();
612: for (int i = 0; i < len; i++) {
613: Object timezoneKey = o[i];
614: if (a.containsKey(timezoneKey)) {
615: Object realName = a.get(timezoneKey);
616: while (a.containsKey(realName)) {
617: realName = a.get(realName);
618: }
619: out1.write(timezoneKey + " (alias for "
620: + "<A HREF=\"" + timezoneList.get(realName)
621: + "\" TARGET=\"rightFrame\">" + realName
622: + "</A>)");
623: } else {
624: out1.write("<A HREF=\""
625: + timezoneList.get(timezoneKey)
626: + "\" TARGET=\"rightFrame\">" + timezoneKey
627: + "</A>");
628: }
629: out1.write("<BR> \n");
630: }
631: out1.write("</FONT></TD>\n</TR>\n</TABLE>\n" + body2
632: + footer);
633:
634: out1.close();
635: fw1.close();
636:
637: /* Creates allTimeZone-frame3.html (Sorted by city names) */
638: fw1 = new FileWriter(outputDir + "allTimeZone-frame3.html",
639: false);
640: out1 = new BufferedWriter(fw1);
641:
642: out1
643: .write(header1
644: + new Date()
645: + header2
646: + Main.getVersionName()
647: + header4
648: + body1
649: + "<FONT size=\"+1\"><B>Sorted by city names</B></FONT>\n"
650: + "<BR>\n\n"
651: + "<TABLE BORDER=\"0\" WIDTH=\"100%\">\n"
652: + "<TR>\n<TD NOWRAP>\n");
653:
654: Set aliasSet = a.keySet();
655: len = aliasSet.size();
656: Object aliasNames[] = aliasSet.toArray();
657: for (int i = 0; i < len; i++) {
658: displayNameList.put(transform((String) aliasNames[i]),
659: (String) aliasNames[i]);
660: }
661:
662: o = displayNameList.keySet().toArray();
663: len = displayNameList.size();
664: for (int i = 0; i < len; i++) {
665: Object displayName = o[i];
666: Object timezoneKey = displayNameList.get(o[i]);
667: if (a.containsKey(timezoneKey)) {
668: Object realName = a.get(timezoneKey);
669: while (a.containsKey(realName)) {
670: realName = a.get(realName);
671: }
672: out1.write(displayName + " (alias for "
673: + "<A HREF=\"" + timezoneList.get(realName)
674: + "\" TARGET=\"rightFrame\">" + realName
675: + "</A>)");
676: } else {
677: out1.write("<A HREF=\""
678: + timezoneList.get(timezoneKey)
679: + "\" TARGET=\"rightFrame\">" + displayName
680: + "</A>");
681: }
682: out1.write("<BR> \n");
683: }
684:
685: out1.write("</FONT></TD>\n</TR>\n</TABLE>\n" + body2
686: + footer);
687:
688: out1.close();
689: fw1.close();
690:
691: /* Creates overview-summary.html */
692: fw1 = new FileWriter(outputDir + "overview-summary.html",
693: false);
694: out1 = new BufferedWriter(fw1);
695:
696: out1
697: .write(header1
698: + new Date()
699: + header2
700: + Main.getVersionName()
701: + header4
702: + body1
703: + "<p>This is the list of time zones generated from <B>"
704: + Main.getVersionName()
705: + "</B> for Java Platform, "
706: + "Standard Edition. The source code can be obtained "
707: + "from ftp site <a href=\"ftp://elsie.nci.nih.gov/pub/\">"
708: + "ftp://elsie.nci.nih.gov/pub/</a>. A total of <B>"
709: + len
710: + "</B> time zones and aliases are supported "
711: + "in this edition. For the "
712: + "format of rules and zones, refer to the zic "
713: + "(zoneinfo compiler) man page on "
714: + "Solaris or Linux.</p>\n"
715: + "<p>Note that the time zone data is not "
716: + "a public interface of the Java Platform. No "
717: + "applications should rely on the time zone data of "
718: + "this document. Time zone names and data "
719: + "may change without any prior notice.</p>\n"
720: + body2 + footer);
721:
722: out1.close();
723: fw1.close();
724: } catch (IOException e) {
725: Main.panic("IO error: " + e.getMessage());
726: return 1;
727: }
728:
729: return 0;
730: }
731:
732: String transform(String s) {
733: int index = s.lastIndexOf("/");
734:
735: /* If the string doesn't include any delimiter, return */
736: if (index == -1) {
737: return s;
738: }
739:
740: int lastIndex = index;
741: String str = s.substring(index + 1);
742: do {
743: index = s.substring(0, lastIndex).lastIndexOf('/');
744: str += ", " + s.substring(index + 1, lastIndex);
745: lastIndex = index;
746: } while (index > -1);
747:
748: return str;
749: }
750:
751: static class LatitudeAndLongitude {
752:
753: private int latDeg, latMin, latSec, longDeg, longMin, longSec;
754:
755: LatitudeAndLongitude(String s) {
756: try {
757: // First of all, check the string has the correct format:
758: // either +-DDMM+-DDDMM or +-DDMMSS+-DDDMMSS
759:
760: if (!s.startsWith("+") && !s.startsWith("-")) {
761: Main.warning("Wrong latitude&longitude data: " + s);
762: return;
763: }
764: int index;
765: if (((index = s.lastIndexOf("+")) <= 0)
766: && ((index = s.lastIndexOf("-")) <= 0)) {
767: Main.warning("Wrong latitude&longitude data: " + s);
768: return;
769: }
770:
771: if (index == 5) {
772: latDeg = Integer.parseInt(s.substring(1, 3));
773: latMin = Integer.parseInt(s.substring(3, 5));
774: latSec = 0;
775: } else if (index == 7) {
776: latDeg = Integer.parseInt(s.substring(1, 3));
777: latMin = Integer.parseInt(s.substring(3, 5));
778: latSec = Integer.parseInt(s.substring(5, 7));
779: } else {
780: Main.warning("Wrong latitude&longitude data: " + s);
781: return;
782: }
783: if (s.startsWith("-")) {
784: latDeg = -latDeg;
785: latMin = -latMin;
786: latSec = -latSec;
787: }
788:
789: int len = s.length();
790: if (index == 5 && len == 11) {
791: longDeg = Integer.parseInt(s.substring(index + 1,
792: index + 4));
793: longMin = Integer.parseInt(s.substring(index + 4,
794: index + 6));
795: longSec = 0;
796: } else if (index == 7 && len == 15) {
797: longDeg = Integer.parseInt(s.substring(index + 1,
798: index + 4));
799: longMin = Integer.parseInt(s.substring(index + 4,
800: index + 6));
801: longSec = Integer.parseInt(s.substring(index + 6,
802: index + 8));
803: } else {
804: Main.warning("Wrong latitude&longitude data: " + s);
805: return;
806: }
807: if (s.charAt(index) == '-') {
808: longDeg = -longDeg;
809: longMin = -longMin;
810: longSec = -longSec;
811: }
812: } catch (Exception e) {
813: Main
814: .warning("LatitudeAndLongitude() Parse error: "
815: + s);
816: }
817: }
818:
819: int getLatDeg() {
820: return latDeg;
821: }
822:
823: int getLatMin() {
824: return latMin;
825: }
826:
827: int getLatSec() {
828: return latSec;
829: }
830:
831: int getLongDeg() {
832: return longDeg;
833: }
834:
835: int getLongMin() {
836: return longMin;
837: }
838:
839: int getLongSec() {
840: return longSec;
841: }
842: }
843: }
|