1 /*
  2  * MeasurementFactory.js - Function to instantiate the appropriate subclasses of
  3  * the Measurement class.
  4  *
  5  * Copyright © 2015, 2018, JEDLSoft
  6  *
  7  * Licensed under the Apache License, Version 2.0 (the "License");
  8  * you may not use this file except in compliance with the License.
  9  * You may obtain a copy of the License at
 10  *
 11  *     http://www.apache.org/licenses/LICENSE-2.0
 12  *
 13  * Unless required by applicable law or agreed to in writing, software
 14  * distributed under the License is distributed on an "AS IS" BASIS,
 15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 16  *
 17  * See the License for the specific language governing permissions and
 18  * limitations under the License.
 19  */
 20 
 21 /*
 22 !depends
 23 UnknownUnit.js
 24 AreaUnit.js
 25 DigitalStorageUnit.js
 26 DigitalSpeedUnit.js
 27 EnergyUnit.js
 28 FuelConsumptionUnit.js
 29 LengthUnit.js
 30 MassUnit.js
 31 TemperatureUnit.js
 32 TimeUnit.js
 33 VelocityUnit.js
 34 VolumeUnit.js
 35 Measurement.js
 36 */
 37 
 38 // TODO: make these dependencies dynamic or at least generate them in the build
 39 // These will each add themselves to Measurement._constructors[]
 40 var UnknownUnit = require("./UnknownUnit.js");
 41 var AreaUnit = require("./AreaUnit.js");
 42 var DigitalStorageUnit = require("./DigitalStorageUnit.js");
 43 var DigitalSpeedUnit = require("./DigitalSpeedUnit.js");
 44 var EnergyUnit = require("./EnergyUnit.js");
 45 var FuelConsumptionUnit = require("./FuelConsumptionUnit.js");
 46 var LengthUnit = require("./LengthUnit.js");
 47 var MassUnit = require("./MassUnit.js");
 48 var TemperatureUnit = require("./TemperatureUnit.js");
 49 var TimeUnit = require("./TimeUnit.js");
 50 var VelocityUnit = require("./VelocityUnit.js");
 51 var VolumeUnit = require("./VolumeUnit.js");
 52 
 53 var Measurement = require("./Measurement.js");
 54 
 55 /**
 56  * Create a measurement subclass instance based on a particular measure
 57  * required. The measurement is immutable once
 58  * it is created, but it can be converted to other measurements later.<p>
 59  *
 60  * The options may contain any of the following properties:
 61  *
 62  * <ul>
 63  * <li><i>amount</i> - either a numeric amount for this measurement given
 64  * as a number of the specified units, or another Measurement instance
 65  * to convert to the requested units. If converting to new units, the type
 66  * of measure between the other instance's units and the current units
 67  * must be the same. That is, you can only convert one unit of mass to
 68  * another. You cannot convert a unit of mass into a unit of length.
 69  *
 70  * <li><i>unit</i> - units of this measurement. Use the
 71  * static call {@link MeasurementFactory.getAvailableUnits}
 72  * to find out what units this version of ilib supports. If the given unit
 73  * is not a base unit, the amount will be normalized to the number of base units
 74  * and stored as that number of base units.
 75  * For example, if an instance is constructed with 1 kg, this will be converted
 76  * automatically into 1000 g, as grams are the base unit and kg is merely a
 77  * commonly used scale of grams.
 78  * </ul>
 79  *
 80  * Here are some examples of converting a length into new units.
 81  * The first method is via this factory function by passing the old measurement
 82  * in as the "amount" property.<p>
 83  *
 84  * <pre>
 85  * var measurement1 = MeasurementFactory({
 86  *   amount: 5,
 87  *   units: "kilometers"
 88  * });
 89  * var measurement2 = MeasurementFactory({
 90  *   amount: measurement1,
 91  *   units: "miles"
 92  * });
 93  * </pre>
 94  *
 95  * The value in measurement2 will end up being about 3.125 miles.<p>
 96  *
 97  * The second method uses the convert method.<p>
 98  *
 99  * <pre>
100  * var measurement1 = MeasurementFactory({
101  *   amount: 5,
102  *   units: "kilometers"
103  * });
104  * var measurement2 = measurement1.convert("miles");
105  * });
106  * </pre>
107  *
108  * The value in measurement2 will again end up being about 3.125 miles.
109  *
110  * @static
111  * @param {Object=} options options that control the construction of this instance
112  */
113 var MeasurementFactory = function(options) {
114     if (!options || typeof(options.unit) === 'undefined') {
115         return undefined;
116     }
117 
118     var measurement, measure = undefined;
119 
120     // first try in the existing case
121     for (var c in Measurement._constructors) {
122         measurement = Measurement._constructors[c];
123         if (Measurement.getUnitId(measurement, options.unit)) {
124             measure = c;
125             break;
126         }
127     }
128 
129     if (!measure) {
130         // if it wasn't found before, try again in lower case -- this may recognize incorrectly because some
131         // units can differ only in their case like "mm" and "Mm"
132         for (var c in Measurement._constructors) {
133             measurement = Measurement._constructors[c];
134             if (typeof(Measurement.getUnitIdCaseInsensitive(measurement, options.unit)) !== 'undefined') {
135                 measure = c;
136                 break;
137             }
138         }
139     }
140 
141     if (!measure || typeof(measure) === 'undefined') {
142         return new UnknownUnit({
143             unit: options.unit,
144             amount: options.amount
145         });
146     } else {
147         return new Measurement._constructors[measure](options);
148     }
149 };
150 
151 /**
152  * Return a list of all possible units that this version of ilib supports.
153  * Typically, the units are given as their full names in English. Unit names
154  * are case-insensitive.
155  *
156  * @static
157  * @return {Array.<string>} an array of strings containing names of measurement
158  * units available
159  */
160 MeasurementFactory.getAvailableUnits = function () {
161     var units = [];
162     for (var c in Measurement._constructors) {
163         var measure = Measurement._constructors[c];
164         units = units.concat(measure.getMeasures());
165     }
166     return units;
167 };
168 
169 module.exports = MeasurementFactory;
170