001/*
002 * Units of Measurement Enum Implementation
003 * Copyright © 2005-2021, Werner Keil and others.
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, Unit-API 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.uom.impl.enums.unit;
031
032import javax.measure.UnitConverter;
033
034import tech.uom.impl.enums.format.SimpleUnitFormat;
035
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;
044
045/**
046 * <p>
047 * This class represents multi-radix units (such as "hour:min:sec" or "ft, in"). Instances of this class are created using the {@link Unit#mix
048 * Unit.mix} method.
049 * </p>
050 * 
051 * <p>
052 * Examples of mixed units:<code> Unit<Time> HOUR_MINUTE_SECOND = HOUR.mix(MINUTE).mix(SECOND); <br>Unit<Length> FOOT_INCH =
053 * FOOT.mix(INCH); </code>
054 * </p>
055 *
056 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
057 * @author <a href="mailto:werner@units.tech">Werner Keil</a>
058 * @version 2.0, Oct 3, 2020
059 * @since 2.0
060 */
061public final class MixedUnit<Q extends Quantity<Q>> implements Unit<Q> {
062
063    /**
064     * Holds the upper unit.
065     */
066    private final Unit<Q> upper;
067
068    /**
069     * Holds the lower unit.
070     */
071    private final Unit<Q> lower;
072
073    /**
074     * Creates a mixed unit from the specified units.
075     *
076     * @param up
077     *            the upper unit.
078     * @param low
079     *            the lower unit(s)
080     * @throws IllegalArgumentException
081     *             if both units do not the same system unit.
082     */
083    public MixedUnit(Unit<Q> up, Unit<Q> low) {
084        if (!up.getSystemUnit().equals(low.getSystemUnit()))
085            throw new IllegalArgumentException("Both units do not have the same system unit");
086        upper = up;
087        lower = low;
088    }
089
090    /**
091     * Returns the lower unit of this mixed unit.
092     *
093     * @return the lower unit.
094     */
095    public Unit<Q> getLower() {
096        return lower;
097    }
098
099    /**
100     * Returns the upper unit of this mixed unit.
101     *
102     * @return the upper unit.
103     */
104    public Unit<Q> getUpper() {
105        return upper;
106    }
107
108    /**
109     * Indicates if this mixed unit is considered equals to the specified object (both are mixed units with same composing units in the same
110     * order).
111     *
112     * @param obj
113     *            the object to compare for equality.
114     * @return <code>true</code> if <code>this</code> and <code>obj</code> are considered equal; <code>false</code>otherwise.
115     */
116    public boolean equals(Object obj) {
117        if (this == obj) {
118            return true;
119        }
120        if (obj instanceof MixedUnit) {
121            MixedUnit<?> thatUnit = (MixedUnit<?>) obj;
122            return this.upper.equals(thatUnit.upper) && this.lower.equals(thatUnit.lower);
123        }
124        return super.equals(obj);
125    }
126
127    @Override
128    public int hashCode() {
129        return upper.hashCode() ^ lower.hashCode();
130    }
131
132    @Override
133    public Unit<Q> getSystemUnit() {
134        return lower.getSystemUnit();
135    }
136
137    @Override
138    public Dimension getDimension() {
139        return lower.getDimension();
140    }
141
142    @Override
143    public String getSymbol() {
144        return upper.getSymbol() + ":" + lower.getSymbol();
145    }
146
147    @Override
148    public String getName() {
149        return upper.getName() + ":" + lower.getName();
150    }
151
152    @Override
153    public Map<? extends Unit<?>, Integer> getBaseUnits() {
154        // TODO Auto-generated method stub
155        return null;
156    }
157
158    @Override
159    public boolean isCompatible(Unit<?> that) {
160        // TODO Auto-generated method stub
161        return false;
162    }
163
164    @Override
165    public <T extends Quantity<T>> Unit<T> asType(Class<T> type) throws ClassCastException {
166        // TODO Auto-generated method stub
167        return null;
168    }
169
170    @Override
171    public UnitConverter getConverterTo(Unit<Q> that) throws UnconvertibleException {
172        // TODO Auto-generated method stub
173        return null;
174    }
175
176    @Override
177    public UnitConverter getConverterToAny(Unit<?> that) throws IncommensurableException, UnconvertibleException {
178        // TODO Auto-generated method stub
179        return null;
180    }
181
182    @Override
183    public Unit<Q> alternate(String symbol) {
184        // TODO Auto-generated method stub
185        return null;
186    }
187
188    @Override
189    public Unit<Q> shift(double offset) {
190        // TODO Auto-generated method stub
191        return null;
192    }
193
194    @Override
195    public Unit<Q> multiply(double multiplier) {
196        // TODO Auto-generated method stub
197        return null;
198    }
199
200    @Override
201    public Unit<?> multiply(Unit<?> multiplier) {
202        // TODO Auto-generated method stub
203        return null;
204    }
205
206    @Override
207    public Unit<?> inverse() {
208        return this;
209    }
210
211    @Override
212    public Unit<Q> divide(double divisor) {
213        return this;
214    }
215
216    @Override
217    public Unit<?> divide(Unit<?> divisor) {
218        return this;
219    }
220
221    @Override
222    public Unit<?> root(int n) {
223        return this;
224    }
225
226    @Override
227    public Unit<?> pow(int n) {
228        return this;
229    }
230
231    @Override
232    public Unit<Q> transform(UnitConverter operation) {
233        return this;
234    }
235
236    @Override
237    public Unit<Q> prefix(Prefix prefix) {
238        return this.multiply(Math.pow(prefix.getValue().doubleValue(), prefix.getExponent()));
239    }
240    
241    public Unit<Q> mix(Unit<Q> that) {
242        return new MixedUnit<Q>(this, that);
243    }
244    
245    /**
246     * Returns the standard representation of this physics unit. The string produced
247     * for a given unit is always the same; it is not affected by the locale. It can
248     * be used as a canonical string representation for exchanging units, or as a
249     * key for a Hashtable, etc.
250     *
251     * Locale-sensitive unit parsing could be handled using {@link LocalUnitFormat}
252     * in subclasses of AbstractUnit.
253     *
254     * @return <code>SimpleUnitFormat.getInstance().format(this)</code>
255     */
256    @Override
257    public String toString() {
258        return SimpleUnitFormat.getInstance().format(this);
259    }
260
261        @Override
262        public Unit<Q> shift(Number offset) {
263                return this;
264        }
265
266        @Override
267        public Unit<Q> multiply(Number multiplier) {
268                return this;
269        }
270
271        @Override
272        public Unit<Q> divide(Number divisor) {
273                return this;
274        }
275
276        @Override
277        public boolean isEquivalentTo(Unit<Q> that) {
278                return equals(that);
279        }
280}