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