baja/obj/Boolean.js

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

/**
 * Augments native Javascript {@link Boolean} class with Niagara-specific
 * functionality.
 * 
 * @module baja/obj/Boolean
 */
define([ "bajaScript/sys",
        "bajaScript/baja/obj/EnumRange",
        "bajaScript/baja/obj/Facets",
        "bajaScript/baja/obj/Format",
        "bajaScript/baja/obj/objUtil",
        "bajaPromises",
        "lex!" ], 
        function (baja, EnumRange, Facets, Format, objUtil, Promise, lexjs) {
  
  'use strict';
  
  var strictArg = baja.strictArg;
  
  /**
   * The native JavaScript Boolean constructor. BajaScript extends it to add
   * Niagara-related functionality: {@link Boolean}
   * 
   * @external Boolean
   * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean Boolean}
   */
  
  /**
   * Represents a `baja:Boolean` in BajaScript.
   * 
   * Augments `Boolean` to be a `baja:Boolean`.
   *
   * @class
   * @alias Boolean
   * @extends external:Boolean
   */
  var BBoolean = Boolean;
   
  /**
   * Default `Boolean` instance.
   */
  BBoolean.DEFAULT = false;

  /**
   * Make a `Boolean`.
   *
   * @param {Boolean} b - a JavaScript `Boolean` value.
   *
   * @returns {Boolean}
   */
  BBoolean.make = function (b) {
    if (b === undefined) {
      return Boolean.DEFAULT;
    }
    if (typeof b !== "boolean") {
      throw new Error("Must supply a Boolean when making BBoolean instances: " + b);
    }
    return b;
  };
  
  /**
   * Make a `Boolean`.
   *
   * @param {Boolean} b - a JavaScript `Boolean` value.
   * 
   * @returns {Boolean}
   */
  BBoolean.prototype.make = function (b) {
    return Boolean.make(b);
  };
  
  /**
   * Decode a `Boolean` from a `String`.
   *
   * @param {String} str - an encoded `Boolean`.
   *
   * @returns {Boolean}
   */
  BBoolean.prototype.decodeFromString = function (str) {
    return str === "true";
  };

  BBoolean.prototype.decodeAsync = function (str) {
    return this.decodeFromString(str);
  };

  /**
   * Encode the `Boolean` (itself) to a `String`.
   *
   * @returns {String}
   */
  BBoolean.prototype.encodeToString = function () {
    return this.toString();
  };
  
  /**
   * Return the data type symbol.
   *
   * Used for encoding this data type (primarily for facets).
   *
   * @returns {String}
   */
  BBoolean.prototype.getDataTypeSymbol = function () {
    return "b";
  };
      
  /**
   * Equality test.
   *
   * @param obj
   *
   * @returns {Boolean}
   */
  BBoolean.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 {@link
   * Boolean#equals}.
   *
   * @param obj
   *
   * @returns {Boolean}
   */
  BBoolean.prototype.equivalent = function (obj) {
    return objUtil.equalsEquivalent(this, obj);
  };
  
  /**
   * New Copy.
   *
   * @returns {Boolean}
   */
  BBoolean.prototype.newCopy = function (exact) {
    return objUtil.valueOfNewCopy(this, exact);
  };
   
  // Boolean Enum Methods
   
  /**
   * Return true if this `Enum` value is considered to be in an active state.
   *
   * @returns {Boolean}
   */
  BBoolean.prototype.isActive = function () {
    return this.valueOf();
  };
  
  /**
   * Return the `Enum` ordinal.
   *
   * @returns {Number}
   */
  BBoolean.prototype.getOrdinal = function () {
    return this.valueOf() ? 1 : 0;
  };
  
  /**
   * Return the `String` identifier of this `Enum` value.
   *
   * @returns {String}
   */
  BBoolean.prototype.getTag = function () {
    return this.valueOf() ? "true" : "false";
  };

  /**
   * Asynchronously get the display tag of this `Enum` value.
   * 
   * @param {Object} obj - the Object Literal used to specify the method's
   * arguments.
   * 
   * @param {baja.Facets|Object} [obj.facets] - facets used to specify the true
   * and false text. The argument can also be an Object Literal.
   *
   * @param {String} [obj.facets.trueText] - a baja Format string. If `Boolean`
   * is true, function will return baja.Format(obj.facets.trueText) instead of
   * 'true'.
   *
   * @param {String} [obj.facets.falseText] - a baja Format string. If `Boolean`
   * is false, function will return baja.Format(obj.facets.falseText) instead of
   * 'false'.

   * @param {Function} [obj.ok] - (Deprecated: use Promise) ok callback called
   * with String value as argument.
   * 
   * @param {Function} [obj.fail] - (Deprecated: use Promise) optional fail
   * callback.
   *
   * @returns {Promise.<String>}
   */
  BBoolean.prototype.getDisplayTag =   function getBooleanDisplayTag(obj) {
    obj = obj || {};

    var text,
        that = this,
        facets = obj.facets,
        df = Promise.deferred(),
        ok = function (s) { 
          (obj.ok || baja.ok)(s);
          df.resolve(s);
        },
        fail = function (err) {
          (obj.fail || baja.fail)(err);
          df.reject(err);
        };
    
    strictArg(ok, Function);

    
    if (facets) {
      if (that.valueOf()) {
        text = facets instanceof Facets ? facets.get("trueText") : facets.trueText;
      } else {
        text = facets instanceof Facets ? facets.get("falseText") : facets.falseText;
      }
    }
    
    if (text) {
      // Handle Format text
      Format.format({
        pattern: text,
        ok: ok,
        fail: fail
      });
    } else {
      // Handle standard lexicon text fetch
      lexjs.module("baja")
        .then(function (lex) {
          ok(lex.get(that.getTag()));
        }, fail);
    }

    return df.promise();
  };
    
  /**
   * Return the `Enum Range`.
   *
   * @returns {baja.EnumRange}
   */
  BBoolean.prototype.getRange = function () {
    return EnumRange.BOOLEAN_RANGE;
  };
    
  // TODO: What about encoding/decoding numbers from different locales?
  // How does this work in JavaScript?
  
  /**
   * Return the Object's Icon.
   *
   * @returns {baja.Icon}
   */
  BBoolean.prototype.getIcon = function () {
    return objUtil.objectGetIcon(this);
  };
  
  /**
   * Return the `Boolean` (itself).
   *
   * @returns {Boolean}
   */
  BBoolean.prototype.getBoolean = function () {
    return this.valueOf();
  };
  
  /**
   * Return the `Boolean` (itself).
   *
   * @function
   *
   * @returns {Boolean}
   */
  BBoolean.prototype.getEnum = BBoolean.prototype.getBoolean;
  
  /**
   * Return a `Boolean` from a BIBoolean.
   *
   * @param {baja.Value} iBoolean any value type implementing BIBoolean
   * @returns {Boolean}
   */
  BBoolean.getBooleanFromIBoolean = function (iBoolean) {
    if (typeof iBoolean.getBoolean === "function") {
      return !!iBoolean.getBoolean();
    }

    var type = iBoolean.getType();
    
    if (type.isComplex()) {
      var out = iBoolean.get("out");
      if (out && out.getType().is("baja:StatusBoolean")) {
        return out.getValue();
      }

      var value = iBoolean.get('value');
      if (baja.hasType(value, 'baja:Boolean')) {
        return value;
      }
    } else if (type.is("baja:Boolean")) {
      return iBoolean.valueOf();
    } else if (type.is('baja:Simple')) {
      if (iBoolean.encodeToString() === 'true') { return true; }
   }

    // Make sure we return a boolean
    return false;
  };

  /**
   * Return facets from an IBoolean
   * 
   * @param {baja.Value} boolVal 
   * @returns {baja.Facets}
   */
  BBoolean.getFacetsFromIBoolean = function (boolVal) {
    // First check if getBooleanFacets is available
    if (typeof boolVal.getBooleanFacets === 'function') {
      return boolVal.getBooleanFacets();
    }

    if (baja.hasType(boolVal, 'baja:StatusBoolean')) {
      return baja.Facets.NULL;
    }

    // Next check the 'out' and 'facets' slots
    return baja.Facets.getFacetsFromObject(boolVal);
  };

  /**
   * Returns a string representation of the `Boolean` (itself).
   *
   * @param {baja.Facets|Object} [cx] - used to specify formatting facets. The
   * argument can also be an Object Literal.
   *
   * @param {String} [cx.trueText] - a baja Format string. If `Boolean` is true,
   * function will return baja.Format(cx.trueText) instead of 'true'.
   *
   * @param {String} [cx.falseText] - a baja Format string. If `Boolean` is
   * false, function will return baja.Format(cx.falseText) instead of 'false'.
   *
   * @returns {String|Promise.<String>} returns a Promise if a cx is passed in.
   */
  BBoolean.prototype.toString = function (cx) {
    if (cx) {
      return this.getDisplayTag({ facets: cx });
    }
    return this.getTag();
  };
  
  return BBoolean;
});