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.lang.reflect.ParameterizedType;
033import java.lang.reflect.Type;
034import java.math.BigInteger;
035import java.util.HashMap;
036import java.util.Map;
037
038import javax.measure.Dimension;
039import javax.measure.IncommensurableException;
040import javax.measure.Quantity;
041import javax.measure.UnconvertibleException;
042import javax.measure.Unit;
043import javax.measure.UnitConverter;
044import javax.measure.format.ParserException;
045import javax.measure.quantity.Dimensionless;
046
047import tech.units.indriya.format.LocalUnitFormat;
048import tech.units.indriya.format.SimpleUnitFormat;
049import tech.units.indriya.function.AddConverter;
050import tech.units.indriya.function.MultiplyConverter;
051import tech.units.indriya.function.PowersOfIntConverter;
052import tech.units.indriya.function.RationalConverter;
053import tech.units.indriya.quantity.QuantityDimension;
054import tech.units.indriya.spi.DimensionalModel;
055import tech.units.indriya.unit.AlternateUnit;
056import tech.units.indriya.unit.AnnotatedUnit;
057import tech.units.indriya.unit.Prefix;
058import tech.units.indriya.unit.ProductUnit;
059import tech.units.indriya.unit.TransformedUnit;
060import tech.units.indriya.unit.Units;
061
062/**
063 * <p>
064 * The class represents units founded on the seven <b>SI</b> base units for
065 * seven base quantities assumed to be mutually independent.
066 * </p>
067 *
068 * <p>
069 * For all physics units, unit conversions are symmetrical:
070 * <code>u1.getConverterTo(u2).equals(u2.getConverterTo(u1).inverse())</code>.
071 * Non-physical units (e.g. currency units) for which conversion is not
072 * symmetrical should have their own separate class hierarchy and are considered
073 * distinct (e.g. financial units), although they can always be combined with
074 * physics units (e.g. "€/Kg", "$/h").
075 * </p>
076 *
077 * @see <a href=
078 *      "http://en.wikipedia.org/wiki/International_System_of_Units">Wikipedia:
079 *      International System of Units</a>
080 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
081 * @author <a href="mailto:units@catmedia.us">Werner Keil</a>
082 * @version 1.2, April 11, 2018
083 * @since 1.0
084 */
085public abstract class AbstractUnit<Q extends Quantity<Q>> implements ComparableUnit<Q> {
086
087        /**
088         * 
089         */
090        private static final long serialVersionUID = -4344589505537030204L;
091
092        /**
093         * Holds the dimensionless unit <code>ONE</code>.
094         * 
095         * @see <a href=
096         *      "https://en.wikipedia.org/wiki/Natural_units#Choosing_constants_to_normalize">
097         *      Wikipedia: Natural Units - Choosing constants to normalize</a>
098         * @see <a href= "http://www.av8n.com/physics/dimensionless-units.htm">Units of
099         *      Dimension One</a>
100         */
101        public static final Unit<Dimensionless> ONE = new ProductUnit<>();
102
103        /**
104         * Holds the name.
105         */
106        protected String name;
107
108        /**
109         * Holds the symbol.
110         */
111        private String symbol;
112
113        /**
114         * Holds the unique symbols collection (base units or alternate units).
115         */
116        protected static final Map<String, Unit<?>> SYMBOL_TO_UNIT = new HashMap<>();
117
118        /**
119         * Default constructor.
120         */
121        protected AbstractUnit() {
122        }
123
124        protected Type getActualType() {
125                ParameterizedType parameterizedType = (ParameterizedType) getClass().getGenericSuperclass();
126                return parameterizedType.getActualTypeArguments()[0].getClass().getGenericInterfaces()[0];
127        }
128
129        /**
130         * Indicates if this unit belongs to the set of coherent SI units (unscaled SI
131         * units).
132         * 
133         * The base and coherent derived units of the SI form a coherent set, designated
134         * the set of coherent SI units. The word coherent is used here in the following
135         * sense: when coherent units are used, equations between the numerical values
136         * of quantities take exactly the same form as the equations between the
137         * quantities themselves. Thus if only units from a coherent set are used,
138         * conversion factors between units are never required.
139         * 
140         * @return <code>equals(toSystemUnit())</code>
141         */
142        @Override
143        public boolean isSystemUnit() {
144                Unit<Q> si = this.toSystemUnit();
145                return (this == si) || this.equals(si);
146        }
147
148        /**
149         * Returns the unscaled {@link SI} unit from which this unit is derived.
150         * 
151         * The SI unit can be be used to identify a quantity given the unit. For
152         * example:<code> static boolean isAngularVelocity(AbstractUnit<?> unit) {
153         * return unit.toSystemUnit().equals(RADIAN.divide(SECOND)); } assert(REVOLUTION.divide(MINUTE).isAngularVelocity()); // Returns true. </code>
154         *
155         * @return the unscaled metric unit from which this unit is derived.
156         */
157        protected abstract Unit<Q> toSystemUnit();
158
159        /**
160         * Returns the converter from this unit to its unscaled {@link #toSysemUnit
161         * System Unit} unit.
162         *
163         * @return <code>getConverterTo(this.toSystemUnit())</code>
164         * @see #toSystemUnit
165         */
166        public abstract UnitConverter getSystemConverter();
167
168        /**
169         * Annotates the specified unit. Annotation does not change the unit semantic.
170         * Annotations are often written between curly braces behind units. For
171         * example:<br>
172         * <code> Unit<Volume> PERCENT_VOL = ((AbstractUnit)Units.PERCENT).annotate("vol"); // "%{vol}" Unit<Mass> KG_TOTAL =
173         * ((AbstractUnit)Units.KILOGRAM).annotate("total"); // "kg{total}" Unit<Dimensionless> RED_BLOOD_CELLS = ((AbstractUnit)Units.ONE).annotate("RBC"); // "{RBC}" </code>
174         *
175         * Note: Annotation of system units are not considered themselves as system
176         * units.
177         *
178         * @param annotation
179         *            the unit annotation.
180         * @return the annotated unit.
181         */
182        public Unit<Q> annotate(String annotation) {
183                return new AnnotatedUnit<>(this, annotation);
184        }
185
186        /*
187         * Returns the combination of this unit with the specified sub-unit. Compound
188         * units are typically used for formatting purpose. Examples of compound
189         * units:<code> Unit<Length> FOOT_INCH = FOOT.compound(INCH); Unit<Time>
190         * HOUR_MINUTE_SECOND = HOUR.compound(MINUTE).compound(SECOND); </code>
191         * 
192         * @param that the least significant unit to combine with this unit.
193         * 
194         * @return the corresponding compound unit.
195         *
196         * public final Unit<Q> compound(Unit<Q> that) { return new
197         * CompoundUnit<Q>(this, that); }
198         */
199
200        /**
201         * Returns the abstract unit represented by the specified characters as per
202         * default format.
203         *
204         * Locale-sensitive unit parsing could be handled using {@link LocalUnitFormat}
205         * in subclasses of AbstractUnit.
206         *
207         * <p>
208         * Note: The standard format supports dimensionless
209         * units.<code> AbstractUnit<Dimensionless> PERCENT =
210         * AbstractUnit.parse("100").inverse().asType(Dimensionless.class); </code>
211         * </p>
212         *
213         * @param charSequence
214         *            the character sequence to parse.
215         * @return <code>SimpleUnitFormat.getInstance().parse(csq, new ParsePosition(0))</code>
216         * @throws ParserException
217         *             if the specified character sequence cannot be correctly parsed
218         *             (e.g. not UCUM compliant).
219         */
220        public static Unit<?> parse(CharSequence charSequence) {
221                return SimpleUnitFormat.getInstance().parse(charSequence);
222        }
223
224        /**
225         * Returns the standard representation of this physics unit. The string produced
226         * for a given unit is always the same; it is not affected by the locale. It can
227         * be used as a canonical string representation for exchanging units, or as a
228         * key for a Hashtable, etc.
229         *
230         * Locale-sensitive unit parsing could be handled using {@link LocalUnitFormat}
231         * in subclasses of AbstractUnit.
232         *
233         * @return <code>SimpleUnitFormat.getInstance().format(this)</code>
234         */
235        @Override
236        public String toString() {
237                return SimpleUnitFormat.getInstance().format(this);
238        }
239
240        // ///////////////////////////////////////////////////////
241        // Implements javax.measure.Unit<Q> interface //
242        // ///////////////////////////////////////////////////////
243
244        /**
245         * Returns the system unit (unscaled SI unit) from which this unit is derived.
246         * They can be be used to identify a quantity given the unit. For example:<br>
247         * <code> static boolean isAngularVelocity(AbstractUnit<?> unit) {<br>&nbsp;&nbsp;return unit.getSystemUnit().equals(RADIAN.divide(SECOND));<br>}
248         * <br>assert(REVOLUTION.divide(MINUTE).isAngularVelocity()); // Returns true. </code>
249         *
250         * @return the unscaled metric unit from which this unit is derived.
251         */
252        @Override
253        public final Unit<Q> getSystemUnit() {
254                return toSystemUnit();
255        }
256
257        /**
258         * Indicates if this unit is compatible with the unit specified. To be
259         * compatible both units must be physics units having the same fundamental
260         * dimension.
261         *
262         * @param that
263         *            the other unit.
264         * @return <code>true</code> if this unit and that unit have equals fundamental
265         *         dimension according to the current physics model; <code>false</code>
266         *         otherwise.
267         */
268        @Override
269        public final boolean isCompatible(Unit<?> that) {
270                return internalIsCompatible(that, true);
271        }
272
273        /**
274         * Casts this unit to a parameterized unit of specified nature or throw a
275         * ClassCastException if the dimension of the specified quantity and this unit's
276         * dimension do not match (regardless whether or not the dimensions are
277         * independent or not).
278         *
279         * @param type
280         *            the quantity class identifying the nature of the unit.
281         * @throws ClassCastException
282         *             if the dimension of this unit is different from the SI dimension
283         *             of the specified type.
284         * @see Units#getUnit(Class)
285         */
286        @SuppressWarnings("unchecked")
287        @Override
288        public final <T extends Quantity<T>> AbstractUnit<T> asType(Class<T> type) {
289                Dimension typeDimension = QuantityDimension.of(type);
290                if ((typeDimension != null) && (!typeDimension.equals(this.getDimension())))
291                        throw new ClassCastException("The unit: " + this + " is not compatible with quantities of type " + type);
292                return (AbstractUnit<T>) this;
293        }
294
295        @Override
296        public abstract Map<? extends Unit<?>, Integer> getBaseUnits();
297
298        @Override
299        public abstract Dimension getDimension();
300
301        protected void setName(String name) {
302                this.name = name;
303        }
304
305        public String getName() {
306                return name;
307        }
308
309        public String getSymbol() {
310                return symbol;
311        }
312
313        protected void setSymbol(String s) {
314                this.symbol = s;
315        }
316
317        @Override
318        public final UnitConverter getConverterTo(Unit<Q> that) throws UnconvertibleException {
319                return internalGetConverterTo(that, true);
320        }
321
322        @SuppressWarnings("rawtypes")
323        @Override
324        public final UnitConverter getConverterToAny(Unit<?> that) throws IncommensurableException, UnconvertibleException {
325                if (!isCompatible(that))
326                        throw new IncommensurableException(this + " is not compatible with " + that);
327                AbstractUnit thatAbstr = (AbstractUnit) that; // Since both units are
328                // compatible they must
329                // be both physics
330                // units.
331                DimensionalModel model = DimensionalModel.current();
332                Unit thisSystemUnit = this.getSystemUnit();
333                UnitConverter thisToDimension = model.getDimensionalTransform(thisSystemUnit.getDimension())
334                                .concatenate(this.getSystemConverter());
335                Unit thatSystemUnit = thatAbstr.getSystemUnit();
336                UnitConverter thatToDimension = model.getDimensionalTransform(thatSystemUnit.getDimension())
337                                .concatenate(thatAbstr.getSystemConverter());
338                return thatToDimension.inverse().concatenate(thisToDimension);
339        }
340
341        @SuppressWarnings({ "rawtypes", "unchecked" })
342        @Override
343        public final Unit<Q> alternate(String symbol) {
344                return new AlternateUnit(this, symbol);
345        }
346
347        @Override
348        public final Unit<Q> transform(UnitConverter operation) {
349                Unit<Q> systemUnit = this.getSystemUnit();
350                UnitConverter cvtr;
351                if (this.isSystemUnit()) {
352                        cvtr = this.getSystemConverter().concatenate(operation);
353                } else {
354                        cvtr = operation;
355                }
356                if (cvtr.isIdentity()) {
357                        return systemUnit;
358                } else {
359                        return new TransformedUnit<>(null, this, systemUnit, cvtr);
360                }
361        }
362
363        @Override
364        public final Unit<Q> shift(double offset) {
365                if (offset == 0)
366                        return this;
367                return transform(new AddConverter(offset));
368        }
369
370        @Override
371        public final Unit<Q> multiply(double factor) {
372                if (factor == 1)
373                        return this;
374                return transform(converterOf(factor));
375        }
376
377        /**
378         * Internal helper for isCompatible
379         */
380        private final boolean internalIsCompatible(Unit<?> that, boolean checkEquals) {
381                if (checkEquals) {
382                        if ((this == that) || this.equals(that))
383                                return true;
384                } else {
385                        if (this == that)
386                                return true;
387                }
388                if (!(that instanceof AbstractUnit))
389                        return false;
390                Dimension thisDimension = this.getDimension();
391                Dimension thatDimension = that.getDimension();
392                if (thisDimension.equals(thatDimension))
393                        return true;
394                DimensionalModel model = DimensionalModel.current(); // Use
395                // dimensional
396                // analysis
397                // model.
398                return model.getFundamentalDimension(thisDimension).equals(model.getFundamentalDimension(thatDimension));
399        }
400
401        private final UnitConverter internalGetConverterTo(Unit<Q> that, boolean useEquals) throws UnconvertibleException {
402                if (useEquals) {
403                        if ((this == that) || this.equals(that))
404                                return AbstractConverter.IDENTITY;
405                } else {
406                        if (this == that)
407                                return AbstractConverter.IDENTITY;
408                }
409                Unit<Q> thisSystemUnit = this.getSystemUnit();
410                Unit<Q> thatSystemUnit = that.getSystemUnit();
411                if (!thisSystemUnit.equals(thatSystemUnit))
412                        try {
413                                return getConverterToAny(that);
414                        } catch (IncommensurableException e) {
415                                throw new UnconvertibleException(e);
416                        }
417                UnitConverter thisToSI = this.getSystemConverter();
418                UnitConverter thatToSI = that.getConverterTo(thatSystemUnit);
419                return thatToSI.inverse().concatenate(thisToSI);
420        }
421
422        private static boolean isLongValue(double value) {
423                return !((value < Long.MIN_VALUE) || (value > Long.MAX_VALUE)) && Math.floor(value) == value;
424        }
425
426        static UnitConverter converterOf(double factor) {
427                if (isLongValue(factor)) {
428                        return new RationalConverter(BigInteger.valueOf((long) factor), BigInteger.ONE);
429                }
430                return new MultiplyConverter(factor);
431        }
432
433        /**
434         * Returns the product of this unit with the one specified.
435         *
436         * <p>
437         * Note: If the specified unit (that) is not a physical unit, then
438         * <code>that.multiply(this)</code> is returned.
439         * </p>
440         *
441         * @param that
442         *            the unit multiplicand.
443         * @return <code>this * that</code>
444         */
445        @Override
446        public final Unit<?> multiply(Unit<?> that) {
447                if (that instanceof AbstractUnit)
448                        return multiply((AbstractUnit<?>) that);
449                // return that.multiply(this); // Commutatif.
450                return ProductUnit.ofProduct(this, that);
451        }
452
453        /**
454         * Returns the product of this physical unit with the one specified.
455         *
456         * @param that
457         *            the physical unit multiplicand.
458         * @return <code>this * that</code>
459         */
460        protected final Unit<?> multiply(AbstractUnit<?> that) {
461                if (this.equals(ONE))
462                        return that;
463                if (that.equals(ONE))
464                        return this;
465                return ProductUnit.ofProduct(this, that);
466        }
467
468        /**
469         * Returns the inverse of this physical unit.
470         *
471         * @return <code>1 / this</code>
472         */
473        @Override
474        public final Unit<?> inverse() {
475                if (this.equals(ONE))
476                        return this;
477                return ProductUnit.ofQuotient(ONE, this);
478        }
479
480        /**
481         * Returns the result of dividing this unit by the specified divisor. If the
482         * factor is an integer value, the division is exact. For example:
483         * 
484         * <pre>
485         * <code>
486         *    QUART = GALLON_LIQUID_US.divide(4); // Exact definition.
487         * </code>
488         * </pre>
489         * 
490         * @param divisor
491         *            the divisor value.
492         * @return this unit divided by the specified divisor.
493         */
494        @Override
495        public final Unit<Q> divide(double divisor) {
496                if (divisor == 1)
497                        return this;
498                if (isLongValue(divisor)) //TODO [ahuber] you can not reach every long with a double!
499                        return transform(new RationalConverter(BigInteger.ONE, BigInteger.valueOf((long) divisor)));
500                return transform(new MultiplyConverter(1.0 / divisor));
501        }
502
503        /**
504         * Returns the quotient of this unit with the one specified.
505         *
506         * @param that
507         *            the unit divisor.
508         * @return <code>this.multiply(that.inverse())</code>
509         */
510        @Override
511        public final Unit<?> divide(Unit<?> that) {
512                return this.multiply(that.inverse());
513        }
514
515        /**
516         * Returns the quotient of this physical unit with the one specified.
517         *
518         * @param that
519         *            the physical unit divisor.
520         * @return <code>this.multiply(that.inverse())</code>
521         */
522        protected final Unit<?> divide(AbstractUnit<?> that) {
523                return this.multiply(that.inverse());
524        }
525
526        /**
527         * Returns a unit equals to the given root of this unit.
528         *
529         * @param n
530         *            the root's order.
531         * @return the result of taking the given root of this unit.
532         * @throws ArithmeticException
533         *             if <code>n == 0</code> or if this operation would result in an
534         *             unit with a fractional exponent.
535         */
536        @Override
537        public final Unit<?> root(int n) {
538                if (n > 0)
539                        return ProductUnit.ofRoot(this, n);
540                else if (n == 0)
541                        throw new ArithmeticException("Root's order of zero");
542                else
543                        // n < 0
544                        return ONE.divide(this.root(-n));
545        }
546
547        /**
548         * Returns a unit equals to this unit raised to an exponent.
549         *
550         * @param n
551         *            the exponent.
552         * @return the result of raising this unit to the exponent.
553         */
554        @Override
555        public final Unit<?> pow(int n) {
556                if (n > 0)
557                        return this.multiply(this.pow(n - 1));
558                else if (n == 0)
559                        return ONE;
560                else
561                        // n < 0
562                        return ONE.divide(this.pow(-n));
563        }
564        
565        public AbstractUnit<Q> prefix(Prefix prefix) {
566                return (AbstractUnit<Q>) this.transform(PowersOfIntConverter.of(prefix));
567        }
568
569        /**
570         * Compares this unit to the specified unit. The default implementation compares
571         * the name and symbol of both this unit and the specified unit.
572         *
573         * @return a negative integer, zero, or a positive integer as this unit is less
574         *         than, equal to, or greater than the specified unit.
575         */
576        public int compareTo(Unit<Q> that) {
577                if (name != null && getSymbol() != null) {
578                        return name.compareTo(that.getName()) + getSymbol().compareTo(that.getSymbol());
579                } else if (name == null) {
580                        if (getSymbol() != null && that.getSymbol() != null) {
581                                return getSymbol().compareTo(that.getSymbol());
582                        } else {
583                                return -1;
584                        }
585                } else if (getSymbol() == null) {
586                        if (name != null) {
587                                return name.compareTo(that.getName());
588                        } else {
589                                return -1;
590                        }
591                } else {
592                        UnitConverter conv = getConverterTo(that);
593                        if (conv instanceof AbstractConverter) {
594                                return ((AbstractConverter) conv).compareTo(that.getConverterTo(this));
595                        }
596                        return -1;
597                }
598        }
599
600        @Override
601        public boolean isEquivalentOf(Unit<Q> that) {
602                if (this.compareTo(that) == 0)
603                        return true;
604                return this.getConverterTo(that).isIdentity();
605                //[ahuber] was ... return this.getConverterTo(that).equals(that.getConverterTo(this));
606        }
607
608        // //////////////////////////////////////////////////////////////
609        // Ensures that sub-classes implement the hashCode method.
610        // //////////////////////////////////////////////////////////////
611
612        @Override
613        public abstract boolean equals(Object obj);
614
615        @Override
616        public abstract int hashCode();
617
618        /**
619         * Utility class for number comparison and equality
620         */
621        protected static final class Equalizer {
622                /**
623                 * Indicates if this unit is considered equals to the specified object. order).
624                 *
625                 * @param obj
626                 *            the object to compare for equality.
627                 * @return <code>true</code> if <code>this</code> and <code>obj</code> are
628                 *         considered equal; <code>false</code>otherwise.
629                 */
630                public static boolean areEqual(@SuppressWarnings("rawtypes") AbstractUnit u1, @SuppressWarnings("rawtypes") AbstractUnit u2) {
631                        /*
632                         * if (u1 != null && u2 != null) { if (u1.getName() != null && u1.getSymbol() !=
633                         * null) { return u1.getName().equals(u2.getName()) &&
634                         * u1.getSymbol().equals(u2.getSymbol()) && u1.internalIsCompatible(u2, false);
635                         * } else if (u1.getSymbol() != null) { return
636                         * u1.getSymbol().equals(u2.getSymbol()) && u1.internalIsCompatible(u2, false);
637                         * } else { return u1.toString().equals(u2.toString()) &&
638                         * u1.internalIsCompatible(u2, false); } } else {
639                         */
640                        if (u1 == u2)
641                                return true;
642                        return false;
643                }
644        }
645        
646
647        
648}