001/*
002 * Units of Measurement Implementation for Java SE
003 * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM.
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-363 nor the names of its 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 tec.uom.se.quantity.time;
031
032import static tec.uom.se.unit.Units.DAY;
033import static tec.uom.se.unit.Units.HOUR;
034import static tec.uom.se.unit.Units.MINUTE;
035import static tec.uom.se.unit.Units.SECOND;
036
037import java.util.Objects;
038import java.math.BigDecimal;
039import java.math.MathContext;
040import java.time.Duration;
041import java.time.temporal.ChronoUnit;
042import java.time.temporal.TemporalAmount;
043import java.time.temporal.TemporalUnit;
044
045import javax.measure.IncommensurableException;
046import javax.measure.Quantity;
047import javax.measure.UnconvertibleException;
048import javax.measure.Unit;
049import javax.measure.UnitConverter;
050import javax.measure.quantity.Time;
051
052import tec.uom.se.AbstractQuantity;
053import tec.uom.se.ComparableQuantity;
054import tec.uom.se.quantity.Quantities;
055
056/**
057 * Class that represents {@link TemporalUnit} in Unit-API
058 * 
059 * @author keilw
060 * @since 1.0
061 */
062public final class TemporalQuantity extends AbstractQuantity<Time> {
063  /**
064     * 
065     */
066  private static final long serialVersionUID = 6835738653744691425L;
067
068  private final TemporalUnit timeUnit;
069  private final Integer value;
070  private final TemporalAmount amount;
071
072  /**
073   * creates the {@link TemporalQuantity} using {@link TemporalUnit} and {@link Integer}
074   * 
075   * @param timeUnit
076   *          - time to be used
077   * @param value
078   *          - value to be used
079   */
080  TemporalQuantity(Integer value, TemporalUnit timeUnit) {
081    super(toUnit(timeUnit));
082    this.timeUnit = timeUnit;
083    this.amount = Duration.of(value, timeUnit);
084    this.value = value;
085  }
086
087  /**
088   * creates the {@link TemporalQuantity} using {@link TemporalUnit} and {@link Integer}
089   * 
090   * @param value
091   *          - value to be used
092   * @param timeUnit
093   *          - time to be used
094   */
095  public static TemporalQuantity of(Integer number, TemporalUnit timeUnit) {
096    return new TemporalQuantity(Objects.requireNonNull(number), Objects.requireNonNull(timeUnit));
097  }
098
099  /**
100   * Creates a {@link TemporalQuantity} based a {@link Quantity<Time>} converted to {@link Units#SECOND}.
101   * 
102   * @param quantity
103   *          - quantity to be used
104   * @return the {@link TemporalQuantity} converted be quantity in seconds.
105   */
106  public static TemporalQuantity of(Quantity<Time> quantity) {
107    Quantity<Time> seconds = Objects.requireNonNull(quantity).to(SECOND);
108    return new TemporalQuantity(seconds.getValue().intValue(), ChronoUnit.SECONDS);
109  }
110
111  /**
112   * get to {@link TemporalAmount}
113   * 
114   * @return the TemporalAmount
115   */
116  public TemporalAmount getTemporalAmount() {
117    return amount;
118  }
119
120  /**
121   * get to {@link TemporalUnit}
122   * 
123   * @return the TemporalUnit
124   */
125  public TemporalUnit getTemporalUnit() {
126    return timeUnit;
127  }
128
129  /**
130   * get value expressed in {@link Integer}
131   * 
132   * @return the value
133   */
134  public Integer getValue() {
135    return value;
136  }
137
138  /**
139   * converts the {@link TemporalUnit} to {@link Unit}
140   * 
141   * @return the {@link TemporalQuantity#getTemporalUnit()} converted to Unit
142   */
143  public Unit<Time> toUnit() {
144    return toUnit(timeUnit);
145  }
146
147  /**
148   * Converts the {@link TemporalQuantity} to {@link Quantity<Time>}
149   * 
150   * @return this class converted to Quantity
151   */
152  public Quantity<Time> toQuantity() {
153    return Quantities.getQuantity(value, toUnit());
154  }
155
156  public TemporalQuantity to(TemporalUnit timeUnit) {
157    Quantity<Time> time = toQuantity().to(toUnit(timeUnit));
158    return new TemporalQuantity(time.getValue().intValue(), timeUnit);
159  }
160
161  private static Unit<Time> toUnit(TemporalUnit timeUnit) {
162    if (timeUnit instanceof ChronoUnit) {
163      ChronoUnit chronoUnit = (ChronoUnit) timeUnit;
164      switch (chronoUnit) {
165        case MICROS:
166          return TimeQuantities.MICROSECOND;
167        case MILLIS:
168          return TimeQuantities.MILLISECOND;
169        case NANOS:
170          return TimeQuantities.NANOSECOND;
171        case SECONDS:
172          return SECOND;
173        case MINUTES:
174          return MINUTE;
175        case HOURS:
176          return HOUR;
177        case DAYS:
178          return DAY;
179        default:
180          throw new IllegalArgumentException("TemporalQuantity only supports DAYS, HOURS, MICROS, MILLIS, MINUTES, NANOS, SECONDS ");
181      }
182    } else {
183      throw new IllegalArgumentException("TemporalQuantity only supports temporal units of type ChronoUnit");
184
185    }
186  }
187
188  @Override
189  public int hashCode() {
190    return Objects.hash(timeUnit, value);
191  }
192
193  @Override
194  public boolean equals(Object obj) {
195    if (this == obj) {
196      return true;
197    }
198    if (TemporalQuantity.class.isInstance(obj)) {
199      TemporalQuantity other = TemporalQuantity.class.cast(obj);
200      return Objects.equals(timeUnit, other.timeUnit) && Objects.equals(value, other.value);
201    }
202    if (obj instanceof Quantity<?>) {
203      Quantity<?> that = (Quantity<?>) obj;
204      return Objects.equals(getUnit(), that.getUnit()) && Equalizer.hasEquality(value, that.getValue());
205    }
206    return super.equals(obj);
207  }
208
209  @Override
210  public String toString() {
211    return "Temporal unit:" + timeUnit + " value: " + value;
212  }
213
214  @Override
215  public ComparableQuantity<Time> add(Quantity<Time> that) {
216    if (getUnit().equals(that.getUnit())) {
217      return TimeQuantities.getQuantity(value + that.getValue().intValue(), timeUnit);
218    }
219    Quantity<Time> converted = that.to(getUnit());
220    return TimeQuantities.getQuantity(value + converted.getValue().intValue(), timeUnit);
221  }
222
223  @Override
224  public ComparableQuantity<Time> subtract(Quantity<Time> that) {
225    if (getUnit().equals(that.getUnit())) {
226      return TimeQuantities.getQuantity(value - that.getValue().intValue(), timeUnit);
227    }
228    Quantity<Time> converted = that.to(getUnit());
229    return TimeQuantities.getQuantity(value - converted.getValue().intValue(), timeUnit);
230  }
231
232  @Override
233  public ComparableQuantity<?> divide(Quantity<?> that) {
234    if (getUnit().equals(that.getUnit())) {
235      return TimeQuantities.getQuantity(value / that.getValue().intValue(), timeUnit);
236    }
237    Unit<?> divUnit = getUnit().divide(that.getUnit());
238    UnitConverter conv;
239    try {
240      conv = getUnit().getConverterToAny(divUnit);
241      return TimeQuantities.getQuantity(value / conv.convert(that.getValue()).intValue(), timeUnit);
242    } catch (UnconvertibleException e) {
243      // TODO Auto-generated catch block
244      e.printStackTrace();
245      return TimeQuantities.getQuantity(value / that.getValue().intValue(), timeUnit);
246    } catch (IncommensurableException e) {
247      // TODO Auto-generated catch block
248      e.printStackTrace();
249      return TimeQuantities.getQuantity(value / that.getValue().intValue(), timeUnit);
250    }
251  }
252
253  @Override
254  public ComparableQuantity<Time> divide(Number that) {
255    return TimeQuantities.getQuantity(value / that.intValue(), timeUnit);
256  }
257
258  @Override
259  public ComparableQuantity<?> multiply(Quantity<?> multiplier) {
260    if (getUnit().equals(multiplier.getUnit())) {
261      return TimeQuantities.getQuantity(value * multiplier.getValue().intValue(), timeUnit);
262    }
263    Unit<?> mulUnit = getUnit().multiply(multiplier.getUnit());
264    UnitConverter conv;
265    try {
266      conv = getUnit().getConverterToAny(mulUnit);
267      return TimeQuantities.getQuantity(value * conv.convert(multiplier.getValue()).intValue(), timeUnit);
268    } catch (UnconvertibleException e) {
269      // TODO Auto-generated catch block
270      e.printStackTrace();
271      return TimeQuantities.getQuantity(value * multiplier.getValue().intValue(), timeUnit);
272    } catch (IncommensurableException e) {
273      // TODO Auto-generated catch block
274      e.printStackTrace();
275      return TimeQuantities.getQuantity(value * multiplier.getValue().intValue(), timeUnit);
276    }
277  }
278
279  @Override
280  public ComparableQuantity<Time> multiply(Number multiplier) {
281    return TimeQuantities.getQuantity(value * multiplier.intValue(), timeUnit);
282  }
283
284  @Override
285  public ComparableQuantity<?> inverse() {
286    return TimeQuantities.getQuantity(1 / value, timeUnit);
287  }
288
289  @Override
290  public boolean isBig() {
291    return true; // Duration backed by BigDecimal/BigInteger
292  }
293
294  @Override
295  public BigDecimal decimalValue(Unit<Time> unit, MathContext ctx) throws ArithmeticException {
296    return BigDecimal.valueOf(value.doubleValue());
297  }
298
299  @Override
300  public double doubleValue(Unit<Time> unit) throws ArithmeticException {
301    return value.doubleValue();
302  }
303}