baja/obj/Integer.js

/**
 * @copyright 2015 Tridium, Inc. All Rights Reserved.
 * @author Gareth Johnson
 */

/**
 * Defines {@link baja.Integer}.
 * @module baja/obj/Integer
 */
define([ 'bajaScript/sys',
        'bajaScript/baja/obj/Simple',
        'bajaScript/baja/obj/numberUtil',
        'bajaScript/baja/obj/objUtil' ], function (
        baja,
        Simple,
        numberUtil,
        objUtil) {
  
  'use strict';
  
  var subclass = baja.subclass,
      callSuper = baja.callSuper,
      strictArg = baja.strictArg,

      integralToString = numberUtil.integralToString,

      cacheDecode = objUtil.cacheDecode,
      cacheEncode = objUtil.cacheEncode,
      uncacheConstantEncodeDecode = objUtil.uncacheConstantEncodeDecode;
  
  /**
   * Represents a `baja:Integer` in BajaScript.
   * 
   * Boxes JavaScript `Number` to represent a `baja:Integer`.
   * 
   * When creating a `Simple`, always use the `make()` method instead of 
   * creating a new Object.
   *
   * @class
   * @alias baja.Integer
   * @extends baja.Simple
   */
  var Integer = function Integer(val) {
    callSuper(Integer, this, arguments); 
    this.$val = strictArg(val, Number);
  };
  
  subclass(Integer, Simple);
      
  /**
   * Make an `Integer`.
   *
   * @param {Number} val - the number value.
   *
   * @returns {baja.Integer}
   */
  Integer.make = function (val) {
    if (val === 0 || isNaN(val)) {
      return Integer.DEFAULT;
    }
    
    if (val >= Integer.MAX_VALUE.valueOf() || val === Number.MAX_VALUE) {
      return Integer.MAX_VALUE;
    }
    
    if (val <= Integer.MIN_VALUE.valueOf() || val === Number.MIN_VALUE) {
      return Integer.MIN_VALUE;
    }
      
    // Ensure we don't have a floating point
    val = Math.floor(val);
    
    if (val === 0) {
      return Integer.DEFAULT;
    }

    return new Integer(val);
  };
  
  /**
   * Make an `Integer`.
   *
   * @param {Number} val - the number value
   *
   * @returns {baja.Integer}
   */
  Integer.prototype.make = function (val) {
    return Integer.make(val);
  };
    
  /**
   * Decode an `Integer` from a `String`.
   *
   * @param {String} str - an encoded `Integer`.
   *
   * @returns {baja.Integer}
   */
  Integer.prototype.decodeFromString = function (str) {
    switch (str) {
    case "0": return Integer.DEFAULT;
    
    // Min and max limits
    case "max": return Integer.MAX_VALUE;
    case "min": return Integer.MIN_VALUE;
    
    default: return Integer.make(Number(str));
    }
  };
  
  /**
   * Encode the `Integer` (itself) to a `String`.
   *
   * @returns {String}
   */
  Integer.prototype.encodeToString = function () {          
    // Check range limits and NAN
    if (isNaN(this.$val)) {
      return "0";
    }
    
    if (this.$val >= Integer.MAX_VALUE.valueOf()) {
      return "max";
    }
    
    if (this.$val <= Integer.MIN_VALUE.valueOf()) {
      return "min";
    }
    
    return Math.floor(this.$val).toFixed(0);
  };
  
  /**
   * Default `Integer` instance.
   * @type {baja.Integer}
   */
  Integer.DEFAULT = uncacheConstantEncodeDecode(new Integer(0));
  
  /**
   * `Integer` Max Value.
   * @type {baja.Integer}
   */
  Integer.MAX_VALUE = uncacheConstantEncodeDecode(new Integer(2147483647));
  
  /**
   * `Integer` Min Value.
   * @type {baja.Integer}
   */
  Integer.MIN_VALUE = uncacheConstantEncodeDecode(new Integer(-2147483648));
  
  Integer.prototype.encodeToString = cacheEncode(Integer.prototype.encodeToString);
  Integer.prototype.decodeFromString = cacheDecode(Integer.prototype.decodeFromString);
      
  /**
   * Return the data type symbol.
   *
   * Used for encoding this data type (primarily for facets).
   *
   * @returns {String}
   */
  Integer.prototype.getDataTypeSymbol = function () {
    return "i";
  };

  /**
   * Equality test.
   *
   * @param obj
   *
   * @returns {Boolean}
   */
  Integer.prototype.equals = function (obj) {
    return objUtil.valueOfEquals(this, obj);
  };
  
  /**
   * Return the `Number` encapsulated in the `Integer` (itself).
   *
   * @returns {Number}
   */
  Integer.prototype.valueOf = function () {
    return this.$val;
  };
  
  /**
   * Return the `String` representation of the `Integer` (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 {Boolean} [cx.showSeparators] - include separators.
   *
   * @param {Number} [cx.radix] - specify the number base of the return string.
   *
   * @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.
   *
   * @param {Number} [cx.zeroPad] - the minimum number of the whole-number
   * digits to be displayed, filling in zeroes when necessary.
   *
   * @returns {String|Promise.<String>} returns a Promise if a cx is passed in.
   */
  Integer.prototype.toString = function (cx) {
    if (cx) {
      return integralToString(this, cx);
    }
    return this.encodeToString();
  };

  return Integer;
});