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;
031
032import java.math.BigDecimal;
033import java.util.Comparator;
034import java.util.Objects;
035
036import javax.measure.Quantity;
037import javax.measure.Unit;
038import javax.measure.UnitConverter;
039import javax.measure.format.QuantityFormat;
040import javax.measure.quantity.Dimensionless;
041
042import tech.units.indriya.format.SimpleQuantityFormat;
043import tech.units.indriya.format.SimpleUnitFormat;
044import tech.units.indriya.function.Calculus;
045import tech.units.indriya.quantity.Quantities;
046import tech.uom.lib.common.function.UnitSupplier;
047import tech.uom.lib.common.function.ValueSupplier;
048import tech.uom.lib.common.util.NaturalQuantityComparator;
049
050/**
051 * <p>
052 * This class represents the immutable result of a scalar measurement stated in a known unit.
053 * </p>
054 *
055 * <p>
056 * To avoid any loss of precision, known exact quantities (e.g. physical constants) should not be created from <code>double</code> constants but from
057 * their decimal representation.<br>
058 * <code>
059 *         public static final Quantity&lt;Velocity&gt; C = NumberQuantity.parse("299792458 m/s").asType(Velocity.class);
060 *         // Speed of Light (exact).
061 *    </code>
062 * </p>
063 * 
064 * <p>
065 * Quantities can be converted to different units.<br>
066 * <code>
067 *         Quantity&lt;Velocity&gt; milesPerHour = C.to(MILES_PER_HOUR); // Use double implementation (fast).
068 *         System.out.println(milesPerHour);
069 * 
070 *         &gt; 670616629.3843951 m/h
071 *     </code>
072 * </p>
073 * 
074 * <p>
075 * Applications may sub-class {@link AbstractQuantity} for particular quantity types.<br>
076 * <code>
077 *         // Quantity of type Mass based on double primitive types.<br>
078 * public class MassAmount extends AbstractQuantity&lt;Mass&gt; {<br>
079 * private final double kilograms; // Internal SI representation.<br>
080 * private Mass(double kg) { kilograms = kg; }<br>
081 * public static Mass of(double value, Unit&lt;Mass&gt; unit) {<br>
082 * return new Mass(unit.getConverterTo(SI.KILOGRAM).convert(value));<br>
083 * }<br>
084 * public Unit&lt;Mass&gt; getUnit() { return SI.KILOGRAM; }<br>
085 * public Double getValue() { return kilograms; }<br>
086 * ...<br>
087 * }<br>
088 * <p>
089 * // Complex numbers measurements.<br>
090 * public class ComplexQuantity
091 * &lt;Q extends Quantity&gt;extends AbstractQuantity
092 * &lt;Q&gt;{<br>
093 * public Complex getValue() { ... } // Assuming Complex is a Number.<br>
094 * ...<br>
095 * }<br>
096 * <br>
097 * // Specializations of complex numbers quantities.<br>
098 * public final class Current extends ComplexQuantity&lt;ElectricCurrent&gt; {...}<br>
099 * public final class Tension extends ComplexQuantity&lt;ElectricPotential&gt; {...} <br>
100 * </code>
101 * </p>
102 * 
103 * <p>
104 * All instances of this class shall be immutable.
105 * </p>
106 *
107 * @author <a href="mailto:werner@uom.technology">Werner Keil</a>
108 * @version 1.4, July 4, 2018
109 * @since 1.0
110 */
111@SuppressWarnings("unchecked")
112public abstract class AbstractQuantity<Q extends Quantity<Q>> implements ComparableQuantity<Q>, UnitSupplier<Q>, ValueSupplier<Number> {
113
114  /**
115    * 
116    */
117  private static final long serialVersionUID = 293852425369811882L;
118
119  private final Unit<Q> unit;
120
121  /**
122   * Holds a dimensionless quantity of none (exact).
123   */
124  public static final Quantity<Dimensionless> NONE = Quantities.getQuantity(0, AbstractUnit.ONE);
125
126  /**
127   * Holds a dimensionless quantity of one (exact).
128   */
129  public static final Quantity<Dimensionless> ONE = Quantities.getQuantity(1, AbstractUnit.ONE);
130
131  /**
132   * constructor.
133   */
134  protected AbstractQuantity(Unit<Q> unit) {
135    this.unit = unit;
136  }
137
138  /**
139   * Returns the numeric value of the quantity.
140   *
141   * @return the quantity value.
142   */
143  @Override
144  public abstract Number getValue();
145
146  /**
147   * Returns the measurement unit.
148   *
149   * @return the measurement unit.
150   */
151  @Override
152  public Unit<Q> getUnit() {
153    return unit;
154  }
155
156  /**
157   * Returns this quantity after conversion to specified unit. The default implementation returns
158   * <code>Measure.valueOf(doubleValue(unit), unit)</code> . If this quantity is already stated in the specified unit, then this quantity is returned
159   * and no conversion is performed.
160   *
161   * @param unit
162   *          the unit in which the returned measure is stated.
163   * @return this quantity or a new quantity equivalent to this quantity stated in the specified unit.
164   * @throws ArithmeticException
165   *           if the result is inexact and the quotient has a non-terminating decimal expansion.
166   */
167  @Override
168  public ComparableQuantity<Q> to(Unit<Q> unit) {
169    if (unit.equals(this.getUnit())) {
170      return this;
171    }
172    UnitConverter t = getUnit().getConverterTo(unit);
173    Number convertedValue = t.convert(getValue());
174    return Quantities.getQuantity(convertedValue, unit);
175  }
176
177//  /**
178//   * Returns this measure after conversion to specified unit. The default implementation returns
179//   * <code>Measure.valueOf(decimalValue(unit, ctx), unit)</code>. If this measure is already stated 
180//   * in the specified unit, then this measure is returned and no conversion is performed.
181//   *
182//   * @param unit
183//   *          the unit in which the returned measure is stated.
184//   * @param ctx
185//   *          the math context to use for conversion.
186//   * @return this measure or a new measure equivalent to this measure but stated in the specified unit.
187//   * @throws ArithmeticException
188//   *           if the result is inexact but the rounding mode is <code>UNNECESSARY</code> or 
189//   *           <code>mathContext.precision == 0</code> and the quotient
190//   *           has a non-terminating decimal expansion.
191//   */
192//  public Quantity<Q> to(Unit<Q> unit) {
193//    if (unit.equals(this.getUnit())) {
194//      return this;
195//    }
196//    return Quantities.getQuantity(decimalValue(unit), unit);
197//  }
198
199  @Override
200  public boolean isGreaterThan(Quantity<Q> that) {
201    return this.compareTo(that) > 0;
202  }
203
204  @Override
205  public boolean isGreaterThanOrEqualTo(Quantity<Q> that) {
206    return this.compareTo(that) >= 0;
207  }
208
209  @Override
210  public boolean isLessThan(Quantity<Q> that) {
211    return this.compareTo(that) < 0;
212  }
213
214  @Override
215  public boolean isLessThanOrEqualTo(Quantity<Q> that) {
216    return this.compareTo(that) <= 0;
217  }
218
219  @Override
220  public boolean isEquivalentTo(Quantity<Q> that) {
221    return this.compareTo(that) == 0;
222  }
223
224  /**
225   * Compares this measure to the specified Measurement quantity. The default implementation compares the {@link AbstractQuantity#doubleValue(Unit)}
226   * of both this measure and the specified Measurement stated in the same unit (this measure's {@link #getUnit() unit}).
227   *
228   * @return a negative integer, zero, or a positive integer as this measure is less than, equal to, or greater than the specified Measurement
229   *         quantity.
230   * @see {@link NaturalQuantityComparator}
231   */
232  @Override
233  public int compareTo(Quantity<Q> that) {
234    final Comparator<Quantity<Q>> comparator = new NaturalQuantityComparator<>();
235    return comparator.compare(this, that);
236  }
237
238  /**
239   * Compares this quantity against the specified object for <b>strict</b> equality (same unit and same amount).
240   *
241   * <p>
242   * Similarly to the {@link BigDecimal#equals} method which consider 2.0 and 2.00 as different objects because of different internal scales,
243   * quantities such as <code>Quantities.getQuantity(3.0, KILOGRAM)</code> <code>Quantities.getQuantity(3, KILOGRAM)</code> and
244   * <code>Quantities.getQuantity("3 kg")</code> might not be considered equals because of possible differences in their implementations.
245   * </p>
246   *
247   * <p>
248   * To compare quantities stated using different units or using different amount implementations the {@link #compareTo compareTo} or
249   * {@link #equals(javax.measure.Quantity, double, javax.measure.unit.Unit) equals(Quantity, epsilon, epsilonUnit)} methods should be used.
250   * </p>
251   *
252   * @param obj
253   *          the object to compare with.
254   * @return <code>this.getUnit.equals(obj.getUnit())
255   *         && this.getValue().equals(obj.getValue())</code>
256   */
257  @Override
258  public boolean equals(Object obj) {
259    if (this == obj) {
260      return true;
261    }
262    if (obj instanceof Quantity<?>) {
263        Quantity<?> that = (Quantity<?>) obj;
264        return Objects.equals(getUnit(), that.getUnit()) && Objects.equals(getValue(), that.getValue());
265    }
266    return false;
267  }
268
269  /**
270   * Returns the hash code for this quantity.
271   *
272   * @return the hash code value.
273   */
274  @Override
275  public int hashCode() {
276    return Objects.hash(getUnit(), getValue());
277  }
278
279  public abstract boolean isBig();
280
281  /**
282   * Returns the <code>String</code> representation of this quantity. The string produced for a given quantity is always the same; it is not affected
283   * by locale. This means that it can be used as a canonical string representation for exchanging quantity, or as a key for a Hashtable, etc.
284   * Locale-sensitive quantity formatting and parsing is handled by the {@link QuantityFormat} implementations and its subclasses.
285   *
286   * @return <code>UnitFormat.getInternational().format(this)</code>
287   */
288  @Override
289  public String toString() {
290    return String.valueOf(getValue()) + " " + String.valueOf(getUnit());
291  }
292
293  public abstract BigDecimal decimalValue(Unit<Q> unit) throws ArithmeticException;
294
295  public abstract double doubleValue(Unit<Q> unit) throws ArithmeticException;
296
297  public final int intValue(Unit<Q> unit) throws ArithmeticException {
298    long longValue = longValue(unit);
299    if ((longValue < Integer.MIN_VALUE) || (longValue > Integer.MAX_VALUE)) {
300      throw new ArithmeticException("Cannot convert " + longValue + " to int (overflow)");
301    }
302    return (int) longValue;
303  }
304
305  protected long longValue(Unit<Q> unit) throws ArithmeticException {
306    double result = doubleValue(unit);
307    if ((result < Long.MIN_VALUE) || (result > Long.MAX_VALUE)) {
308      throw new ArithmeticException("Overflow (" + result + ")");
309    }
310    return (long) result;
311  }
312
313  protected final float floatValue(Unit<Q> unit) {
314    return (float) doubleValue(unit);
315  }
316
317  @Override
318  public <T extends Quantity<T>, E extends Quantity<E>> ComparableQuantity<E> divide(Quantity<T> that, Class<E> asTypeQuantity) {
319
320    return divide(Objects.requireNonNull(that)).asType(Objects.requireNonNull(asTypeQuantity));
321
322  }
323
324  @Override
325  public <T extends Quantity<T>, E extends Quantity<E>> ComparableQuantity<E> multiply(Quantity<T> that, Class<E> asTypeQuantity) {
326    return multiply(Objects.requireNonNull(that)).asType(Objects.requireNonNull(asTypeQuantity));
327  }
328
329  @Override
330  public <T extends Quantity<T>> ComparableQuantity<T> inverse(Class<T> quantityClass) {
331    return inverse().asType(quantityClass);
332  }
333
334  /**
335   * Casts this quantity to a parameterized quantity of specified nature or throw a <code>ClassCastException</code> if the dimension of the specified
336   * quantity and its unit's dimension do not match. For example:<br>
337   * <code>
338   *     Quantity<Length> length = AbstractQuantity.parse("2 km").asType(Length.class);
339   * </code>
340   *
341   * @param type
342   *          the quantity class identifying the nature of the quantity.
343   * @return this quantity parameterized with the specified type.
344   * @throws ClassCastException
345   *           if the dimension of this unit is different from the specified quantity dimension.
346   * @throws UnsupportedOperationException
347   *           if the specified quantity class does not have a public static field named "UNIT" holding the SI unit for the quantity.
348   * @see Unit#asType(Class)
349   */
350  public final <T extends Quantity<T>> ComparableQuantity<T> asType(Class<T> type) throws ClassCastException {
351    this.getUnit().asType(type); // Raises ClassCastException if dimension
352    // mismatches.
353    return (ComparableQuantity<T>) this;
354  }
355
356  /**
357   * Returns the quantity of unknown type corresponding to the specified representation. This method can be used to parse dimensionless quantities.<br>
358   * <code>
359   *     Quatity<Dimensionless> proportion = AbstractQuantity.parse("0.234").asType(Dimensionless.class);
360   * </code>
361   *
362   * <p>
363   * Note: This method handles only {@link SimpleUnitFormat#getStandard standard} unit format. Locale-sensitive quantity parsing is currently not
364   * supported.
365   * </p>
366   *
367   * @param csq
368   *          the decimal value and its unit (if any) separated by space(s).
369   * @return <code>QuantityFormat.getInstance().parse(csq)</code>
370   */
371  public static Quantity<?> parse(CharSequence csq) {
372    return SimpleQuantityFormat.getInstance().parse(csq);
373  }
374
375  protected boolean hasFraction(double value) {
376    return Math.round(value) != value;
377  }
378
379  protected boolean hasFraction(BigDecimal value) {
380    return value.remainder(BigDecimal.ONE).compareTo(BigDecimal.ZERO) != 0;
381  }
382
383  /**
384   * Utility class for number comparison and equality
385   */
386  protected static final class Equalizer {
387
388    /**
389     * Check if the both value has equality number, in other words, 1 is equals to 1.0000 and 1.0.
390     * 
391     * If the first value is a <type>Number</type> of either <type>Double</type>, <type>Float</type>, <type>Integer</type>, <type>Long</type>,
392     * <type>Short</type> or <type>Byte</type> it is compared using the respective <code>*value()</code> method of <type>Number</type>. Otherwise it
393     * is checked, if {@link BigDecimal#compareTo(Object)} is equal to zero.
394     *
395     * @param valueA
396     *          the value a
397     * @param valueB
398     *          the value B
399     * @return {@link BigDecimal#compareTo(Object)} == zero
400     */
401    public static boolean hasEquality(Number valueA, Number valueB) {
402      Objects.requireNonNull(valueA);
403      Objects.requireNonNull(valueB);
404
405      if (valueA instanceof Double && valueB instanceof Double) {
406        return valueA.doubleValue() == valueB.doubleValue();
407      } else if (valueA instanceof Float && valueB instanceof Float) {
408        return valueA.floatValue() == valueB.floatValue();
409      } else if (valueA instanceof Integer && valueB instanceof Integer) {
410        return valueA.intValue() == valueB.intValue();
411      } else if (valueA instanceof Long && valueB instanceof Long) {
412        return valueA.longValue() == valueB.longValue();
413      } else if (valueA instanceof Short && valueB instanceof Short) {
414        return valueA.shortValue() == valueB.shortValue();
415      } else if (valueA instanceof Byte && valueB instanceof Byte) {
416        return valueA.byteValue() == valueB.byteValue();
417      }
418      return Calculus.toBigDecimal(valueA).compareTo(Calculus.toBigDecimal(valueB)) == 0;
419    }
420  }
421}