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