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.util.ArrayList; 27 import java.util.Arrays; 28 import java.util.Comparator; 29 import java.util.List; 30 import java.util.StringTokenizer; 31 32 /** 33 * Rule manipulates Rule records. 34 * 35 * @since 1.4 36 */ 37 class Rule { 38 39 private List<RuleRec> list; 40 private String name; 41 42 /** 43 * Constructs a Rule which consists of a Rule record list. The 44 * specified name is given to this Rule. 45 * @param name the Rule name 46 */ 47 Rule(String name) { 48 this.name = name; 49 list = new ArrayList<RuleRec>(); 50 } 51 52 /** 53 * Added a RuleRec to the Rule record list. 54 */ 55 void add(RuleRec rec) { 56 list.add(rec); 57 } 58 59 /** 60 * @return the Rule name 61 */ 62 String getName() { 63 return name; 64 } 65 66 /** 67 * Gets all rule records that cover the given year. 68 * 69 * @param year the year number for which the rule is applicable. 70 * @return rules in List that are collated in time. If no rule is found, an empty 71 * List is returned. 72 */ 73 List<RuleRec> getRules(int year) { 74 List<RuleRec> rules = new ArrayList<RuleRec>(3); 75 for (RuleRec rec : list) { 76 if (year >= rec.getFromYear() && year <= rec.getToYear()) { 77 if ((rec.isOdd() && year % 2 == 0) || (rec.isEven() && year % 2 == 1)) 78 continue; 79 rules.add(rec); 80 } 81 } 82 int n = rules.size(); 83 if (n <= 1) { 84 return rules; 85 } 86 if (n == 2) { 87 RuleRec rec1 = rules.get(0); 88 RuleRec rec2 = rules.get(1); 89 if (rec1.getMonthNum() > rec2.getMonthNum()) { 90 rules.set(0, rec2); 91 rules.set(1, rec1); 92 } else if (rec1.getMonthNum() == rec2.getMonthNum()) { 93 // TODO: it's not accurate to ignore time types (STD, WALL, UTC) 94 long t1 = Time.getLocalTime(year, rec1.getMonth(), 95 rec1.getDay(), rec1.getTime().getTime()); 96 long t2 = Time.getLocalTime(year, rec2.getMonth(), 97 rec2.getDay(), rec2.getTime().getTime()); 98 if (t1 > t2) { 99 rules.set(0, rec2); 100 rules.set(1, rec1); 101 } 102 } 103 return rules; 104 } 105 106 final int y = year; 107 RuleRec[] recs = new RuleRec[rules.size()]; 108 rules.toArray(recs); 109 110 Arrays.sort(recs, new Comparator<RuleRec>() { 111 public int compare(RuleRec r1, RuleRec r2) { 112 int n = r1.getMonthNum() - r2.getMonthNum(); 113 if (n != 0) { 114 return n; 115 } 116 // TODO: it's not accurate to ignore time types (STD, WALL, UTC) 117 long t1 = Time.getLocalTime(y, r1.getMonth(), 118 r1.getDay(), r1.getTime().getTime()); 119 long t2 = Time.getLocalTime(y, r2.getMonth(), 120 r2.getDay(), r2.getTime().getTime()); 121 return Long.compare(t1, t2); 122 } 123 public boolean equals(Object o) { 124 return this == o; 125 } 126 }); 127 rules.clear(); 128 for (int i = 0; i < n; i++) { 129 if (i != 0 && recs[i -1].getSave() == recs[i].getSave()) { 130 // we have two recs back to back with same saving for the same year. 131 if (recs[i].isLastRule()) { 132 continue; 133 } else if (recs[i - 1].isLastRule()) { 134 rules.remove(rules.size() - 1); 135 } 136 } 137 rules.add(recs[i]); 138 } 139 return rules; 140 } 141 142 /** 143 * Gets rule records that have either "max" or cover the endYear 144 * value in its DST schedule. 145 * 146 * @return rules that contain last DST schedule. An empty 147 * ArrayList is returned if no last rules are found. 148 */ 149 List<RuleRec> getLastRules() { 150 RuleRec start = null; 151 RuleRec end = null; 152 153 for (int i = 0; i < list.size(); i++) { 154 RuleRec rec = list.get(i); 155 if (rec.isLastRule()) { 156 if (rec.getSave() > 0) { 157 start = rec; 158 } else { 159 end = rec; 160 } 161 } 162 } 163 if (start == null || end == null) { 164 int endYear = Zoneinfo.getEndYear(); 165 for (int i = 0; i < list.size(); i++) { 166 RuleRec rec = list.get(i); 167 if (endYear >= rec.getFromYear() && endYear <= rec.getToYear()) { 168 if (start == null && rec.getSave() > 0) { 169 start = rec; 170 } else { 171 if (end == null && rec.getSave() == 0) { 172 end = rec; 173 } 174 } 175 } 176 } 177 } 178 179 List<RuleRec> r = new ArrayList<RuleRec>(2); 180 if (start == null || end == null) { 181 if (start != null || end != null) { 182 Main.warning("found last rules for "+name+" inconsistent."); 183 } 184 return r; 185 } 186 187 r.add(start); 188 r.add(end); 189 return r; 190 } 191 }