/**
* @copyright 2015 Tridium, Inc. All Rights Reserved.
* @author Gareth Johnson
*/
/**
* Defines {@link baja.Double}.
* @module baja/obj/Double
*/
define([ 'bajaScript/sys',
'bajaScript/baja/obj/numberUtil',
'bajaScript/baja/obj/objUtil' ], function (
baja,
numberUtil,
objUtil) {
'use strict';
var floatingPointToString = numberUtil.floatingPointToString,
oldNumberToString = Number.prototype.toString;
/**
* The native JavaScript Number constructor. BajaScript extends it to add
* Niagara-related functionality: {@link baja.Double}
*
* @external Number
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number Number}
*/
/**
* Represents a `baja:Double` in BajaScript.
*
* Augments `Number` to be a Baja `Double`. ECMAScript only has one numeric
* type for Doubles, Floats, Longs and Integers. Therefore, this type
* naturally maps to `baja:Double`.
*
* @class
* @alias baja.Double
* @extends external:Number
*/
var BDouble = Number;
/**
* Default `Number` instance.
* @type {Number}
*/
BDouble.DEFAULT = 0;
/**
* Make a `Number`.
*
* @param {Number} num - the number value.
*
* @returns {Number}
*/
BDouble.make = function (num) {
return Number(num);
};
/**
* Make a `Number`.
*
* @param {Number} num - the number value.
*
* @returns {Number}
*/
BDouble.prototype.make = function (num) {
return Number.make(num);
};
/**
* Decode a `Number` from a `String`.
*
* @param {String} str - an encoded `Number`.
*
* @returns {Number}
*/
BDouble.prototype.decodeFromString = function (str) {
switch (str) {
case "0": return 0;
// Infinity and NaN
case '+inf': return Number.POSITIVE_INFINITY;
case '-inf': return Number.NEGATIVE_INFINITY;
case 'nan': return Number.NaN; // Workaround for JsLint
default: return Number(str);
}
};
BDouble.prototype.decodeAsync = function (str) {
return this.decodeFromString(str);
};
/**
* Encode the `Number` (itself) to a `String`.
*
* @returns {String}
*/
BDouble.prototype.encodeToString = function () {
var num = this.valueOf();
// Infinity and NaN
if (num === Number.POSITIVE_INFINITY) { return '+inf'; }
if (num === Number.NEGATIVE_INFINITY) { return '-inf'; }
if (isNaN(num)) { return 'nan'; }
return uppercaseExponent(String(num));
};
/**
* Return the data type symbol.
*
* Used for encoding this data type (primarily for facets).
*
* @returns {String}
*/
BDouble.prototype.getDataTypeSymbol = function () {
return "d";
};
/**
* Equality test.
*
* @param obj
*
* @returns {Boolean}
*/
BDouble.prototype.equals = function (obj) {
return objUtil.valueOfEquals(this, obj);
};
/**
* Equivalence test.
*
* Used to compare if two objects have equivalent state, but might not want to
* return true for equals since it it has implied semantics for many
* operations. The default implementation returns the result of
* <code>equals()</code>.
*
* @param obj
*
* @returns {Boolean}
*/
BDouble.prototype.equivalent = function (obj) {
return objUtil.equalsEquivalent(this, obj);
};
/**
* New Copy.
*
* @returns {Number}
*/
BDouble.prototype.newCopy = function (exact) {
return objUtil.valueOfNewCopy(this, exact);
};
/**
* Return the Object's Icon.
*
* @returns {baja.Icon}
*/
BDouble.prototype.getIcon = function () {
return objUtil.objectGetIcon(this);
};
/**
* Return the `Number` (itself).
*
* @returns {Number}
*/
BDouble.prototype.getNumber = function () {
return this.valueOf();
};
/**
* Returns the `Number` (itself).
* @returns {Number}
*/
BDouble.prototype.getNumeric = function () {
return this.valueOf();
};
/**
* Return a `Number` from a BINumeric.
*
* @returns {Number}
*/
BDouble.getNumberFromINumeric = function (numeric) {
var type = numeric.getType(),
out;
if (typeof numeric.getNumeric === "function") {
return numeric.getNumeric();
}
if (type.isComplex()) {
out = numeric.get("out");
if (out && out.getType().is("baja:StatusNumeric")) {
return out.getValue().valueOf();
} else {
var value = numeric.get('value');
if (baja.hasType(value, 'baja:Number')) {
return +value;
}
}
}
if (type.is("baja:Number")) {
return numeric.valueOf();
} else if (typeof numeric.getNumber === "function") {
return numeric.getNumber();
}
if (numeric.getType().is("baja:Simple")) {
var encodedValue = numeric.encodeToString(),
result = baja.Double.DEFAULT.decodeFromString(encodedValue);
if (!isNaN(result) || [ "nan", "+inf", "-inf" ].includes(encodedValue)) {
return result;
}
}
return 0;
};
/**
* Return facets from an INumeric
*
* @param {baja.Value} numeric
* @returns {baja.Facets}
*/
BDouble.getFacetsFromINumeric = function (numeric) {
// First check if getNumericFacets is available
if (typeof numeric.getNumericFacets === 'function') {
return numeric.getNumericFacets();
}
if (baja.hasType(numeric, 'baja:StatusNumeric')) {
return baja.Facets.NULL;
}
// Next check the 'out' and 'facets' slots
return baja.Facets.getFacetsFromObject(numeric);
};
/**
* Return the `String` representation of the `Double` (itself).
*
* @param {baja.Facets|Object} [cx] - used to specify formatting facets. The
* argument can also be an Object Literal.
*
* @param {Boolean} [cx.forceSign] - specifying 'true' will concatenate a '+'
* to the beginning of the number if positive.
*
* @param {Number} [cx.precision] - the number of decimal places to show in
* the return string. Specifying '0' will also remove the decimal. If a context
* is provided without precision, this value will default to 2. If no context
* is provided, there will be no precision applied.
*
* @param {Boolean} [cx.showSeparators] - include separators.
*
* @param {baja.Unit} [cx.units] - the baja Unit to apply to the return
* string.
*
* @param {baja.Enum|Number|String} [cx.unitConversion] - the
* `baja:UnitConversion` enum, an ordinal, or tag. If omitted, the
* user-configured `baja.getUnitConversion()` will be used.
*
* @param {Number} [cx.zeroPad] - the minimum number of the whole-number
* digits to be displayed, filling in zeroes when necessary.
*
* @param {boolean} [cx.trimTrailingZeros] - set to true if trailing zeros
* should not be included in the string. If the only digits after the decimal
* point are zeros, the decimal point will be removed as well.
*
* @returns {String|Promise.<String>} returns a Promise if a cx is passed in.
*/
BDouble.prototype.toString = function (cx) {
if (!cx || typeof cx === 'number') {
return uppercaseExponent(oldNumberToString.apply(this, arguments));
}
if (cx instanceof baja.Facets) {
cx = cx.toObject();
}
return floatingPointToString(this, cx);
};
function uppercaseExponent(str) {
//BDouble will not accept lowercase exponents
return str.replace(/e([+-])/, function (match, sign) {
return 'E' + sign;
});
}
return BDouble;
});