1 /*
  2  * DigitalStorageUnit.js - Unit conversions for Digital Storage
  3  *
  4  * Copyright © 2014-2015, 2018 JEDLSoft
  5  *
  6  * Licensed under the Apache License, Version 2.0 (the "License");
  7  * you may not use this file except in compliance with the License.
  8  * You may obtain a copy of the License at
  9  *
 10  *     http://www.apache.org/licenses/LICENSE-2.0
 11  *
 12  * Unless required by applicable law or agreed to in writing, software
 13  * distributed under the License is distributed on an "AS IS" BASIS,
 14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15  *
 16  * See the License for the specific language governing permissions and
 17  * limitations under the License.
 18  */
 19 
 20 /*
 21 !depends
 22 Measurement.js
 23 JSUtils.js
 24 */
 25 
 26 var Measurement = require("./Measurement.js");
 27 var JSUtils = require("./JSUtils.js");
 28 
 29 /**
 30  * @class
 31  * Create a new DigitalStorage measurement instance.
 32  *
 33  * @constructor
 34  * @extends Measurement
 35  * @param options {{unit:string,amount:number|string|undefined}} Options controlling
 36  * the construction of this instance
 37  */
 38 var DigitalStorageUnit = function (options) {
 39     this.unit = "byte";
 40     this.amount = 0;
 41 
 42     this.ratios = DigitalStorageUnit.ratios;
 43     this.aliases = DigitalStorageUnit.aliases;
 44     this.aliasesLower = DigitalStorageUnit.aliasesLower;
 45     this.systems = DigitalStorageUnit.systems;
 46 
 47     this.parent.call(this, options);
 48 };
 49 
 50 DigitalStorageUnit.prototype = new Measurement();
 51 DigitalStorageUnit.prototype.parent = Measurement;
 52 DigitalStorageUnit.prototype.constructor = DigitalStorageUnit;
 53 
 54 DigitalStorageUnit.ratios = {
 55     /*            #    bit             byte            kb              kB              mb              mB              gb               gB               tb               tB               pb               pB   */
 56     "bit":      [ 1,   1,              0.125,          0.0009765625,   1.220703125e-4, 9.536743164e-7, 1.192092896e-7, 9.313225746e-10, 1.164153218e-10, 9.094947017e-13, 1.136868377e-13, 8.881784197e-16, 1.110223025e-16 ],
 57     "byte":     [ 2,   8,              1,              0.0078125,      0.0009765625,   7.629394531e-6, 9.536743164e-7, 7.450580597e-9,  9.313225746e-10, 7.275957614e-12, 9.094947017e-13, 7.105427358e-15, 8.881784197e-16 ],
 58     "kilobit":  [ 3,   1024,           128,            1,              0.125,          0.0009765625,   1.220703125e-4, 9.536743164e-7,  1.192092896e-7,  9.313225746e-10, 1.164153218e-10, 9.094947017e-13, 1.136868377e-13 ],
 59     "kilobyte": [ 4,   8192,           1024,           8,              1,              0.0078125,      0.0009765625,   7.629394531e-6,  9.536743164e-7,  7.450580597e-9,  9.313225746e-10, 7.275957614e-12, 9.094947017e-13 ],
 60     "megabit":  [ 5,   1048576,        131072,         1024,           128,            1,              0.125,          0.0009765625,    1.220703125e-4,  9.536743164e-7,  1.192092896e-7,  9.313225746e-10, 1.164153218e-10 ],
 61     "megabyte": [ 6,   8388608,        1048576,        8192,           1024,           8,              1,              0.0078125,       0.0009765625,    7.629394531e-6,  9.536743164e-7,  7.450580597e-9,  9.313225746e-10 ],
 62     "gigabit":  [ 7,   1073741824,     134217728,      1048576,        131072,         1024,           128,            1,               0.125,           0.0009765625,    1.220703125e-4,  9.536743164e-7,  1.192092896e-7  ],
 63     "gigabyte": [ 8,   8589934592,     1073741824,     8388608,        1048576,        8192,           1024,           8,               1,               0.0078125,       0.0009765625,    7.629394531e-6,  9.536743164e-7  ],
 64     "terabit":  [ 9,   1.099511628e12, 137438953472,   1073741824,     134217728,      1048576,        131072,         1024,            128,             1,               0.125,           0.0009765625,    1.220703125e-4  ],
 65     "terabyte": [ 10,  8.796093022e12, 1.099511628e12, 8589934592,     1073741824,     8388608,        1048576,        8192,            1024,            8,               1,               0.0078125,       0.0009765625    ],
 66     "petabit":  [ 11,  1.125899907e15, 1.407374884e14, 1.099511628e12, 137438953472,   1073741824,     134217728,      1048576,         131072,          1024,            128,             1,               0.125           ],
 67     "petabyte": [ 12,  9.007199255e15, 1.125899907e15, 8.796093022e12, 1.099511628e12, 8589934592,     1073741824,     8388608,         1048576,         8192,            1024,            8,               1               ]
 68 };
 69 
 70 /**
 71  * Return a new instance of this type of measurement.
 72  *
 73  * @param {Object} params parameters to the constructor
 74  * @return {Measurement} a measurement subclass instance
 75  */
 76 DigitalStorageUnit.prototype.newUnit = function(params) {
 77     return new DigitalStorageUnit(params);
 78 };
 79 
 80 DigitalStorageUnit.systems = {
 81     "metric": [],
 82     "uscustomary": [],
 83     "imperial": [],
 84     "conversions": {
 85         "metric": {},
 86         "uscustomary": {},
 87         "imperial": {}
 88     }
 89 };
 90 
 91 DigitalStorageUnit.bitSystem = [
 92     "bit",
 93     "kilobit",
 94     "megabit",
 95     "gigabit",
 96     "terabit",
 97     "petabit"
 98 ];
 99 DigitalStorageUnit.byteSystem = [
100     "byte",
101     "kilobyte",
102     "megabyte",
103     "gigabyte",
104     "terabyte",
105     "petabyte"
106 ];
107 
108 /**
109  * Return the type of this measurement. Examples are "mass",
110  * "length", "speed", etc. Measurements can only be converted
111  * to measurements of the same type.<p>
112  *
113  * The type of the units is determined automatically from the
114  * units. For example, the unit "grams" is type "mass". Use the
115  * static call {@link Measurement.getAvailableUnits}
116  * to find out what units this version of ilib supports.
117  *
118  * @return {string} the name of the type of this measurement
119  */
120 DigitalStorageUnit.prototype.getMeasure = function() {
121     return "digitalStorage";
122 };
123 
124 /**
125  * Localize the measurement to the commonly used measurement in that locale. For example
126  * If a user's locale is "en-US" and the measurement is given as "60 kmh",
127  * the formatted number should be automatically converted to the most appropriate
128  * measure in the other system, in this case, mph. The formatted result should
129  * appear as "37.3 mph".
130  *
131  * @param {string} locale current locale string
132  * @returns {Measurement} a new instance that is converted to locale
133  */
134 DigitalStorageUnit.prototype.localize = function(locale) {
135     return new DigitalStorageUnit({
136         unit: this.unit,
137         amount: this.amount
138     });
139 };
140 
141 /**
142  * Scale the measurement unit to an acceptable level. The scaling
143  * happens so that the integer part of the amount is as small as
144  * possible without being below zero. This will result in the
145  * largest units that can represent this measurement without
146  * fractions. Measurements can only be scaled to other measurements
147  * of the same type.
148  *
149  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
150  * or undefined if the system can be inferred from the current measure
151  * @param {Object=} units mapping from the measurement system to the units to use
152  * for this scaling. If this is not defined, this measurement type will use the
153  * set of units that it knows about for the given measurement system
154  * @return {Measurement} a new instance that is scaled to the
155  * right level
156  */
157 DigitalStorageUnit.prototype.scale = function(measurementsystem, units) {
158     var mSystem, systemName = this.getMeasurementSystem();
159     if (units) {
160         mSystem = units[systemName];
161     } else {
162         if (JSUtils.indexOf(DigitalStorageUnit.byteSystem, this.unit) > -1) {
163             mSystem = DigitalStorageUnit.byteSystem;
164         } else {
165             mSystem = DigitalStorageUnit.bitSystem;
166         }
167     }
168 
169     return this.newUnit(this.scaleUnits(mSystem));
170 };
171 
172 /**
173  * Expand the current measurement such that any fractions of the current unit
174  * are represented in terms of smaller units in the same system instead of fractions
175  * of the current unit. For example, "6.25 feet" may be represented as
176  * "6 feet 4 inches" instead. The return value is an array of measurements which
177  * are progressively smaller until the smallest unit in the system is reached
178  * or until there is a whole number of any unit along the way.
179  *
180  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
181  * or undefined if the system can be inferred from the current measure
182  * @param {Object=} units mapping from the measurement system to the units to use
183  * for this scaling. If this is not defined, this measurement type will use the
184  * set of units that it knows about for the given measurement system
185  * @return {Array.<Measurement>} an array of new measurements in order from
186  * the current units to the smallest units in the system which together are the
187  * same measurement as this one
188  */
189 DigitalStorageUnit.prototype.expand = function(measurementsystem, units) {
190     var mSystem, systemName = this.getMeasurementSystem();
191     if (units) {
192         mSystem = units[systemName];
193     } else {
194         if (this.unit in DigitalStorageUnit.byteSystem) {
195             mSystem = DigitalStorageUnit.byteSystem;
196         } else {
197             mSystem = DigitalStorageUnit.bitSystem;
198         }
199     }
200 
201     return this.list(mSystem, DigitalStorageUnit.ratios).map(function(item) {
202         return new DigitalStorageUnit(item);
203     });
204 };
205 
206 
207 DigitalStorageUnit.aliases = {
208     "bits": "bit",
209     "bit": "bit",
210     "Bits": "bit",
211     "Bit": "bit",
212     "byte": "byte",
213     "bytes": "byte",
214     "Byte": "byte",
215     "Bytes": "byte",
216     "kilobits": "kilobit",
217     "Kilobits": "kilobit",
218     "KiloBits": "kilobit",
219     "kiloBits": "kilobit",
220     "kilobit": "kilobit",
221     "Kilobit": "kilobit",
222     "kiloBit": "kilobit",
223     "KiloBit": "kilobit",
224     "kb": "kilobit",
225     "Kb": "kilobit",
226     "kilobyte": "kilobyte",
227     "Kilobyte": "kilobyte",
228     "kiloByte": "kilobyte",
229     "KiloByte": "kilobyte",
230     "kilobytes": "kilobyte",
231     "Kilobytes": "kilobyte",
232     "kiloBytes": "kilobyte",
233     "KiloBytes": "kilobyte",
234     "kB": "kilobyte",
235     "KB": "kilobyte",
236     "megabit": "megabit",
237     "Megabit": "megabit",
238     "megaBit": "megabit",
239     "MegaBit": "megabit",
240     "megabits": "megabit",
241     "Megabits": "megabit",
242     "megaBits": "megabit",
243     "MegaBits": "megabit",
244     "Mb": "megabit",
245     "mb": "megabit",
246     "megabyte": "megabyte",
247     "Megabyte": "megabyte",
248     "megaByte": "megabyte",
249     "MegaByte": "megabyte",
250     "megabytes": "megabyte",
251     "Megabytes": "megabyte",
252     "megaBytes": "megabyte",
253     "MegaBytes": "megabyte",
254     "MB": "megabyte",
255     "mB": "megabyte",
256     "gigabit": "gigabit",
257     "Gigabit": "gigabit",
258     "gigaBit": "gigabit",
259     "GigaBit": "gigabit",
260     "gigabits": "gigabit",
261     "Gigabits": "gigabit",
262     "gigaBits": "gigabyte",
263     "GigaBits": "gigabit",
264     "Gb": "gigabit",
265     "gb": "gigabit",
266     "gigabyte": "gigabyte",
267     "Gigabyte": "gigabyte",
268     "gigaByte": "gigabyte",
269     "GigaByte": "gigabyte",
270     "gigabytes": "gigabyte",
271     "Gigabytes": "gigabyte",
272     "gigaBytes": "gigabyte",
273     "GigaBytes": "gigabyte",
274     "GB": "gigabyte",
275     "gB": "gigabyte",
276     "terabit": "terabit",
277     "Terabit": "terabit",
278     "teraBit": "terabit",
279     "TeraBit": "terabit",
280     "terabits": "terabit",
281     "Terabits": "terabit",
282     "teraBits": "terabit",
283     "TeraBits": "terabit",
284     "tb": "terabit",
285     "Tb": "terabit",
286     "terabyte": "terabyte",
287     "Terabyte": "terabyte",
288     "teraByte": "terabyte",
289     "TeraByte": "terabyte",
290     "terabytes": "terabyte",
291     "Terabytes": "terabyte",
292     "teraBytes": "terabyte",
293     "TeraBytes": "terabyte",
294     "TB": "terabyte",
295     "tB": "terabyte",
296     "petabit": "petabit",
297     "Petabit": "petabit",
298     "petaBit": "petabit",
299     "PetaBit": "petabit",
300     "petabits": "petabit",
301     "Petabits": "petabit",
302     "petaBits": "petabit",
303     "PetaBits": "petabit",
304     "pb": "petabit",
305     "Pb": "petabit",
306     "petabyte": "petabyte",
307     "Petabyte": "petabyte",
308     "petaByte": "petabyte",
309     "PetaByte": "petabyte",
310     "petabytes": "petabyte",
311     "Petabytes": "petabyte",
312     "petaBytes": "petabyte",
313     "PetaBytes": "petabyte",
314     "PB": "petabyte",
315     "pB": "petabyte"
316 };
317 
318 (function() {
319     DigitalStorageUnit.aliasesLower = {};
320     for (var a in DigitalStorageUnit.aliases) {
321         DigitalStorageUnit.aliasesLower[a.toLowerCase()] = DigitalStorageUnit.aliases[a];
322     }
323 })();
324 
325 /**
326  * Convert a digitalStorage to another measure.
327  * @static
328  * @param to {string} unit to convert to
329  * @param from {string} unit to convert from
330  * @param digitalStorage {number} amount to be convert
331  * @returns {number|undefined} the converted amount
332  */
333 DigitalStorageUnit.convert = function(to, from, digitalStorage) {
334     from = Measurement.getUnitIdCaseInsensitive(DigitalStorageUnit, from) || from;
335     to = Measurement.getUnitIdCaseInsensitive(DigitalStorageUnit, to) || to;
336     var fromRow = DigitalStorageUnit.ratios[from];
337     var toRow = DigitalStorageUnit.ratios[to];
338     if (typeof(from) === 'undefined' || typeof(to) === 'undefined') {
339         return undefined;
340     }
341     var result = digitalStorage * fromRow[toRow[0]];
342     return result;
343 };
344 
345 /**
346  * @private
347  * @static
348  */
349 DigitalStorageUnit.getMeasures = function () {
350     return Object.keys(DigitalStorageUnit.ratios);
351 };
352 
353 //register with the factory method
354 Measurement._constructors["digitalStorage"] = DigitalStorageUnit;
355 
356 module.exports = DigitalStorageUnit;
357