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 tech.uom.lib.common.function.DescriptionSupplier;
033import tech.uom.lib.common.function.DoubleFactorSupplier;
034import tech.uom.impl.enums.DimensionalModel;
035import tech.uom.impl.enums.function.AbstractConverter;
036
037import static tech.uom.impl.enums.unit.Constants.DEG;
038
039import java.util.HashMap;
040import java.util.Map;
041
042import javax.measure.Dimension;
043import javax.measure.IncommensurableException;
044import javax.measure.Prefix;
045import javax.measure.Quantity;
046import javax.measure.UnconvertibleException;
047import javax.measure.Unit;
048import javax.measure.UnitConverter;
049import javax.measure.quantity.Temperature;
050
051/**
052 * @author Werner Keil
053 * @version 1.0, $Date: 2020-10-03 $
054 */
055public enum TemperatureUnit implements Unit<Temperature>, DoubleFactorSupplier, DescriptionSupplier {
056
057        /** Kelvin, commonly used in scientific endeavors. */
058        KELVIN(1d, 0d, null, 273.15d, 373.15d, "K", "William Thomson, 1st Baron Kelvin"),
059
060        /** Rankine, used in scientific endeavors. */
061        RANKINE(5 / 9, 0d, KELVIN, 491.67d, 671.641d, DEG + "R", "William John Macquorn Rankine"),
062
063        /** Celsius, used by most of the world's population. */
064        CELSIUS(0d, 273.15d, KELVIN, 0d, 100d, DEG + "C", "Anders Celsius"),
065
066        /** Fahrenheit, commonly used in the United States. */
067        FAHRENHEIT(0d, 459.67d, RANKINE, 32d, 212d, DEG + "F", "Daniel Gabriel Fahrenheit");
068
069        /** Units by which this temperature scale is expressed. */
070        private final String description;
071
072        private final double multFactor;
073
074        /** Freezing point of water for each temperature scale. */
075        private final double freezingPoint;
076
077        /** Boiling point of water for each temperature scale. */
078        private final double boilingPoint;
079
080        /** Name of person that this temperature scale is named for. */
081        private final String namedFor;
082
083        private final TemperatureUnit relativeTo;
084
085        // private static final Double FIVE = new Double("5");
086        // private static final Double NINE = new Double("9");
087        // private static final Double THIRTY_TWO = new Double("32");
088        // private static final Double KELVIN_CELSIUS_DELTA = new Double("273");
089        private static final double RANKINE_FAHRENHEIT_DELTA = 459.67d;
090
091        /**
092         * Constructor for TemperatureUnit that accepts key characteristics of each
093         * temperature scale.
094         *
095         * @param newFreezingPoint
096         *            Freezing point for this temperature scale.
097         * @param newBoilingPoint
098         *            Boiling point for this temperature scale.
099         * @param newUnits
100         *            Unit symbol for this temperature scale.
101         * @param newNamedFor
102         *            Name of person after which temperature scale was named.
103         */
104        private TemperatureUnit(double newMult, double shift, final TemperatureUnit rel, double newFreezingPoint,
105                        double newBoilingPoint, final String newSymbol, final String newNamedFor) {
106                this.multFactor = newMult;
107                this.relativeTo = rel;
108                this.freezingPoint = newFreezingPoint;
109                this.boilingPoint = newBoilingPoint;
110                this.description = newSymbol;
111                this.namedFor = newNamedFor;
112        }
113
114        public String getSymbol() {
115                return description;
116        }
117
118        public double getFactor() {
119                return multFactor;
120        }
121
122        public String getName() {
123                return namedFor;
124        }
125
126        public Unit<Temperature> getSystemUnit() {
127                return KELVIN;
128        }
129
130        public Map<? extends Unit<Temperature>, Integer> getBaseUnits() {
131                Map<Unit<Temperature>, Integer> prodUnits = new HashMap<Unit<Temperature>, Integer>();
132                prodUnits.put(KELVIN, Integer.valueOf(2));
133                return prodUnits;
134        }
135
136        public static TemperatureUnit getBySymbol(String symbol) {
137                if (CELSIUS.name().equals(symbol)) {
138                        return CELSIUS;
139                }
140                if (FAHRENHEIT.name().equals(symbol)) {
141                        return FAHRENHEIT;
142                }
143                return KELVIN;
144        }
145
146        public UnitConverter getConverterTo(Unit<Temperature> that) throws UnconvertibleException {
147                if ((this == that) || this.equals(that))
148                        return AbstractConverter.IDENTITY; // Shortcut.
149                Unit<Temperature> thisSystemUnit = this.getSystemUnit();
150                Unit<Temperature> thatSystemUnit = that.getSystemUnit();
151                if (!thisSystemUnit.equals(thatSystemUnit))
152                        try {
153                                return getConverterToAny(that);
154                        } catch (IncommensurableException e) {
155                                throw new UnconvertibleException(e);
156                        }
157                return that.getConverterTo(thatSystemUnit);
158        }
159
160        public UnitConverter getConverterToAny(Unit<?> that) throws IncommensurableException, UnconvertibleException {
161                if (!isCompatible(that))
162                        throw new IncommensurableException(this + " is not compatible with " + that);
163                DimensionalModel model = DimensionalModel.current();
164                return model.getDimensionalTransform(this.getSystemUnit().getDimension()); // .concatenate(this.getConverterToSI());
165        }
166
167        public Unit<Temperature> alternate(String s) {
168                return this;
169        }
170
171        public Dimension getDimension() {
172                return SimpleDimension.INSTANCE;
173        }
174
175        public Unit<?> inverse() {
176                return this;
177        }
178
179        public Unit<Temperature> divide(double v) {
180                return null; // To change body of implemented methods use File |
181                // Settings | File TemplateBuilder.
182        }
183
184        public Unit<?> divide(Unit<?> unit) {
185                return null; // To change body of implemented methods use File |
186                // Settings | File TemplateBuilder.
187        }
188
189        public boolean isCompatible(Unit<?> that) {
190                if (that instanceof TemperatureUnit)
191                        return true;
192                return false;
193        }
194
195        @SuppressWarnings({ "unchecked" })
196        public final <T extends Quantity<T>> Unit<T> asType(Class<T> type) {
197                Unit<T> metricUnit = (Unit<T>) getSystemUnit();
198                if ((metricUnit == null) || metricUnit.isCompatible(this))
199                        return (Unit<T>) this;
200                throw new ClassCastException("The unit: " + this //$NON-NLS-1$
201                                + " is not of parameterized type " + type); //$NON-NLS-1$
202        }
203
204        public Unit<Temperature> multiply(double factor) {
205                return this;
206        }
207
208        public Unit<?> multiply(Unit<?> that) {
209                return this;
210        }
211
212        public Unit<?> pow(int n) {
213                return this;
214        }
215
216        public Unit<?> root(int n) {
217                return this;
218        }
219
220        public Unit<Temperature> transform(UnitConverter operation) {
221                return this;
222        }
223
224        public Unit<Temperature> shift(double v) {
225                return this;
226        }
227
228        public String getDescription() {
229                return description;
230        }
231
232        @Override
233        public Unit<Temperature> prefix(Prefix prefix) {
234                return this.multiply(Math.pow(prefix.getValue().doubleValue(), prefix.getExponent()));
235        }
236        
237        @Override
238        public Unit<Temperature> shift(Number offset) {
239                return this;
240        }
241
242        @Override
243        public Unit<Temperature> multiply(Number multiplier) {
244                return this;
245        }
246
247        @Override
248        public Unit<Temperature> divide(Number divisor) {
249                return this;
250        }
251
252        @Override
253        public boolean isEquivalentTo(Unit<Temperature> that) {
254                return equals(that);
255        }
256}