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    return super.equals(obj);
203  }
204
205  @Override
206  public String toString() {
207    return "Temporal unit:" + timeUnit + " value: " + value;
208  }
209
210  @Override
211  public ComparableQuantity<Time> add(Quantity<Time> that) {
212    if (getUnit().equals(that.getUnit())) {
213      return TimeQuantities.getQuantity(value + that.getValue().intValue(), timeUnit);
214    }
215    Quantity<Time> converted = that.to(getUnit());
216    return TimeQuantities.getQuantity(value + converted.getValue().intValue(), timeUnit);
217  }
218
219  @Override
220  public ComparableQuantity<Time> subtract(Quantity<Time> that) {
221    if (getUnit().equals(that.getUnit())) {
222      return TimeQuantities.getQuantity(value - that.getValue().intValue(), timeUnit);
223    }
224    Quantity<Time> converted = that.to(getUnit());
225    return TimeQuantities.getQuantity(value - converted.getValue().intValue(), timeUnit);
226  }
227
228  @Override
229  public ComparableQuantity<?> divide(Quantity<?> that) {
230    if (getUnit().equals(that.getUnit())) {
231      return TimeQuantities.getQuantity(value / that.getValue().intValue(), timeUnit);
232    }
233    Unit<?> divUnit = getUnit().divide(that.getUnit());
234    UnitConverter conv;
235    try {
236      conv = getUnit().getConverterToAny(divUnit);
237      return TimeQuantities.getQuantity(value / conv.convert(that.getValue()).intValue(), timeUnit);
238    } catch (UnconvertibleException e) {
239      // TODO Auto-generated catch block
240      e.printStackTrace();
241      return TimeQuantities.getQuantity(value / that.getValue().intValue(), timeUnit);
242    } catch (IncommensurableException e) {
243      // TODO Auto-generated catch block
244      e.printStackTrace();
245      return TimeQuantities.getQuantity(value / that.getValue().intValue(), timeUnit);
246    }
247  }
248
249  @Override
250  public ComparableQuantity<Time> divide(Number that) {
251    return TimeQuantities.getQuantity(value / that.intValue(), timeUnit);
252  }
253
254  @Override
255  public ComparableQuantity<?> multiply(Quantity<?> multiplier) {
256    if (getUnit().equals(multiplier.getUnit())) {
257      return TimeQuantities.getQuantity(value * multiplier.getValue().intValue(), timeUnit);
258    }
259    Unit<?> mulUnit = getUnit().multiply(multiplier.getUnit());
260    UnitConverter conv;
261    try {
262      conv = getUnit().getConverterToAny(mulUnit);
263      return TimeQuantities.getQuantity(value * conv.convert(multiplier.getValue()).intValue(), timeUnit);
264    } catch (UnconvertibleException e) {
265      // TODO Auto-generated catch block
266      e.printStackTrace();
267      return TimeQuantities.getQuantity(value * multiplier.getValue().intValue(), timeUnit);
268    } catch (IncommensurableException e) {
269      // TODO Auto-generated catch block
270      e.printStackTrace();
271      return TimeQuantities.getQuantity(value * multiplier.getValue().intValue(), timeUnit);
272    }
273  }
274
275  @Override
276  public ComparableQuantity<Time> multiply(Number multiplier) {
277    return TimeQuantities.getQuantity(value * multiplier.intValue(), timeUnit);
278  }
279
280  @Override
281  public ComparableQuantity<?> inverse() {
282    return TimeQuantities.getQuantity(1 / value, timeUnit);
283  }
284
285  @Override
286  public boolean isBig() {
287    return true; // Duration backed by BigDecimal/BigInteger
288  }
289
290  @Override
291  public BigDecimal decimalValue(Unit<Time> unit, MathContext ctx) throws ArithmeticException {
292    return BigDecimal.valueOf(value.doubleValue());
293  }
294
295  @Override
296  public double doubleValue(Unit<Time> unit) throws ArithmeticException {
297    return value.doubleValue();
298  }
299}