1/* GENERATED SOURCE. DO NOT MODIFY. */
2/*
3******************************************************************************
4* Copyright (C) 2007, International Business Machines Corporation and   *
5* others. All Rights Reserved.                                               *
6******************************************************************************
7*/
8
9package android.icu.impl.duration;
10
11import android.icu.impl.duration.impl.DataRecord.ETimeLimit;
12
13/**
14 * Represents an approximate duration in multiple TimeUnits.  Each unit,
15 * if set, has a count (which can be fractional and must be non-negative).
16 * In addition Period can either represent the duration as being into the past
17 * or future, and as being more or less than the defined value.
18 * <p>
19 * Use a PeriodFormatter to convert a Period to a String.
20 * <p>
21 * Periods are immutable.  Mutating operations return the new
22 * result leaving the original unchanged.
23 * <p>
24 * Example:<pre>
25 * Period p1 = Period.at(3, WEEK).and(2, DAY).inFuture();
26 * Period p2 = p1.and(12, HOUR);</pre>
27 * @hide Only a subset of ICU is exposed in Android
28 */
29public final class Period {
30  final byte timeLimit;
31  final boolean inFuture;
32  final int[] counts;
33
34  /**
35   * Constructs a Period representing a duration of
36   * count units extending into the past.
37   * @param count the number of units, must be non-negative
38   * @param unit the unit
39   * @return the new Period
40   */
41  public static Period at(float count, TimeUnit unit) {
42    checkCount(count);
43    return new Period(ETimeLimit.NOLIMIT, false, count, unit);
44  }
45
46  /**
47   * Constructs a Period representing a duration more than
48   * count units extending into the past.
49   * @param count the number of units. must be non-negative
50   * @param unit the unit
51   * @return the new Period
52   */
53  public static Period moreThan(float count, TimeUnit unit) {
54    checkCount(count);
55    return new Period(ETimeLimit.MT, false, count, unit);
56  }
57
58  /**
59   * Constructs a Period representing a duration
60   * less than count units extending into the past.
61   * @param count the number of units. must be non-negative
62   * @param unit the unit
63   * @return the new Period
64   */
65  public static Period lessThan(float count, TimeUnit unit) {
66    checkCount(count);
67    return new Period(ETimeLimit.LT, false, count, unit);
68  }
69
70  /**
71   * Set the given unit to have the given count.  Marks the
72   * unit as having been set.  This can be used to set
73   * multiple units, or to reset a unit to have a new count.
74   * This does <b>not</b> add the count to an existing count
75   * for this unit.
76   *
77   * @param count the number of units.  must be non-negative
78   * @param unit the unit
79   * @return the new Period
80   */
81  public Period and(float count, TimeUnit unit) {
82    checkCount(count);
83    return setTimeUnitValue(unit, count);
84  }
85
86  /**
87   * Mark the given unit as not being set.
88   *
89   * @param unit the unit to unset
90   * @return the new Period
91   */
92  public Period omit(TimeUnit unit) {
93    return setTimeUnitInternalValue(unit, 0);
94  }
95
96  /**
97   * Mark the duration as being at the defined duration.
98   *
99   * @return the new Period
100   */
101  public Period at() {
102    return setTimeLimit(ETimeLimit.NOLIMIT);
103  }
104
105  /**
106   * Mark the duration as being more than the defined duration.
107   *
108   * @return the new Period
109   */
110  public Period moreThan() {
111    return setTimeLimit(ETimeLimit.MT);
112  }
113
114  /**
115   * Mark the duration as being less than the defined duration.
116   *
117   * @return the new Period
118   */
119  public Period lessThan() {
120    return setTimeLimit(ETimeLimit.LT);
121  }
122
123  /**
124   * Mark the time as being in the future.
125   *
126   * @return the new Period
127   */
128  public Period inFuture() {
129    return setFuture(true);
130  }
131
132  /**
133   * Mark the duration as extending into the past.
134   *
135   * @return the new Period
136   */
137  public Period inPast() {
138    return setFuture(false);
139  }
140
141  /**
142   * Mark the duration as extending into the future if
143   * future is true, and into the past otherwise.
144   *
145   * @param future true if the time is in the future
146   * @return the new Period
147   */
148  public Period inFuture(boolean future) {
149    return setFuture(future);
150  }
151
152  /**
153   * Mark the duration as extending into the past if
154   * past is true, and into the future otherwise.
155   *
156   * @param past true if the time is in the past
157   * @return the new Period
158   */
159  public Period inPast(boolean past) {
160    return setFuture(!past);
161  }
162
163  /**
164   * Returns true if any unit is set.
165   * @return true if any unit is set
166   */
167  public boolean isSet() {
168    for (int i = 0; i < counts.length; ++i) {
169      if (counts[i] != 0) {
170        return true;
171      }
172    }
173    return false;
174  }
175
176  /**
177   * Returns true if the given unit is set.
178   * @param unit the unit to test
179   * @return true if the given unit is set.
180   */
181  public boolean isSet(TimeUnit unit) {
182    return counts[unit.ordinal] > 0;
183  }
184
185  /**
186   * Returns the count for the specified unit.  If the
187   * unit is not set, returns 0.
188   * @param unit the unit to test
189   * @return the count
190   */
191  public float getCount(TimeUnit unit) {
192    int ord = unit.ordinal;
193    if (counts[ord] == 0) {
194      return 0;
195    }
196    return (counts[ord] - 1)/1000f;
197  }
198
199  /**
200   * Returns true if this represents a
201   * duration into the future.
202   * @return true if this represents a
203   * duration into the future.
204   */
205  public boolean isInFuture() {
206    return inFuture;
207  }
208
209  /**
210   * Returns true if this represents a
211   * duration into the past
212   * @return true if this represents a
213   * duration into the past
214   */
215  public boolean isInPast  () {
216    return !inFuture;
217  }
218
219  /**
220   * Returns true if this represents a duration in
221   * excess of the defined duration.
222   * @return true if this represents a duration in
223   * excess of the defined duration.
224   */
225  public boolean isMoreThan() {
226    return timeLimit == ETimeLimit.MT;
227  }
228
229  /**
230   * Returns true if this represents a duration
231   * less than the defined duration.
232   * @return true if this represents a duration
233   * less than the defined duration.
234   */
235  public boolean isLessThan() {
236    return timeLimit == ETimeLimit.LT;
237  }
238
239  /**
240   * Returns true if rhs extends Period and
241   * the two Periods are equal.
242   * @param rhs the object to compare to
243   * @return true if rhs is a Period and is equal to this
244   */
245  public boolean equals(Object rhs) {
246    try {
247      return equals((Period)rhs);
248    }
249    catch (ClassCastException e) {
250      return false;
251    }
252  }
253
254  /**
255   * Returns true if the same units are defined with
256   * the same counts, both extend into the future or both into the
257   * past, and if the limits (at, more than, less than) are the same.
258   * Note that this means that a period of 1000ms and a period of 1sec
259   * will not compare equal.
260   *
261   * @param rhs the period to compare to
262   * @return true if the two periods are equal
263   */
264  public boolean equals(Period rhs) {
265    if (rhs != null &&
266        this.timeLimit == rhs.timeLimit &&
267        this.inFuture == rhs.inFuture) {
268      for (int i = 0; i < counts.length; ++i) {
269        if (counts[i] != rhs.counts[i]) {
270          return false;
271        }
272      }
273      return true;
274    }
275    return false;
276  }
277
278  /**
279   * Returns the hashCode.
280   * @return the hashCode
281   */
282  public int hashCode() {
283    int hc = (timeLimit << 1) | (inFuture ? 1 : 0);
284    for (int i = 0; i < counts.length; ++i) {
285      hc = (hc << 2) ^ counts[i];
286    }
287    return hc;
288  }
289
290  /**
291   * Private constructor used by static factory methods.
292   */
293  private Period(int limit, boolean future, float count, TimeUnit unit) {
294    this.timeLimit = (byte) limit;
295    this.inFuture = future;
296    this.counts = new int[TimeUnit.units.length];
297    this.counts[unit.ordinal] = (int)(count * 1000) + 1;
298  }
299
300  /**
301   * Package private constructor used by setters and factory.
302   */
303  Period(int timeLimit, boolean inFuture, int[] counts) {
304    this.timeLimit = (byte) timeLimit;
305    this.inFuture = inFuture;
306    this.counts = counts;
307  }
308
309  /**
310   * Set the unit's internal value, converting from float to int.
311   */
312  private Period setTimeUnitValue(TimeUnit unit, float value) {
313    if (value < 0) {
314      throw new IllegalArgumentException("value: " + value);
315    }
316    return setTimeUnitInternalValue(unit, (int)(value * 1000) + 1);
317  }
318
319  /**
320   * Sets the period to have the provided value, 1/1000 of the
321   * unit plus 1.  Thus unset values are '0', 1' is the set value '0',
322   * 2 is the set value '1/1000', 3 is the set value '2/1000' etc.
323   * @param p the period to change
324   * @param value the int value as described above.
325   * @eturn the new Period object.
326   */
327  private Period setTimeUnitInternalValue(TimeUnit unit, int value) {
328    int ord = unit.ordinal;
329    if (counts[ord] != value) {
330      int[] newCounts = new int[counts.length];
331      for (int i = 0; i < counts.length; ++i) {
332        newCounts[i] = counts[i];
333      }
334      newCounts[ord] = value;
335      return new Period(timeLimit, inFuture, newCounts);
336    }
337    return this;
338  }
339
340  /**
341   * Sets whether this defines a future time.
342   * @param future true if the time is in the future
343   * @return  the new Period
344   */
345  private Period setFuture(boolean future) {
346    if (this.inFuture != future) {
347      return new Period(timeLimit, future, counts);
348    }
349    return this;
350  }
351
352  /**
353   * Sets whether this is more than, less than, or
354   * 'about' the specified time.
355   * @param limit the kind of limit
356   * @return the new Period
357   */
358  private Period setTimeLimit(byte limit) {
359    if (this.timeLimit != limit) {
360      return new Period(limit, inFuture, counts);
361
362    }
363    return this;
364  }
365
366  /**
367   * Validate count.
368   */
369  private static void checkCount(float count) {
370    if (count < 0) {
371      throw new IllegalArgumentException("count (" + count +
372                                         ") cannot be negative");
373    }
374  }
375}
376