baja/obj/OrdToCategoryMap.js

/**
 * @copyright 2023 Tridium, Inc. All Rights Reserved.
 */

/**
 * Defines {@link baja.OrdToCategoryMap}.
 * @private
 * @module baja/obj/OrdToCategoryMap
 */
define([
  'bajaScript/baja/obj/CategoryMask',
  'bajaScript/baja/ord/Ord',
  'bajaScript/baja/obj/Simple' ], function (
  CategoryMask,
  Ord,
  Simple) {

  'use strict';

  /**
   * @class
   * @alias module:baja/obj/OrdToCategoryMap
   * @private
   * @extends baja.Simple
   * @since Niagara 4.14
   */
  class OrdToCategoryMap extends Simple {

    /**
     * @param {Array.<object>} pairs ord/mask pairs
     */
    constructor(pairs) {
      super();
      this.$pairs = pairs;
    }

    /**
     * @param {number} i
     * @returns {baja.Ord|undefined} the ord at this index or undefined if not present
     */
    getOrd(i) {
      const pair = this.$pairs[i];
      return pair && pair.ord;
    }

    /**
     * @param {number|baja.Ord} i numeric index, or an ORD to check
     * @returns {module:baja/obj/CategoryMask|undefined} the category mask matching this index or ORD,
     * or undefined if not present
     */
    getCategoryMask(i) {
      const pairs = this.$pairs;
      let pair;
      if (typeof i === 'number') {
        pair = pairs[i];
      } else {
        // In NCCB-63126, we re-allowed some "station:" based ORDs to be case-sensitive (which
        // had been made lowercase since NCCB-56823). In order to be backwards compatible, we'll also
        // check for a lowercase match and use the lowercase match only if an exact match
        // isn't found first
        const ordStr = String(i.relativizeToSession());
        pair = pairs.find(({ $str }) => $str === ordStr);
        if (!pair) {
          const lowerCaseOrdStr = ordStr.toLowerCase();
          pair = pairs.find(({ $str }) => $str === lowerCaseOrdStr);
        }
      }
      return pair && pair.mask;
    }

    /**
     * @returns {number} the number of pairs in this map
     */
    size() {
      return this.$pairs.length;
    }

    /**
     * @returns {Array.<object>} returns ord/mask pairs
     */
    pairs() {
      return this.$pairs.slice();
    }

    /**
     * @param {object} params
     * @param {Array.<baja.Ord>} params.ords
     * @param {Array.<module:baja/obj/CategoryMask>} params.masks
     * @returns {module:baja/obj/OrdToCategoryMap}
     */
    make({ ords, masks }) {
      if (ords.length !== masks.length) {
        throw new Error('ords.length != masks.length');
      }

      if (!ords.length) {
        return OrdToCategoryMap.DEFAULT;
      }

      const pairs = ords.map((ord, i) => makePair(ord, masks[i]));
      pairs.sort((p1, p2) => p2.ord.toString().length - p1.ord.toString().length);
      return new OrdToCategoryMap(pairs);
    }

    /**
     * @returns {string}
     */
    encodeToString() {
      return this.$pairs.map(({ ord, mask }) => `${ ord }=${ mask }`).join('\n');
    }

    /**
     * @param {string} str
     * @returns {module:baja/obj/OrdToCategoryMap}
     */
    decodeFromString(str) {
      if (!str) {
        return OrdToCategoryMap.DEFAULT;
      }

      const pairs = str.split('\n').map((line) => {
        const [ , ord, mask ] = /^([^=]+)=(.*)$/.exec(line);
        return makePair(ord, CategoryMask.make(mask));
      });

      return new OrdToCategoryMap(pairs);
    }
  }

  OrdToCategoryMap.DEFAULT = new OrdToCategoryMap([]);

  function makePair(ord, mask) {
    const ordStr = String(ord);
    // NCCB-63126: ORDs that start with "station:" (e.g. virtuals) are case-sensitive, while others
    // are not (use lowercase form)
    return { ord: Ord.make(ord), mask, $str: ordStr.startsWith('station:|') ? ordStr : ordStr.toLowerCase() };
  }

  return OrdToCategoryMap;
});