001/*
002 * Units of Measurement Reference Implementation
003 * Copyright (c) 2005-2018, Jean-Marie Dautelle, Werner Keil, Otavio Santana.
004 *
005 * All rights reserved.
006 *
007 * Redistribution and use in source and binary forms, with or without modification,
008 * are permitted provided that the following conditions are met:
009 *
010 * 1. Redistributions of source code must retain the above copyright notice,
011 *    this list of conditions and the following disclaimer.
012 *
013 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
014 *    and the following disclaimer in the documentation and/or other materials provided with the distribution.
015 *
016 * 3. Neither the name of JSR-385, Indriya nor the names of their contributors may be used to endorse or promote products
017 *    derived from this software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
020 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
021 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
022 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
023 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
026 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
028 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package tech.units.indriya.quantity.time;
031
032import static tech.units.indriya.unit.Units.DAY;
033import static tech.units.indriya.unit.Units.HOUR;
034import static tech.units.indriya.unit.Units.MINUTE;
035import static tech.units.indriya.unit.Units.SECOND;
036
037import java.math.BigDecimal;
038import java.time.Duration;
039import java.time.temporal.ChronoUnit;
040import java.time.temporal.TemporalAmount;
041import java.time.temporal.TemporalUnit;
042import java.util.Objects;
043
044import javax.measure.IncommensurableException;
045import javax.measure.Quantity;
046import javax.measure.UnconvertibleException;
047import javax.measure.Unit;
048import javax.measure.UnitConverter;
049import javax.measure.quantity.Frequency;
050import javax.measure.quantity.Time;
051
052import tech.units.indriya.AbstractQuantity;
053import tech.units.indriya.ComparableQuantity;
054import tech.units.indriya.quantity.Quantities;
055import tech.units.indriya.unit.Units;
056
057/**
058 * Class that represents {@link TemporalUnit} in Unit-API
059 * 
060 * @author keilw
061 * @since 1.0
062 */
063public final class TemporalQuantity extends AbstractQuantity<Time> {
064  /**
065     * 
066     */
067  private static final long serialVersionUID = 6835738653744691425L;
068
069  private final TemporalUnit timeUnit;
070  private final Integer value;
071  private final TemporalAmount amount;
072
073  /**
074   * creates the {@link TemporalQuantity} using {@link TemporalUnit} and {@link Integer}
075   * 
076   * @param timeUnit
077   *          - time to be used
078   * @param value
079   *          - value to be used
080   */
081  TemporalQuantity(Integer value, TemporalUnit timeUnit) {
082    super(toUnit(timeUnit));
083    this.timeUnit = timeUnit;
084    this.amount = Duration.of(value, timeUnit);
085    this.value = value;
086  }
087
088  /**
089   * creates the {@link TemporalQuantity} using {@link TemporalUnit} and {@link Integer}
090   * 
091   * @param value
092   *          - value to be used
093   * @param timeUnit
094   *          - time to be used
095   */
096  public static TemporalQuantity of(Integer number, TemporalUnit timeUnit) {
097    return new TemporalQuantity(Objects.requireNonNull(number), Objects.requireNonNull(timeUnit));
098  }
099
100  /**
101   * Creates a {@link TemporalQuantity} based a {@link Quantity<Time>} converted to {@link Units#SECOND}.
102   * 
103   * @param quantity
104   *          - quantity to be used
105   * @return the {@link TemporalQuantity} converted be quantity in seconds.
106   */
107  public static TemporalQuantity of(Quantity<Time> quantity) {
108    Quantity<Time> seconds = Objects.requireNonNull(quantity).to(SECOND);
109    return new TemporalQuantity(seconds.getValue().intValue(), ChronoUnit.SECONDS);
110  }
111
112  /**
113   * get to {@link TemporalAmount}
114   * 
115   * @return the TemporalAmount
116   */
117  public TemporalAmount getTemporalAmount() {
118    return amount;
119  }
120
121  /**
122   * get to {@link TemporalUnit}
123   * 
124   * @return the TemporalUnit
125   */
126  public TemporalUnit getTemporalUnit() {
127    return timeUnit;
128  }
129
130  /**
131   * get value expressed in {@link Integer}
132   * 
133   * @return the value
134   */
135  public Integer getValue() {
136    return value;
137  }
138
139  /**
140   * converts the {@link TemporalUnit} to {@link Unit}
141   * 
142   * @return the {@link TemporalQuantity#getTemporalUnit()} converted to Unit
143   */
144  public Unit<Time> toUnit() {
145    return toUnit(timeUnit);
146  }
147
148  /**
149   * Converts the {@link TemporalQuantity} to {@link Quantity<Time>}
150   * 
151   * @return this class converted to Quantity
152   */
153  public Quantity<Time> toQuantity() {
154    return Quantities.getQuantity(value, toUnit());
155  }
156
157  public TemporalQuantity to(TemporalUnit timeUnit) {
158    Quantity<Time> time = toQuantity().to(toUnit(timeUnit));
159    return new TemporalQuantity(time.getValue().intValue(), timeUnit);
160  }
161
162  private static Unit<Time> toUnit(TemporalUnit timeUnit) {
163    if (timeUnit instanceof ChronoUnit) {
164      ChronoUnit chronoUnit = (ChronoUnit) timeUnit;
165      switch (chronoUnit) {
166        case MICROS:
167          return TimeQuantities.MICROSECOND;
168        case MILLIS:
169          return TimeQuantities.MILLISECOND;
170        case NANOS:
171          return TimeQuantities.NANOSECOND;
172        case SECONDS:
173          return SECOND;
174        case MINUTES:
175          return MINUTE;
176        case HOURS:
177          return HOUR;
178        case DAYS:
179          return DAY;
180        default:
181          throw new IllegalArgumentException("TemporalQuantity only supports DAYS, HOURS, MICROS, MILLIS, MINUTES, NANOS, SECONDS ");
182      }
183    } else {
184      throw new IllegalArgumentException("TemporalQuantity only supports temporal units of type ChronoUnit");
185
186    }
187  }
188
189  @Override
190  public int hashCode() {
191    return Objects.hash(timeUnit, value);
192  }
193
194  @Override
195  public boolean equals(Object obj) {
196    if (this == obj) {
197      return true;
198    }
199    if (TemporalQuantity.class.isInstance(obj)) {
200      TemporalQuantity other = TemporalQuantity.class.cast(obj);
201      return Objects.equals(timeUnit, other.timeUnit) && Objects.equals(value, other.value);
202    }
203    if (obj instanceof Quantity<?>) {
204      Quantity<?> that = (Quantity<?>) obj;
205      return Objects.equals(getUnit(), that.getUnit()) && Equalizer.hasEquality(value, that.getValue());
206    }
207    return super.equals(obj);
208  }
209
210  @Override
211  public String toString() {
212    return "Temporal unit:" + timeUnit + " value: " + value;
213  }
214
215  @Override
216  public ComparableQuantity<Time> add(Quantity<Time> that) {
217    if (getUnit().equals(that.getUnit())) {
218      return TimeQuantities.getQuantity(value + that.getValue().intValue(), timeUnit);
219    }
220    Quantity<Time> converted = that.to(getUnit());
221    return TimeQuantities.getQuantity(value + converted.getValue().intValue(), timeUnit);
222  }
223
224  @Override
225  public ComparableQuantity<Time> subtract(Quantity<Time> that) {
226    if (getUnit().equals(that.getUnit())) {
227      return TimeQuantities.getQuantity(value - that.getValue().intValue(), timeUnit);
228    }
229    Quantity<Time> converted = that.to(getUnit());
230    return TimeQuantities.getQuantity(value - converted.getValue().intValue(), timeUnit);
231  }
232
233  @Override
234  public ComparableQuantity<?> divide(Quantity<?> that) {
235    if (getUnit().equals(that.getUnit())) {
236      return TimeQuantities.getQuantity(value / that.getValue().intValue(), timeUnit);
237    }
238    Unit<?> divUnit = getUnit().divide(that.getUnit());
239    UnitConverter conv;
240    try {
241      conv = getUnit().getConverterToAny(divUnit);
242      return TimeQuantities.getQuantity(value / conv.convert(that.getValue()).intValue(), timeUnit);
243    } catch (UnconvertibleException e) {
244      // TODO Auto-generated catch block
245      e.printStackTrace();
246      return TimeQuantities.getQuantity(value / that.getValue().intValue(), timeUnit);
247    } catch (IncommensurableException e) {
248      // TODO Auto-generated catch block
249      e.printStackTrace();
250      return TimeQuantities.getQuantity(value / that.getValue().intValue(), timeUnit);
251    }
252  }
253
254  @Override
255  public ComparableQuantity<Time> divide(Number that) {
256    return TimeQuantities.getQuantity(value / that.intValue(), timeUnit);
257  }
258
259  @Override
260  public ComparableQuantity<?> multiply(Quantity<?> multiplier) {
261    if (getUnit().equals(multiplier.getUnit())) {
262      return TimeQuantities.getQuantity(value * multiplier.getValue().intValue(), timeUnit);
263    }
264    Unit<?> mulUnit = getUnit().multiply(multiplier.getUnit());
265    UnitConverter conv;
266    try {
267      conv = getUnit().getConverterToAny(mulUnit);
268      return TimeQuantities.getQuantity(value * conv.convert(multiplier.getValue()).intValue(), timeUnit);
269    } catch (UnconvertibleException e) {
270      // TODO Auto-generated catch block
271      e.printStackTrace();
272      return TimeQuantities.getQuantity(value * multiplier.getValue().intValue(), timeUnit);
273    } catch (IncommensurableException e) {
274      // TODO Auto-generated catch block
275      e.printStackTrace();
276      return TimeQuantities.getQuantity(value * multiplier.getValue().intValue(), timeUnit);
277    }
278  }
279
280  @Override
281  public ComparableQuantity<Time> multiply(Number multiplier) {
282    return TimeQuantities.getQuantity(value * multiplier.intValue(), timeUnit);
283  }
284
285  @Override
286  public ComparableQuantity<Frequency> inverse() {
287    return Quantities.getQuantity(1d / value.doubleValue(), toUnit(timeUnit).inverse()).asType(Frequency.class);
288  }
289
290  @Override
291  public boolean isBig() {
292    return true; // Duration backed by BigDecimal/BigInteger
293  }
294
295  @Override
296  public BigDecimal decimalValue(Unit<Time> unit) throws ArithmeticException {
297    return BigDecimal.valueOf(value.doubleValue());
298  }
299
300  @Override
301  public double doubleValue(Unit<Time> unit) throws ArithmeticException {
302    return value.doubleValue();
303  }
304}