1 /* 2 * Copyright (c) 2000, 2018, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import java.util.ArrayList; 25 import java.util.Arrays; 26 import java.util.Comparator; 27 import java.util.List; 28 import java.util.StringTokenizer; 29 30 /** 31 * Rule manipulates Rule records. 32 * 33 * @since 1.4 34 */ 35 class Rule { 36 37 private List<RuleRec> list; 38 private String name; 39 40 /** 41 * Constructs a Rule which consists of a Rule record list. The 42 * specified name is given to this Rule. 43 * @param name the Rule name 44 */ 45 Rule(String name) { 46 this.name = name; 47 list = new ArrayList<RuleRec>(); 48 } 49 50 /** 51 * Added a RuleRec to the Rule record list. 52 */ 53 void add(RuleRec rec) { 54 list.add(rec); 55 } 56 57 /** 58 * @return the Rule name 59 */ 60 String getName() { 61 return name; 62 } 63 64 /** 65 * Gets all rule records that cover the given year. 66 * 67 * @param year the year number for which the rule is applicable. 68 * @return rules in List that are collated in time. If no rule is found, an empty 69 * List is returned. 70 */ 71 List<RuleRec> getRules(int year) { 72 List<RuleRec> rules = new ArrayList<RuleRec>(3); 73 for (RuleRec rec : list) { 74 if (year >= rec.getFromYear() && year <= rec.getToYear()) { 75 if ((rec.isOdd() && year % 2 == 0) || (rec.isEven() && year % 2 == 1)) 76 continue; 77 rules.add(rec); 78 } 79 } 80 int n = rules.size(); 81 if (n <= 1) { 82 return rules; 83 } 84 if (n == 2) { 85 RuleRec rec1 = rules.get(0); 86 RuleRec rec2 = rules.get(1); 87 if (rec1.getMonthNum() > rec2.getMonthNum()) { 88 rules.set(0, rec2); 89 rules.set(1, rec1); 90 } else if (rec1.getMonthNum() == rec2.getMonthNum()) { 91 // TODO: it's not accurate to ignore time types (STD, WALL, UTC) 92 long t1 = Time.getLocalTime(year, rec1.getMonth(), 93 rec1.getDay(), rec1.getTime().getTime()); 94 long t2 = Time.getLocalTime(year, rec2.getMonth(), 95 rec2.getDay(), rec2.getTime().getTime()); 96 if (t1 > t2) { 97 rules.set(0, rec2); 98 rules.set(1, rec1); 99 } 100 } 101 return rules; 102 } 103 104 final int y = year; 105 RuleRec[] recs = new RuleRec[rules.size()]; 106 rules.toArray(recs); 107 108 Arrays.sort(recs, new Comparator<RuleRec>() { 109 public int compare(RuleRec r1, RuleRec r2) { 110 int n = r1.getMonthNum() - r2.getMonthNum(); 111 if (n != 0) { 112 return n; 113 } 114 // TODO: it's not accurate to ignore time types (STD, WALL, UTC) 115 long t1 = Time.getLocalTime(y, r1.getMonth(), 116 r1.getDay(), r1.getTime().getTime()); 117 long t2 = Time.getLocalTime(y, r2.getMonth(), 118 r2.getDay(), r2.getTime().getTime()); 119 return Long.compare(t1, t2); 120 } 121 public boolean equals(Object o) { 122 return this == o; 123 } 124 }); 125 rules.clear(); 126 for (int i = 0; i < n; i++) { 127 if (i != 0 && recs[i -1].getSave() == recs[i].getSave()) { 128 // we have two recs back to back with same saving for the same year. 129 if (recs[i].isLastRule()) { 130 continue; 131 } else if (recs[i - 1].isLastRule()) { 132 rules.remove(rules.size() - 1); 133 } 134 } 135 rules.add(recs[i]); 136 } 137 return rules; 138 } 139 140 /** 141 * Gets rule records that have either "max" or cover the endYear 142 * value in its DST schedule. 143 * 144 * @return rules that contain last DST schedule. An empty 145 * ArrayList is returned if no last rules are found. 146 */ 147 List<RuleRec> getLastRules() { 148 RuleRec start = null; 149 RuleRec end = null; 150 151 for (int i = 0; i < list.size(); i++) { 152 RuleRec rec = list.get(i); 153 if (rec.isLastRule()) { 154 if (rec.getSave() > 0) { 155 start = rec; 156 } else { 157 end = rec; 158 } 159 } 160 } 161 if (start == null || end == null) { 162 int endYear = Zoneinfo.getEndYear(); 163 for (int i = 0; i < list.size(); i++) { 164 RuleRec rec = list.get(i); 165 if (endYear >= rec.getFromYear() && endYear <= rec.getToYear()) { 166 if (start == null && rec.getSave() > 0) { 167 start = rec; 168 } else { 169 if (end == null && rec.getSave() == 0) { 170 end = rec; 171 } 172 } 173 } 174 } 175 } 176 177 List<RuleRec> r = new ArrayList<RuleRec>(2); 178 if (start == null || end == null) { 179 if (start != null || end != null) { 180 Main.warning("found last rules for "+name+" inconsistent."); 181 } 182 return r; 183 } 184 185 r.add(start); 186 r.add(end); 187 return r; 188 } 189 }