1 /*
   2  * Copyright (c) 2000, 2004, 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.util.StringTokenizer;
  27 
  28 /**
  29  * RuleRec class represents one record of the Rule set.
  30  *
  31  * @since 1.4
  32  */
  33 class RuleRec {
  34     private int fromYear;
  35     private int toYear;
  36     private String type;
  37     private Month inMonth;
  38     private RuleDay onDay;
  39     private Time atTime;
  40     private int save;
  41     private String letters;
  42     private String line;
  43     private boolean isLastRule;
  44 
  45     int getFromYear() {
  46         return fromYear;
  47     }
  48 
  49     int getToYear() {
  50         return toYear;
  51     }
  52 
  53     Month getMonth() {
  54         return inMonth;
  55     }
  56 
  57     int getMonthNum() {
  58         return inMonth.value();
  59     }
  60 
  61     RuleDay getDay() {
  62         return onDay;
  63     }
  64 
  65     Time getTime() {
  66         return atTime;
  67     }
  68 
  69     int getSave() {
  70         return save;
  71     }
  72 
  73     String getLine() {
  74         return line;
  75     }
  76 
  77     /**
  78      * Sets the line from the text file.
  79      * @param line the text of the line
  80      */
  81     void setLine(String line) {
  82         this.line = line;
  83     }
  84 
  85     /**
  86      * @return true if the rule type is "odd".
  87      */
  88     boolean isOdd() {
  89         return "odd".equals(type);
  90     }
  91 
  92     /**
  93      * @return true if the rule type is "even".
  94      */
  95     boolean isEven() {
  96         return "even".equals(type);
  97     }
  98 
  99     /**
 100      * Determines if this rule record is the last DST schedule rule.
 101      *
 102      * @return true if this rule record has "max" as TO (year).
 103      */
 104     boolean isLastRule() {
 105         return isLastRule;
 106     }
 107 
 108     /**
 109      * Determines if the unadjusted until time of the specified ZoneRec
 110      * is the same as the transition time of this rule in the same
 111      * year as the ZoneRec until year.
 112      *
 113      * @param zrec ZoneRec to compare to
 114      * @param save the amount of daylight saving in milliseconds
 115      * @param gmtOffset the GMT offset value in milliseconds
 116      * @return true if the unadjusted until time is the same as rule's
 117      * transition time.
 118      */
 119     boolean isSameTransition(ZoneRec zrec, int save, int gmtOffset) {
 120         long    until, transition;
 121 
 122         if (zrec.getUntilTime().getType() != atTime.getType()) {
 123             until = zrec.getLocalUntilTime(save, gmtOffset);
 124             transition = Time.getLocalTime(zrec.getUntilYear(),
 125                                            getMonth(),
 126                                            getDay(),
 127                                            save,
 128                                            gmtOffset,
 129                                            atTime);
 130         } else {
 131             until = zrec.getLocalUntilTime();
 132             transition = Time.getLocalTime(zrec.getUntilYear(),
 133                                            getMonth(),
 134                                            getDay(),
 135                                            atTime.getTime());
 136         }
 137 
 138         return until == transition;
 139     }
 140 
 141     /**
 142      * Parses a Rule line and returns a RuleRec object.
 143      *
 144      * @param tokens a StringTokenizer object that should contain a
 145      * token for the "FROM" field and the rest.
 146      * @return a RuleRec object.
 147      */
 148     static RuleRec parse(StringTokenizer tokens) {
 149         RuleRec rec = new RuleRec();
 150         try {
 151             // FROM
 152             String token = tokens.nextToken();
 153             try {
 154                 rec.fromYear = Integer.parseInt(token);
 155             } catch (NumberFormatException e) {
 156                 // it's not integer
 157                 if ("min".equals(token) || "minimum".equals(token)) {
 158                     rec.fromYear = Zoneinfo.getMinYear();
 159                 } else if ("max".equals(token) || "maximum".equals(token)) {
 160                     rec.fromYear = Zoneinfo.getMaxYear();
 161                 } else {
 162                     Main.panic("invalid year value: "+token);
 163                 }
 164             }
 165 
 166             // TO
 167             token = tokens.nextToken();
 168             rec.isLastRule = false;
 169             try {
 170                 rec.toYear = Integer.parseInt(token);
 171             } catch (NumberFormatException e) {
 172                 // it's not integer
 173                 if ("min".equals(token) || "minimum".equals(token)) {
 174                     rec.fromYear = Zoneinfo.getMinYear();
 175                 } else if ("max".equals(token) || "maximum".equals(token)) {
 176                     rec.toYear = Integer.MAX_VALUE;
 177                     rec.isLastRule = true;
 178                 } else if ("only".equals(token)) {
 179                     rec.toYear = rec.fromYear;
 180                 } else {
 181                     Main.panic("invalid year value: "+token);
 182                 }
 183             }
 184 
 185             // TYPE
 186             rec.type = tokens.nextToken();
 187 
 188             // IN
 189             rec.inMonth = Month.parse(tokens.nextToken());
 190 
 191             // ON
 192             rec.onDay = RuleDay.parse(tokens.nextToken());
 193 
 194             // AT
 195             rec.atTime = Time.parse(tokens.nextToken());
 196 
 197             // SAVE
 198             rec.save = (int) Time.parse(tokens.nextToken()).getTime();
 199 
 200             // LETTER/S
 201             rec.letters = tokens.nextToken();
 202         } catch (Exception e) {
 203             e.printStackTrace();
 204         }
 205         return rec;
 206     }
 207 
 208     /**
 209      * Calculates the transition time of the given year under this rule.
 210      * @param year the year value
 211      * @param gmtOffset the GMT offset value in milliseconds
 212      * @param save the amount of daylight save time
 213      * @return the transition time in milliseconds of the given year in UTC.
 214      */
 215     long getTransitionTime(int year, int gmtOffset, int save) {
 216         long time = Time.getLocalTime(year, getMonth(),
 217                                       getDay(), atTime.getTime());
 218         if (atTime.isSTD()) {
 219             time -= gmtOffset;
 220         } else if (atTime.isWall()) {
 221             time -= gmtOffset + save;
 222         }
 223         return time;
 224     }
 225 
 226     private static int getInt(StringTokenizer tokens) {
 227         String token = tokens.nextToken();
 228         return Integer.parseInt(token);
 229     }
 230 }