1 /*
   2  * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 import java.io.BufferedReader;
  27 import java.io.FileReader;
  28 import java.io.FileNotFoundException;
  29 import java.io.IOException;
  30 import java.util.ArrayList;
  31 import java.util.HashMap;
  32 import java.util.HashSet;
  33 import java.util.List;
  34 import java.util.Map;
  35 import java.util.Set;
  36 import java.util.StringTokenizer;
  37 
  38 /**
  39  * ZoneRec hold information of time zone corresponding to each text
  40  * line of the "Zone" part.
  41  *
  42  * @since 1.4
  43  */
  44 class ZoneRec {
  45     private int gmtOffset;
  46     private String ruleName;
  47     private int directSave;
  48     private Rule ruleRef;
  49     private String format;
  50     private boolean hasUntil;
  51     private int untilYear;
  52     private Month untilMonth;
  53     private RuleDay untilDay;
  54     private Time untilTime;
  55     private long untilInMillis;
  56     private String line;
  57 
  58     /**
  59      * @return the "UNTIL" value in milliseconds
  60      */
  61     Time getUntilTime() {
  62         return untilTime;
  63     }
  64 
  65     /**
  66      * @return the GMT offset value in milliseconds
  67      */
  68     int getGmtOffset() {
  69         return gmtOffset;
  70     }
  71 
  72     /**
  73      * @return the rule name to which this zone record refers
  74      */
  75     String getRuleName() {
  76         return ruleName;
  77     }
  78 
  79     /**
  80      * @return the amount of saving time directly defined in the
  81      * "RULES/SAVE" field.
  82      */
  83     int getDirectSave() {
  84         return directSave;
  85     }
  86 
  87     /**
  88      * @return true if this zone record has a reference to a rule
  89      */
  90     boolean hasRuleReference() {
  91         return ruleRef != null;
  92     }
  93 
  94     /**
  95      * Returns the "FORMAT" field string of this zone record. This
  96      * @return the "FORMAT" field
  97      */
  98     String getFormat() {
  99         return format;
 100     }
 101 
 102     /**
 103      * @return the year in the "UNTIL" field
 104      */
 105     int getUntilYear() {
 106         return untilYear;
 107     }
 108 
 109     /**
 110      * Returns the "UNTIL" field value in milliseconds from Janurary
 111      * 1, 1970 0:00 GMT.
 112      * @param currentSave the amount of daylight saving in
 113      * milliseconds that is used to adjust wall-clock time.
 114      * @return the milliseconds value of the "UNTIL" field
 115      */
 116     long getUntilTime(int currentSave) {
 117         if (untilTime.isWall()) {
 118             return untilInMillis - currentSave;
 119         }
 120         return untilInMillis;
 121     }
 122 
 123     /**
 124      * Returns the "UNTIL" time in milliseconds without adjusting GMT
 125      * offsets or daylight saving.
 126      * @return local "UNTIL" time in milliseconds
 127      */
 128     long getLocalUntilTime() {
 129         return Time.getLocalTime(untilYear,
 130                                  untilMonth,
 131                                  untilDay,
 132                                  untilTime.getTime());
 133     }
 134 
 135     /**
 136      * Returns the "UNTIL" time in milliseconds with adjusting GMT offsets and daylight saving.
 137      * @return the "UNTIL" time after the adjustment
 138      */
 139     long getLocalUntilTime(int save, int gmtOffset) {
 140         return Time.getLocalTime(untilYear,
 141                                  untilMonth,
 142                                  untilDay,
 143                                  save,
 144                                  gmtOffset,
 145                                  untilTime);
 146     }
 147 
 148     /**
 149      * @return the text line of this zone record
 150      */
 151     String getLine() {
 152         return line;
 153     }
 154 
 155     /**
 156      * Sets the specified text line to this zone record
 157      */
 158     void setLine(String line) {
 159         this.line = line;
 160     }
 161 
 162     /**
 163      * @return true if this zone record has the "UNTIL" field
 164      */
 165     boolean hasUntil() {
 166         return this.hasUntil;
 167     }
 168 
 169     /**
 170      * Adjusts the "UNTIL" time to GMT offset if this zone record has
 171      * it.  <code>untilTime</code> is not adjusted to daylight saving
 172      * in this method.
 173      */
 174     void adjustTime() {
 175         if (!hasUntil()) {
 176             return;
 177         }
 178         if (untilTime.isSTD() || untilTime.isWall()) {
 179             // adjust to gmt offset only here.  adjust to real
 180             // wall-clock time when tracking rules
 181             untilInMillis -= gmtOffset;
 182         }
 183     }
 184 
 185     /**
 186      * @return the reference to the Rule object
 187      */
 188     Rule getRuleRef() {
 189         return ruleRef;
 190     }
 191 
 192     /**
 193      * Resolves the reference to a Rule and adjusts its "UNTIL" time
 194      * to GMT offset.
 195      */
 196     void resolve(Zoneinfo zi) {
 197         if (ruleName != null && (!"-".equals(ruleName))) {
 198                 ruleRef = zi.getRule(ruleName);
 199         }
 200         adjustTime();
 201     }
 202 
 203     /**
 204      * Parses a Zone text line that is described by a StringTokenizer.
 205      * @param tokens represents tokens of a Zone text line
 206      * @return the zone record produced by parsing the text
 207      */
 208     static ZoneRec parse(StringTokenizer tokens) {
 209         ZoneRec rec = new ZoneRec();
 210         try {
 211             rec.gmtOffset = (int) Time.parse(tokens.nextToken()).getTime();
 212             String token = tokens.nextToken();
 213             char c = token.charAt(0);
 214             if (c >= '0' && c <= '9') {
 215                 rec.directSave = (int) Time.parse(token).getTime();
 216             } else {
 217                 rec.ruleName = token;
 218             }
 219             rec.format = tokens.nextToken();
 220             if (tokens.hasMoreTokens()) {
 221                 rec.hasUntil = true;
 222                 rec.untilYear = Integer.parseInt(tokens.nextToken());
 223                 if (tokens.hasMoreTokens()) {
 224                     rec.untilMonth = Month.parse(tokens.nextToken());
 225                 } else {
 226                     rec.untilMonth = Month.JANUARY;
 227                 }
 228                 if (tokens.hasMoreTokens()) {
 229                     rec.untilDay = RuleDay.parse(tokens.nextToken());
 230                 } else {
 231                     rec.untilDay = new RuleDay(1);
 232                 }
 233                 if (tokens.hasMoreTokens()) {
 234                     rec.untilTime = Time.parse(tokens.nextToken());
 235                 } else {
 236                     rec.untilTime = Time.parse("0:00");
 237                 }
 238                 rec.untilInMillis = rec.getLocalUntilTime();
 239             }
 240         } catch (Exception e) {
 241             // TODO: error reporting
 242             e.printStackTrace();
 243         }
 244         return rec;
 245     }
 246 
 247     private static void panic(String msg) {
 248         Main.panic(msg);
 249     }
 250 }