001/*
002 * Units of Measurement Reference Implementation
003 * Copyright (c) 2005-2016, 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;
033
034import javax.measure.Quantity;
035import javax.measure.Unit;
036import javax.measure.quantity.Dimensionless;
037
038import tec.units.ri.format.QuantityFormat;
039import tec.units.ri.function.NaturalOrder;
040import tec.units.ri.quantity.NumberQuantity;
041import tec.uom.lib.common.function.UnitSupplier;
042import tec.uom.lib.common.function.ValueSupplier;
043
044/**
045 * <p>
046 * This class represents the immutable result of a scalar measurement stated in a known unit.
047 * </p>
048 * 
049 * <p>
050 * <code>
051 *         public static final Quantity<Velocity> C = NumberQuantity.parse("299792458 m/s").asType(Velocity.class);
052 *         // Speed of Light (exact).
053 *    </code>
054 * </p>
055 * 
056 * <p>
057 * Quantities can be converted to different units.<br/>
058 * <code>
059 *         Quantity<Velocity> milesPerHour = C.to(MILES_PER_HOUR); // Use double implementation (fast).
060 *         System.out.println(milesPerHour);
061 * 
062 *         > 670616629.3843951 m/h
063 *     </code>
064 * </p>
065 * 
066 * <p>
067 * Applications may sub-class {@link AbstractQuantity} for particular quantity types.<br/>
068 * <code>
069 *         // Quantity of type Mass based on <code>double</code> primitive types.<br>
070 * public class MassAmount extends AbstractQuantity<Mass> {<br>
071 * private final double kilograms; // Internal SI representation.<br>
072 * private Mass(double kg) { kilograms = kg; }<br>
073 * public static Mass of(double value, Unit<Mass> unit) {<br>
074 * return new Mass(unit.getConverterTo(SI.KILOGRAM).convert(value));<br>
075 * }<br>
076 * public Unit<Mass> getUnit() { return SI.KILOGRAM; }<br>
077 * public Double getValue() { return _kilograms; }<br>
078 * ...<br>
079 * }<br>
080 * </p>
081 * <p>
082 * // Complex numbers measurements.<br>
083 * public class ComplexQuantity
084 * <Q extends Quantity>extends AbstractQuantity
085 * <Q>{<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<ElectricCurrent> {...}<br>
092 * public final class Tension extends ComplexQuantity<ElectricPotential> {...} <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, August 9, 2016
102 */
103public abstract class AbstractQuantity<Q extends Quantity<Q>> implements Quantity<Q>, Comparable<Quantity<Q>>, UnitSupplier<Q>, ValueSupplier<Number> {
104
105  /**
106         * 
107         */
108  // private static final long serialVersionUID = -4993173119977931016L;
109
110  private final Unit<Q> unit;
111
112  /**
113   * Holds a dimensionless quantity of none (exact).
114   */
115  public static final Quantity<Dimensionless> NONE = NumberQuantity.of(0, AbstractUnit.ONE);
116
117  /**
118   * Holds a dimensionless quantity of one (exact).
119   */
120  public static final Quantity<Dimensionless> ONE = NumberQuantity.of(1, AbstractUnit.ONE);
121
122  /**
123   * constructor.
124   */
125  protected AbstractQuantity(Unit<Q> unit) {
126    this.unit = unit;
127  }
128
129  /**
130   * Returns the measurement numeric value.
131   *
132   * @return the measurement value.
133   */
134  public abstract Number getValue();
135
136  /**
137   * Returns the measurement unit.
138   *
139   * @return the measurement unit.
140   */
141  public Unit<Q> getUnit() {
142    return unit;
143  }
144
145  /**
146   * Convenient method equivalent to {@link #to(javax.measure.unit.Unit) to(this.getUnit().toSI())}.
147   *
148   * @return this measure or a new measure equivalent to this measure but stated in SI units.
149   * @throws ArithmeticException
150   *           if the result is inexact and the quotient has a non-terminating decimal expansion.
151   */
152  public Quantity<Q> toSI() {
153    return to(this.getUnit().getSystemUnit());
154  }
155
156  /**
157   * Returns this measure after conversion to specified unit. The default implementation returns <code>Measure.valueOf(doubleValue(unit), unit)</code>
158   * . If this measure is already stated in the specified unit, then this measure is returned and no conversion is performed.
159   *
160   * @param unit
161   *          the unit in which the returned measure is stated.
162   * @return this measure or a new measure equivalent to this measure but stated in the specified unit.
163   * @throws ArithmeticException
164   *           if the result is inexact and the quotient has a non-terminating decimal expansion.
165   */
166  public Quantity<Q> to(Unit<Q> unit) {
167    if (unit.equals(this.getUnit())) {
168      return this;
169    }
170    return NumberQuantity.of(doubleValue(unit), unit);
171  }
172
173  /**
174   * Compares this measure to the specified Measurement quantity. The default implementation compares the {@link AbstractQuantity#doubleValue(Unit)}
175   * of both this measure and the specified Measurement stated in the same unit (this measure's {@link #getUnit() unit}).
176   *
177   * @return a negative integer, zero, or a positive integer as this measure is less than, equal to, or greater than the specified Measurement
178   *         quantity.
179   * @see {@link NaturalOrder}
180   */
181  public int compareTo(Quantity<Q> that) {
182    final Comparator<Quantity<Q>> comparator = new NaturalOrder<Q>();
183    return comparator.compare(this, that);
184  }
185
186  /**
187   * Compares this measure against the specified object for <b>strict</b> equality (same unit and same amount).
188   *
189   * <p>
190   * Similarly to the {@link BigDecimal#equals} method which consider 2.0 and 2.00 as different objects because of different internal scales,
191   * measurements such as <code>Measure.valueOf(3.0, KILOGRAM)</code> <code>Measure.valueOf(3, KILOGRAM)</code> and
192   * <code>Quantities.getQuantity("3 kg")</code> might not be considered equals because of possible differences in their implementations.
193   * </p>
194   *
195   * <p>
196   * To compare measures stated using different units or using different amount implementations the {@link #compareTo compareTo} or
197   * {@link #equals(javax.measure.Measurement, double, javax.measure.unit.Unit) equals(Measurement, epsilon, epsilonUnit)} methods should be used.
198   * </p>
199   *
200   * @param obj
201   *          the object to compare with.
202   * @return <code>this.getUnit.equals(obj.getUnit())
203   *         && this.getValue().equals(obj.getValue())</code>
204   */
205  @Override
206  public boolean equals(Object obj) {
207    if (!(obj instanceof AbstractQuantity<?>)) {
208      return false;
209    }
210    AbstractQuantity<?> that = (AbstractQuantity<?>) obj;
211    return this.getUnit().equals(that.getUnit()) && this.getValue().equals(that.getValue());
212  }
213
214  /**
215   * Compares this measure and the specified Measurement to the given accuracy. Measurements are considered approximately equals if their absolute
216   * differences when stated in the same specified unit is less than the specified epsilon.
217   *
218   * @param that
219   *          the Measurement to compare with.
220   * @param epsilon
221   *          the absolute error stated in epsilonUnit.
222   * @param epsilonUnit
223   *          the epsilon unit.
224   * @return <code>abs(this.doubleValue(epsilonUnit) - that.doubleValue(epsilonUnit)) &lt;= epsilon</code>
225   */
226  public boolean equals(AbstractQuantity<Q> that, double epsilon, Unit<Q> epsilonUnit) {
227    return Math.abs(this.doubleValue(epsilonUnit) - that.doubleValue(epsilonUnit)) <= epsilon;
228  }
229
230  /**
231   * Returns the hash code for this quantity.
232   *
233   * @return the hash code value.
234   */
235  @Override
236  public int hashCode() {
237    return getUnit().hashCode() + getValue().hashCode();
238  }
239
240  final boolean isBig() {
241    return false;
242  }
243
244  /**
245   * Returns the <code>String</code> representation of this quantity. The string produced for a given quantity is always the same; it is not affected
246   * 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.
247   * Locale-sensitive quantity formatting and parsing is handled by the {@link QuantityFormat} class and its subclasses.
248   *
249   * @return <code>UnitFormat.getInternational().format(this)</code>
250   */
251  @Override
252  public String toString() {
253    // return MeasureFormat.getStandard().format(this); TODO improve
254    // MeasureFormat
255    // return String.valueOf(getValue()) + " " + String.valueOf(getUnit());
256    return QuantityFormat.getInstance().format(this);
257  }
258
259  public abstract double doubleValue(Unit<Q> unit) throws ArithmeticException;
260
261  protected long longValue(Unit<Q> unit) throws ArithmeticException {
262    double result = doubleValue(unit);
263    if ((result < Long.MIN_VALUE) || (result > Long.MAX_VALUE)) {
264      throw new ArithmeticException("Overflow (" + result + ")");
265    }
266    return (long) result;
267  }
268
269  protected float floatValue(Unit<Q> unit) {
270    return (float) doubleValue(unit);
271  }
272
273  /**
274   * Casts this quantity to a parameterized unit of specified nature or throw a <code>ClassCastException</code> if the dimension of the specified
275   * quantity and this measure unit's dimension do not match. For example: <br/>
276   * <code>
277   *     Measure<Length> length = Quantities.getQuantity("2 km").asType(Length.class);
278   * </code>
279   *
280   * @param type
281   *          the quantity class identifying the nature of the quantity.
282   * @return this quantity parameterized with the specified type.
283   * @throws ClassCastException
284   *           if the dimension of this unit is different from the specified quantity dimension.
285   * @throws UnsupportedOperationException
286   *           if the specified quantity class does not have a public static field named "UNIT" holding the SI unit for the quantity.
287   * @see Unit#asType(Class)
288   */
289  @SuppressWarnings("unchecked")
290  public final <T extends Quantity<T>> AbstractQuantity<T> asType(Class<T> type) throws ClassCastException {
291    this.getUnit().asType(type); // Raises ClassCastException is dimension
292    // mismatches.
293    return (AbstractQuantity<T>) this;
294  }
295}