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
26import java.io.BufferedReader;
27import java.io.FileReader;
28import java.io.FileNotFoundException;
29import java.io.IOException;
30import java.util.ArrayList;
31import java.util.HashMap;
32import java.util.HashSet;
33import java.util.List;
34import java.util.Map;
35import java.util.Set;
36import 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 */
44class 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}
251