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.quantity.time;
031
032import static tech.units.indriya.unit.Units.DAY;
033import static tech.units.indriya.unit.Units.HOUR;
034import static tech.units.indriya.unit.Units.MINUTE;
035import static tech.units.indriya.unit.Units.SECOND;
036
037import java.math.BigDecimal;
038import java.time.Duration;
039import java.time.temporal.ChronoUnit;
040import java.time.temporal.TemporalAmount;
041import java.time.temporal.TemporalUnit;
042import java.util.Objects;
043
044import javax.measure.IncommensurableException;
045import javax.measure.Quantity;
046import javax.measure.UnconvertibleException;
047import javax.measure.Unit;
048import javax.measure.UnitConverter;
049import javax.measure.quantity.Frequency;
050import javax.measure.quantity.Time;
051
052import tech.units.indriya.AbstractQuantity;
053import tech.units.indriya.ComparableQuantity;
054import tech.units.indriya.quantity.Quantities;
055import tech.units.indriya.unit.Units;
056
057/**
058 * Class that represents {@link TemporalUnit} in Unit-API
059 * 
060 * @author Werner Keil
061 * @version 1.0.2
062 * @since 1.0
063 */
064public final class TemporalQuantity extends AbstractQuantity<Time> {
065        /**
066         * 
067         */
068        private static final long serialVersionUID = 6835738653744691425L;
069
070        private final TemporalUnit timeUnit;
071        private final Integer value;
072        private final TemporalAmount amount;
073
074        /**
075         * creates the {@link TemporalQuantity} using {@link TemporalUnit} and
076         * {@link Integer}
077         * 
078         * @param timeUnit - time to be used
079         * @param value    - value to be used
080         */
081        TemporalQuantity(Integer value, TemporalUnit timeUnit) {
082                super(toUnit(timeUnit));
083                this.timeUnit = timeUnit;
084                this.amount = Duration.of(value, timeUnit);
085                this.value = value;
086        }
087
088        /**
089         * creates the {@link TemporalQuantity} using {@link TemporalUnit} and
090         * {@link Integer}
091         * 
092         * @param value    - value to be used
093         * @param timeUnit - time to be used
094         */
095        public static TemporalQuantity of(Integer number, TemporalUnit timeUnit) {
096                return new TemporalQuantity(Objects.requireNonNull(number), Objects.requireNonNull(timeUnit));
097        }
098
099        /**
100         * Creates a {@link TemporalQuantity} based a {@link Quantity<Time>} converted
101         * to {@link Units#SECOND}.
102         * 
103         * @param quantity - quantity to be used
104         * @return the {@link TemporalQuantity} converted be quantity in seconds.
105         */
106        public static TemporalQuantity of(Quantity<Time> quantity) {
107                Quantity<Time> seconds = Objects.requireNonNull(quantity).to(SECOND);
108                return new TemporalQuantity(seconds.getValue().intValue(), ChronoUnit.SECONDS);
109        }
110
111        /**
112         * get to {@link TemporalAmount}
113         * 
114         * @return the TemporalAmount
115         */
116        public TemporalAmount getTemporalAmount() {
117                return amount;
118        }
119
120        /**
121         * get to {@link TemporalUnit}
122         * 
123         * @return the TemporalUnit
124         */
125        public TemporalUnit getTemporalUnit() {
126                return timeUnit;
127        }
128
129        /**
130         * get value expressed in {@link Integer}
131         * 
132         * @return the value
133         */
134        public Integer getValue() {
135                return value;
136        }
137
138        /**
139         * converts the {@link TemporalUnit} to {@link Unit}
140         * 
141         * @return the {@link TemporalQuantity#getTemporalUnit()} converted to Unit
142         */
143        public Unit<Time> toUnit() {
144                return toUnit(timeUnit);
145        }
146
147        /**
148         * Converts the {@link TemporalQuantity} to {@link Quantity<Time>}
149         * 
150         * @return this class converted to Quantity
151         */
152        public Quantity<Time> toQuantity() {
153                return Quantities.getQuantity(value, toUnit());
154        }
155
156        public TemporalQuantity to(TemporalUnit timeUnit) {
157                Quantity<Time> time = toQuantity().to(toUnit(timeUnit));
158                return new TemporalQuantity(time.getValue().intValue(), timeUnit);
159        }
160
161        private static Unit<Time> toUnit(TemporalUnit timeUnit) {
162                if (timeUnit instanceof ChronoUnit) {
163                        ChronoUnit chronoUnit = (ChronoUnit) timeUnit;
164                        switch (chronoUnit) {
165                        case MICROS:
166                                return TimeQuantities.MICROSECOND;
167                        case MILLIS:
168                                return TimeQuantities.MILLISECOND;
169                        case NANOS:
170                                return TimeQuantities.NANOSECOND;
171                        case SECONDS:
172                                return SECOND;
173                        case MINUTES:
174                                return MINUTE;
175                        case HOURS:
176                                return HOUR;
177                        case DAYS:
178                                return DAY;
179                        default:
180                                throw new IllegalArgumentException(
181                                                "TemporalQuantity only supports DAYS, HOURS, MICROS, MILLIS, MINUTES, NANOS, SECONDS ");
182                        }
183                } else {
184                        throw new IllegalArgumentException("TemporalQuantity only supports temporal units of type ChronoUnit");
185
186                }
187        }
188
189        @Override
190        public int hashCode() {
191                return Objects.hash(timeUnit, value);
192        }
193
194        @Override
195        public boolean equals(Object obj) {
196                if (this == obj) {
197                        return true;
198                }
199                if (TemporalQuantity.class.isInstance(obj)) {
200                        TemporalQuantity other = TemporalQuantity.class.cast(obj);
201                        return Objects.equals(timeUnit, other.timeUnit) && Objects.equals(value, other.value);
202                }
203                if (obj instanceof Quantity<?>) {
204                        Quantity<?> that = (Quantity<?>) obj;
205                        return Objects.equals(getUnit(), that.getUnit()) && Equalizer.hasEquality(value, that.getValue());
206                }
207                return super.equals(obj);
208        }
209
210        @Override
211        public String toString() {
212                return "Temporal unit:" + timeUnit + " value: " + value;
213        }
214
215        @Override
216        public ComparableQuantity<Time> add(Quantity<Time> that) {
217                if (getUnit().equals(that.getUnit())) {
218                        return TimeQuantities.getQuantity(value + that.getValue().intValue(), timeUnit);
219                }
220                Quantity<Time> converted = that.to(getUnit());
221                return TimeQuantities.getQuantity(value + converted.getValue().intValue(), timeUnit);
222        }
223
224        @Override
225        public ComparableQuantity<Time> subtract(Quantity<Time> that) {
226                if (getUnit().equals(that.getUnit())) {
227                        return TimeQuantities.getQuantity(value - that.getValue().intValue(), timeUnit);
228                }
229                Quantity<Time> converted = that.to(getUnit());
230                return TimeQuantities.getQuantity(value - converted.getValue().intValue(), timeUnit);
231        }
232
233        @Override
234        public ComparableQuantity<?> divide(Quantity<?> that) {
235                if (getUnit().equals(that.getUnit())) {
236                        return TimeQuantities.getQuantity(value / that.getValue().intValue(), timeUnit);
237                }
238                Unit<?> divUnit = getUnit().divide(that.getUnit());
239                UnitConverter conv;
240                try {
241                        conv = getUnit().getConverterToAny(divUnit);
242                        return TimeQuantities.getQuantity(value / conv.convert(that.getValue()).intValue(), timeUnit);
243                } catch (UnconvertibleException e) {
244                        // TODO Auto-generated catch block
245                        e.printStackTrace();
246                        return TimeQuantities.getQuantity(value / that.getValue().intValue(), timeUnit);
247                } catch (IncommensurableException e) {
248                        // TODO Auto-generated catch block
249                        e.printStackTrace();
250                        return TimeQuantities.getQuantity(value / that.getValue().intValue(), timeUnit);
251                }
252        }
253
254        @Override
255        public ComparableQuantity<Time> divide(Number that) {
256                return TimeQuantities.getQuantity(value / that.intValue(), timeUnit);
257        }
258
259        @Override
260        public ComparableQuantity<?> multiply(Quantity<?> multiplier) {
261                if (getUnit().equals(multiplier.getUnit())) {
262                        return TimeQuantities.getQuantity(value * multiplier.getValue().intValue(), timeUnit);
263                }
264                Unit<?> mulUnit = getUnit().multiply(multiplier.getUnit());
265                UnitConverter conv;
266                try {
267                        conv = getUnit().getConverterToAny(mulUnit);
268                        return TimeQuantities.getQuantity(value * conv.convert(multiplier.getValue()).intValue(), timeUnit);
269                } catch (UnconvertibleException e) {
270                        // TODO Auto-generated catch block
271                        e.printStackTrace();
272                        return TimeQuantities.getQuantity(value * multiplier.getValue().intValue(), timeUnit);
273                } catch (IncommensurableException e) {
274                        // TODO Auto-generated catch block
275                        e.printStackTrace();
276                        return TimeQuantities.getQuantity(value * multiplier.getValue().intValue(), timeUnit);
277                }
278        }
279
280        @Override
281        public ComparableQuantity<Time> multiply(Number multiplier) {
282                return TimeQuantities.getQuantity(value * multiplier.intValue(), timeUnit);
283        }
284
285        @Override
286        public ComparableQuantity<Frequency> inverse() {
287                return Quantities.getQuantity(1d / value.doubleValue(), toUnit(timeUnit).inverse()).asType(Frequency.class);
288        }
289
290        @Override
291        public boolean isBig() {
292                return true; // Duration backed by BigDecimal/BigInteger
293        }
294
295        @Override
296        public BigDecimal decimalValue(Unit<Time> unit) throws ArithmeticException {
297                return BigDecimal.valueOf(value.doubleValue());
298        }
299
300        @Override
301        public double doubleValue(Unit<Time> unit) throws ArithmeticException {
302                return value.doubleValue();
303        }
304
305        /**
306         * @since 1.0.2
307         */
308        @Override
309        public Quantity<Time> negate() {
310                return of(-value, getTemporalUnit());
311        }
312}