001/*
002 * Units of Measurement Reference Implementation
003 * Copyright (c) 2005-2020, Units of Measurement project.
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;
031
032import static javax.measure.Quantity.Scale.ABSOLUTE;
033
034import java.math.BigDecimal;
035import java.math.BigInteger;
036import java.util.Objects;
037
038import javax.measure.MeasurementException;
039import javax.measure.Quantity;
040import javax.measure.Quantity.Scale;
041import javax.measure.Unit;
042import javax.measure.format.MeasurementParseException;
043
044import tech.units.indriya.ComparableQuantity;
045import tech.units.indriya.format.AbstractQuantityFormat;
046import tech.units.indriya.format.SimpleQuantityFormat;
047import tech.units.indriya.function.MixedRadix;
048
049/**
050 * Singleton class for accessing {@link Quantity} instances.
051 * 
052 * @version 1.10, April 20, 2019
053 * @author keilw
054 * @author otaviojava
055 * @since 1.0
056 */
057public final class Quantities {
058        /**
059         * Private singleton constructor.
060         */
061        private Quantities() {
062        }
063
064        /**
065         * Returns the {@link #valueOf(java.math.BigDecimal, javax.measure.unit.Unit)
066         * decimal} quantity of unknown type corresponding to the specified
067         * representation. This method can be used to parse dimensionless
068         * quantities.<br>
069         * <code>
070         *     Quantity<Dimensionless> proportion = Quantities.getQuantity("0.234").asType(Dimensionless.class);
071         * </code>
072         *
073         * <p>
074         * Note: This method handles only Locale-neutral quantity formatting and parsing
075         * are handled by the {@link AbstractQuantityFormat} class and its subclasses.
076         * </p>
077         *
078         * @param csq the decimal value and its unit (if any) separated by space(s).
079         * @return <code>QuantityFormat.getInstance(LOCALE_NEUTRAL).parse(csq)</code>
080         */
081        public static Quantity<?> getQuantity(CharSequence csq) {
082                try {
083                        return SimpleQuantityFormat.getInstance("n u~ ").parse(csq);
084                } catch (MeasurementParseException e) {
085                        throw new IllegalArgumentException(e.getParsedString());
086                }
087        }
088
089        /**
090         * Returns the scalar quantity. When the {@link Number} was {@link BigDecimal}
091         * or {@link BigInteger} will uses {@link DecimalQuantity}, when the
092         * {@link Number} was {@link Double} will {@link DoubleQuantity} otherwise will
093         * {@link NumberQuantity}. in the specified unit.
094         * 
095         * @param value the measurement value.
096         * @param unit  the measurement unit.
097         * @param scale the measurement scale.
098         * @return the corresponding <code>numeric</code> quantity.
099         * @throws NullPointerException if value, unit or scale were null
100         * @throws MeasurementException if unit is a MixedUnit
101         * @since 2.0
102         */
103        public static <Q extends Quantity<Q>> ComparableQuantity<Q> getQuantity(Number value, Unit<Q> unit, Scale scale) {
104                Objects.requireNonNull(value);
105                Objects.requireNonNull(unit);
106                Objects.requireNonNull(scale);
107                return new NumberQuantity<>(value, unit, scale);
108        }
109
110        /**
111         * Returns the scalar quantity. When the {@link Number} was {@link BigDecimal}
112         * or {@link BigInteger} will uses {@link DecimalQuantity}, when the
113         * {@link Number} was {@link Double} will {@link DoubleQuantity} otherwise will
114         * {@link NumberQuantity}. in the specified unit.
115         * 
116         * @param value the measurement value.
117         * @param unit  the measurement unit.
118         * @return the corresponding <code>numeric</code> quantity.
119         * @throws NullPointerException when value or unit were null
120         */
121        public static <Q extends Quantity<Q>> ComparableQuantity<Q> getQuantity(Number value, Unit<Q> unit) {
122                return getQuantity(value, unit, ABSOLUTE);
123        }
124
125        /**
126         * Returns the mixed radix values and units combined into a single quantity.
127         * When the {@link Number} was {@link BigDecimal} or {@link BigInteger} will
128         * uses {@link DecimalQuantity}, when the {@link Number} was {@link Double} will
129         * {@link DoubleQuantity} otherwise will {@link NumberQuantity}. in the
130         * specified unit.
131         * 
132         * @param values the measurement values.
133         * @param units  the measurement units.
134         * @param scale  the measurement scale.
135         * @return the corresponding quantity.
136         * @throws NullPointerException     if value or scale were null
137         * @throws IllegalArgumentException if the size of the values array does not
138         *                                  match that of units.
139         * @since 2.0
140         */
141        public static <Q extends Quantity<Q>> Quantity<Q> getQuantity(Number[] values, Unit<Q>[] units, Scale scale) {
142                if (values.length == units.length) {
143                        return MixedRadix.of(units).createQuantity(values, scale);
144                } else {
145                        throw new IllegalArgumentException(
146                                        String.format("%s values don't match %s units", values.length, units.length));
147                }
148        }
149
150        /**
151         * Returns the mixed radix values and units combined into a single quantity in
152         * the {@code ABSOLUTE} scale.
153         * 
154         * @param values the measurement values.
155         * @param units  the measurement units.
156         * @return the corresponding quantity.
157         * @throws NullPointerException     if value or unit were null
158         * @throws IllegalArgumentException if the size of the values array does not
159         *                                  match that of units.
160         * @since 2.0
161         */
162        @SafeVarargs
163        public static <Q extends Quantity<Q>> Quantity<Q> getQuantity(Number[] values, Unit<Q>... units) {
164                return getQuantity(values, units, ABSOLUTE);
165        }
166
167        /**
168         * Returns the mixed radix values and units as {@link CompoundQuantity} in the
169         * specified scale.
170         * 
171         * @param values the measurement values.
172         * @param units  the measurement units.
173         * @param scale  the measurement scale.
174         * @return the corresponding compound quantity.
175         * @throws NullPointerException     if values, units or scale were null
176         * @throws IllegalArgumentException if the size of the values array does not
177         *                                  match that of units.
178         * @since 2.0
179         */
180        public static <Q extends Quantity<Q>> CompoundQuantity<Q> getCompoundQuantity(Number[] values, Unit<Q>[] units,
181                        Scale scale) {
182                if (values.length == units.length) {
183                        return MixedRadix.of(units).createCompoundQuantity(values, scale);
184                } else {
185                        throw new IllegalArgumentException(
186                                        String.format("%s values don't match %s units", values.length, units.length));
187                }
188        }
189
190        /**
191         * Returns the mixed radix values and units as {@link CompoundQuantity} in the
192         * {@code ABSOLUTE} scale.
193         * 
194         * @param values the measurement values.
195         * @param units  the measurement units.
196         * @return the corresponding compound quantity.
197         * @throws NullPointerException     if values, units or scale were null
198         * @throws IllegalArgumentException if the size of the values array does not
199         *                                  match that of units.
200         * @since 2.0
201         */
202        public static <Q extends Quantity<Q>> CompoundQuantity<Q> getCompoundQuantity(final Number[] values,
203                        final Unit<Q>[] units) {
204                return getCompoundQuantity(values, units, ABSOLUTE);
205        }
206}