1 /* 2 * MeasurementFactory.js - Function to instantiate the appropriate subclasses of 3 * the Measurement class. 4 * 5 * Copyright © 2015, 2018, 2022 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 ilib = require("../index.js"); 41 var UnknownUnit = require("./UnknownUnit.js"); 42 var AreaUnit = require("./AreaUnit.js"); 43 var DigitalStorageUnit = require("./DigitalStorageUnit.js"); 44 var DigitalSpeedUnit = require("./DigitalSpeedUnit.js"); 45 var EnergyUnit = require("./EnergyUnit.js"); 46 var ForceUnit = require("./ForceUnit.js"); 47 var PowerUnit = require("./PowerUnit.js"); 48 var PressureUnit = require("./PressureUnit.js"); 49 var FuelConsumptionUnit = require("./FuelConsumptionUnit.js"); 50 var LengthUnit = require("./LengthUnit.js"); 51 var MassUnit = require("./MassUnit.js"); 52 var TemperatureUnit = require("./TemperatureUnit.js"); 53 var TimeUnit = require("./TimeUnit.js"); 54 var VelocityUnit = require("./VelocityUnit.js"); 55 var VolumeUnit = require("./VolumeUnit.js"); 56 57 var Measurement = require("./Measurement.js"); 58 59 /** 60 * Create a measurement subclass instance based on a particular measure 61 * required. The measurement is immutable once 62 * it is created, but it can be converted to other measurements later.<p> 63 * 64 * The options may contain any of the following properties: 65 * 66 * <ul> 67 * <li><i>amount</i> - either a numeric amount for this measurement given 68 * as a number of the specified units, or another Measurement instance 69 * to convert to the requested units. If converting to new units, the type 70 * of measure between the other instance's units and the current units 71 * must be the same. That is, you can only convert one unit of mass to 72 * another. You cannot convert a unit of mass into a unit of length. 73 * 74 * <li><i>unit</i> - units of this measurement. Use the 75 * static call {@link MeasurementFactory.getAvailableUnits} 76 * to find out what units this version of ilib supports. If the given unit 77 * is not a base unit, the amount will be normalized to the number of base units 78 * and stored as that number of base units. 79 * For example, if an instance is constructed with 1 kg, this will be converted 80 * automatically into 1000 g, as grams are the base unit and kg is merely a 81 * commonly used scale of grams. 82 * </ul> 83 * 84 * Here are some examples of converting a length into new units. 85 * The first method is via this factory function by passing the old measurement 86 * in as the "amount" property.<p> 87 * 88 * <pre> 89 * var measurement1 = MeasurementFactory({ 90 * amount: 5, 91 * units: "kilometers" 92 * }); 93 * var measurement2 = MeasurementFactory({ 94 * amount: measurement1, 95 * units: "miles" 96 * }); 97 * </pre> 98 * 99 * The value in measurement2 will end up being about 3.125 miles.<p> 100 * 101 * The second method uses the convert method.<p> 102 * 103 * <pre> 104 * var measurement1 = MeasurementFactory({ 105 * amount: 5, 106 * units: "kilometers" 107 * }); 108 * var measurement2 = measurement1.convert("miles"); 109 * }); 110 * </pre> 111 * 112 * The value in measurement2 will again end up being about 3.125 miles. 113 * 114 * @static 115 * @param {Object=} options options that control the construction of this instance 116 */ 117 var MeasurementFactory = function(options) { 118 if (!options || typeof(options.unit) === 'undefined') { 119 return undefined; 120 } 121 122 var measurement, measure = undefined; 123 var c; 124 // first try in the existing case 125 for (c in Measurement._constructors) { 126 measurement = Measurement._constructors[c]; 127 if (Measurement.getUnitId(measurement, options.unit)) { 128 measure = c; 129 break; 130 } 131 } 132 133 if (!measure) { 134 // if it wasn't found before, try again in lower case -- this may recognize incorrectly because some 135 // units can differ only in their case like "mm" and "Mm" 136 for (c in Measurement._constructors) { 137 measurement = Measurement._constructors[c]; 138 if (typeof(Measurement.getUnitIdCaseInsensitive(measurement, options.unit)) !== 'undefined') { 139 measure = c; 140 break; 141 } 142 } 143 } 144 145 if (!measure || typeof(measure) === 'undefined') { 146 return new UnknownUnit({ 147 unit: options.unit, 148 amount: options.amount 149 }); 150 } else { 151 return new Measurement._constructors[measure](options); 152 } 153 }; 154 155 /** 156 * Return a list of all possible units that this version of ilib supports. 157 * Typically, the units are given as their full names in English. Unit names 158 * are case-insensitive. 159 * 160 * @static 161 * @return {Array.<string>} an array of strings containing names of measurement 162 * units available 163 */ 164 MeasurementFactory.getAvailableUnits = function () { 165 var units = []; 166 for (var c in Measurement._constructors) { 167 var measure = Measurement._constructors[c]; 168 units = units.concat(measure.getMeasures()); 169 } 170 return units; 171 }; 172 173 module.exports = MeasurementFactory; 174