baja/comp/Flags.js

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

/**
 * Defines {@link baja.Flags}.
 * @module baja/comp/Flags
 */
define([ "bajaScript/sys" ], function (baja) {
  
  "use strict";
  
  var BaseBajaObj = baja.BaseBajaObj,
  
      subclass = baja.subclass,
      strictArg = baja.strictArg;
  
  /**
   * Slot Flags.
   * 
   * Flags are boolean values which are stored as
   * a bitmask on each slot in a `Complex`.  Some
   * flags apply to all slot types, while some only
   * have meaning for certain slot types.
   * 
   * Flags should always be a Number. This Constructor should only be 
   * used to create new objects by Tridium developers.
   *
   * @class
   * @alias baja.Flags
   * @extends baja.BaseBajaObj
   */
  var Flags = function Flags(mask, symbol, fname) {
    this.$mask = mask;
    this.$symbol = symbol;
    this.$name = fname;
    
    // Cache this Flag via the symbol name in an Object for quick decoding
    Flags.bySymbol[symbol] = this;
  };
  
  subclass(Flags, BaseBajaObj);
  
  Flags.bySymbol = {}; // Used to quickly decode Flag Strings
  
  /**
   * Return the mask for the `Flags`.
   *
   * @returns {Number}
   */
  Flags.prototype.getMask = function () {
    return this.$mask;
  };
  
  /**
   * Return the symbol for the `Flags`.
   *
   * @returns {String}
   */
  Flags.prototype.getSymbol = function () {
    return this.$symbol;
  };
  
  /**
   * Return the `String` representation of the `Flags`.
   *
   * @returns {String}
   */
  Flags.prototype.toString = function () {
    return this.$name;
  };
  
  /**
   * Equality test.
   *
   * @param obj
   * @returns {Boolean}
   */
  Flags.prototype.equals = function (obj) { 
    return obj instanceof Flags && obj.getMask() === this.getMask();
  };
  
  /**
   * readonly flag.
   * @type {Number}
   */
  Flags.READONLY             = 0x00000001;  // 'r'
  
  /**
   * transient flag.
   * @type {Number}
   */
  Flags.TRANSIENT            = 0x00000002;  // 't'
  
  /**
   * hidden flag.
   * @type {Number}
   */
  Flags.HIDDEN               = 0x00000004;  // 'h'
  
  /**
   * summary flag.
   * @type {Number}
   */
  Flags.SUMMARY              = 0x00000008;  // 's'
  
  /**
   * async flag.
   * @type {Number}
   */
  Flags.ASYNC                = 0x00000010;  // 'a'
  
  /**
   * noRun flag.
   * @type {Number}
   */
  Flags.NO_RUN               = 0x00000020;  // 'n'
  
  /**
   * defaultOnClone flag.
   * @type {Number}
   */
  Flags.DEFAULT_ON_CLONE     = 0x00000040;  // 'd'
  
  /**
   * confirmRequired flag.
   * @type {Number}
   */
  Flags.CONFIRM_REQUIRED     = 0x00000080;  // 'c'
  
  /**
   * operator flag.
   * @type {Number}
   */
  Flags.OPERATOR             = 0x00000100;  // 'o'
  
  /**
   * executeOnChange flag.
   * @type {Number}
   */
  Flags.EXECUTE_ON_CHANGE    = 0x00000200;  // 'x'
  
  /**
   * fanIn flag.
   * @type {Number}
   */
  Flags.FAN_IN               = 0x00000400;  // 'f'
  
  /**
   * noAudit flag.
   * @type {Number}
   */
  Flags.NO_AUDIT             = 0x00000800;  // 'A'
  
  /**
   * composite flag.
   * @type {Number}
   */
  Flags.COMPOSITE            = 0x00001000;  // 'p'
  
  /**
   * removeOnClone flag.
   * @type {Number}
   */
  Flags.REMOVE_ON_CLONE      = 0x00002000;  // 'R'
  
  /**
   * metaData flag.
   * @type {Number}
   */
  Flags.METADATA             = 0x00004000;  // 'm'
  
  /**
   * linkTarget flag.
   * @type {Number}
   */
  Flags.LINK_TARGET          = 0x00008000;  // 'L'
  
  /**
   * nonCritical flag.
   * @type {Number}
   */
  Flags.NON_CRITICAL         = 0x00010000;  // 'N'
  
  /**
   * userDefined1 flag.
   * @type {Number}
   */
  Flags.USER_DEFINED_1       = 0x10000000;  // '1'
  
  /**
   * userDefined2 flag.
   * @type {Number}
   */
  Flags.USER_DEFINED_2       = 0x20000000;  // '2'
  
  /**
   * userDefined3 flag.
   * @type {Number}
   */
  Flags.USER_DEFINED_3       = 0x40000000;  // '3'
  
  /**
   * userDefined4 flag.
   * @type {Number}
   */
  Flags.USER_DEFINED_4       = 0x80000000;  // '4'
  
  Flags.flags = [ new Flags(Flags.READONLY,           "r", "readonly"),
                 new Flags(Flags.TRANSIENT,          "t", "transient"),
                 new Flags(Flags.HIDDEN,             "h", "hidden"),
                 new Flags(Flags.SUMMARY,            "s", "summary"),
                 new Flags(Flags.ASYNC,              "a", "async"),
                 new Flags(Flags.NO_RUN,             "n", "noRun"),
                 new Flags(Flags.DEFAULT_ON_CLONE,   "d", "defaultOnClone"),
                 new Flags(Flags.CONFIRM_REQUIRED,   "c", "confirmRequired"),
                 new Flags(Flags.OPERATOR,           "o", "operator"),
                 new Flags(Flags.EXECUTE_ON_CHANGE,  "x", "executeOnChange"),
                 new Flags(Flags.FAN_IN,             "f", "fanIn"),
                 new Flags(Flags.NO_AUDIT,           "A", "noAudit"),
                 new Flags(Flags.COMPOSITE,          "p", "composite"),
                 new Flags(Flags.REMOVE_ON_CLONE,    "R", "removeOnClone"),
                 new Flags(Flags.METADATA,           "m", "metadata"),
                 new Flags(Flags.NON_CRITICAL,       "N", "nonCritical"),
                 new Flags(Flags.LINK_TARGET,        "L", "linkTarget"),
                 new Flags(Flags.USER_DEFINED_1,     "1", "userDefined1"),
                 new Flags(Flags.USER_DEFINED_2,     "2", "userDefined2"),
                 new Flags(Flags.USER_DEFINED_3,     "3", "userDefined3"),
                 new Flags(Flags.USER_DEFINED_4,     "4", "userDefined4")
                ];
  
  /**
   * Encode Slot Flags to a `String`.
   *
   * @param {Number} flags the flags to be encoded.
   *
   * @returns {String}
   */  
  Flags.encodeToString = function (flags) {
    if (flags === 0) {
      return "";
    }
  
    strictArg(flags, Number);
    var s = "", i;
    for (i = 0; i < Flags.flags.length; ++i) {
      if ((Flags.flags[i].getMask() & flags) !== 0) {
        s += Flags.flags[i].getSymbol();
      }
    }
    return s;
  };  
  
  /**
   * Decode Slot Flags from a `String`.
   *
   * @param {String} flagsStr  the `Flags` encoded as a `String`.
   * @returns {Number}
   */  
  Flags.decodeFromString = function (flagsStr) {
    if (flagsStr === "0") {
      return 0;
    }
    
    strictArg(flagsStr, String);

    const { bySymbol } = Flags;
    let decodedFlags = 0;

    for (let i = 0, len = flagsStr.length; i < len; ++i) {
      // Find the flags via a Symbol look up
      const flags = bySymbol[flagsStr[i]];
      
      if (flags) {
        // Add the mask for the flag to the result
        decodedFlags |= flags.getMask();
      }
    }
    return decodedFlags;
  };
  
  return Flags;
});