PointMgrModel.js

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

/**
 * @module nmodule/driver/rc/wb/mgr/PointMgrModel
 */

define([ 'baja!',
        'underscore',
        'Promise',
        'nmodule/webEditors/rc/wb/mgr/MgrTypeInfo',
        'nmodule/webEditors/rc/wb/mgr/model/folderMgrModelMixin',
        'nmodule/webEditors/rc/wb/mgr/model/MgrModel',
        'nmodule/webEditors/rc/wb/table/model/Row',
        'nmodule/webEditors/rc/wb/table/model/source/ContainerComponentSource',
        'baja!control:ControlPoint,driver:ProxyExt' ], function (
        baja,
        _,
        Promise,
        MgrTypeInfo,
        addFolderMgrModelMixin,
        MgrModel,
        Row,
        ContainerComponentSource) {

  'use strict';

  var CONTROL_POINT = 'control:ControlPoint',
      BOOLEAN_POINT = 'control:BooleanPoint',
      BOOLEAN_WRITABLE = 'control:BooleanWritable',
      NUMERIC_POINT = 'control:NumericPoint',
      NUMERIC_WRITABLE = 'control:NumericWritable',
      STRING_POINT = 'control:StringPoint',
      STRING_WRITABLE = 'control:StringWritable',
      ENUM_POINT = 'control:EnumPoint',
      ENUM_WRITABLE = 'control:EnumWritable',
      PROXY_EXT = 'driver:ProxyExt',

      CHANGE_EVENT_THROTTLE_MS = 1000;

  /**
   * Default filter for the component source if one is not specified by the
   * constructor parameters coming from a derived class. This function will
   * filter BControlPoint derived classes with a driver:ProxyExt derived
   * extension. Points configured with non-driver types of proxy ext that derive
   * directly from control:AbstractProxyExt (such as control:NullProxyExt) are not
   * returned by the filter. If a folder type was specified, folders of that
   * type will be returned too.
   *
   * @param {Object} params - parameters passed to the model constructor.
   * @returns {Function} a function used by the component source when filtering slots.
   */
  function makeDefaultSourceFilter(params) {
    var folderType = params.folderType,
        proxyExtType = params.proxyExtType || PROXY_EXT;

    return function (prop, value) {
      var type = prop.getType(),
          ext;

      if (prop.getFlags() & baja.Flags.HIDDEN) { return false; }

      if (type.is(CONTROL_POINT)) {
        ext = value && value.getProxyExt();
        return !!(ext && ext.getType().is(proxyExtType));
      }

      return !!(folderType && type.is(folderType));
    };
  }

  /**
   * API Status: **Development**
   * 
   * A `MgrModel` type for a `PointMgr` derived type as an agent on a driver's
   * BPointDeviceExt type.
   *
   * @class
   * @alias module:nmodule/driver/rc/wb/mgr/PointMgrModel
   * @extends module:nmodule/webEditors/rc/wb/mgr/model/MgrModel
   *
   * @param {Object} params object containing the constructor parameters
   * @param {baja.Component} params.component the component containing the points to
   * be shown in the manager, typically a device's point ext or a point folder.
   * @param {string|Type} [params.folderType] optional parameter indicating the folder
   * type for the manager. This will be used by the 'new folder' command.
   */
  var PointMgrModel = function PointMgrModel(params) {
    var that = this,
        folderType = params.folderType;

    MgrModel.call(that, _.extend({
      componentSource: new ContainerComponentSource({
        container: params.component,
        filter: params.filter || makeDefaultSourceFilter(params)
      }),
      rowsChangedEventDelay: CHANGE_EVENT_THROTTLE_MS
    }, params));

    if (folderType) {
      addFolderMgrModelMixin(that, { folderType: folderType });
    }

    this.$proxyExtType = params.proxyExtType;
  };

  PointMgrModel.prototype = Object.create(MgrModel.prototype);
  PointMgrModel.prototype.constructor = PointMgrModel;

  /**
   * Get the display name from the display name of the root component container.
   * This is used for the title of the tab in the HTML5 hx profile.
   */
  PointMgrModel.prototype.getNavDisplayName = function () {
    return this.getComponentSource().getContainer().getNavDisplayName();
  };

////////////////////////////////////////////////////////////////
// Point Types
////////////////////////////////////////////////////////////////

  /**
   * Return `MgrTypeInfo` instances for the default new types for a point manager.
   * This includes writable and non-writable versions of the four basic point
   * data types (boolean, numeric, enum, string).
   *
   * @static
   * @returns {Promise.<Array.<module:nmodule/webEditors/rc/wb/mgr/MgrTypeInfo>>}
   */
  PointMgrModel.getDefaultNewTypes = function () {
    var types = [];

    PointMgrModel.addBooleanPointTypes(true, types);
    PointMgrModel.addNumericPointTypes(true, types);
    PointMgrModel.addEnumPointTypes(true, types);
    PointMgrModel.addStringPointTypes(true, types);

    return MgrTypeInfo.make(types);
  };

  /**
   * Add the boolean point types to the given array. If the writable parameter
   * is false, the writable boolean type will not be added.
   *
   * @static
   * @param {boolean} writable If true, will add the BooleanWritable type to the array.
   * @param {Array} types An array of that will have the numeric types appended.
   * If not specified, a new array will be created and returned.
   * @returns The provided array or a new one containing the appropriate boolean point types.
   */
  PointMgrModel.addBooleanPointTypes = function (writable, types) {
    return addStandardPointTypes(BOOLEAN_POINT, BOOLEAN_WRITABLE, writable, types);
  };

  /**
   * Add the standard numeric point types to the given array. If the writable parameter
   * is false, the writable numeric type will not be added.
   *
   * @static
   * @param {boolean} writable If true, will add the NumericWritable type to the array.
   * @param {Array} types An array of that will have the numeric types appended.
   * If not specified, a new array will be created and returned.
   * @returns The provided array or a new one containing the appropriate numeric point types.
   */
  PointMgrModel.addNumericPointTypes = function (writable, types) {
    return addStandardPointTypes(NUMERIC_POINT, NUMERIC_WRITABLE, writable, types);
  };

  /**
   * Add the standard enum point types to the given array. If the writable parameter
   * is false, the writable enum type will not be added.
   *
   * @static
   * @param {boolean} writable If true, will add the EnumWritable type to the array.
   * @param {Array} types An array of that will have the numeric types appended.
   * If not specified, a new array will be created and returned.
   * @returns The provided array or a new one containing the appropriate enum point types.
   */
  PointMgrModel.addEnumPointTypes = function (writable, types) {
    return addStandardPointTypes(ENUM_POINT, ENUM_WRITABLE, writable, types);
  };

  /**
   * Add the standard numeric point types to the given array. If the writable parameter
   * is false, the writable numeric type will not be added.
   *
   * @static
   * @param {boolean} writable If true, will add the StringWritable type to the array.
   * @param {Array} types An array of that will have the numeric types appended.
   * If not specified, a new array will be created and returned.
   * @returns The provided array or a new one containing the appropriate numeric point types.
   */
  PointMgrModel.addStringPointTypes = function (writable, types) {
    return addStandardPointTypes(STRING_POINT, STRING_WRITABLE, writable, types);
  };

  /**
   * Function to add a standard readable point type to an array (e.g. NumericPoint)
   * and optionally the corresponding writable type, if the writable parameter is true.
   */
  function addStandardPointTypes(readableType, writableType, writable, types) {
    types = types || [];
    writable = !!writable;

    if (!Array.isArray(types)) {
      types = [ types ];
    }

    if (writable) { types.push(writableType); }
    types.push(readableType);

    return types;
  }

  /**
   * Return the proxy extension type used by the concrete driver implementation. This
   * is used by the default implementation of the `#newInstance()` function.
   *
   * @returns {string|Type}
   */
  PointMgrModel.prototype.getProxyExtType = function () {
    return this.$proxyExtType;
  };

////////////////////////////////////////////////////////////////
// New Point Instances
////////////////////////////////////////////////////////////////

  /**
   * Override point to customize how new instances of the selected type spec
   * are instantiated. The default implementation will create a point and proxy ext
   * using the type specified by the getProxyExtType() function.
   *
   * @param {module:nmodule/webEditors/rc/wb/mgr/MgrTypeInfo} typeInfo
   * @returns {baja.Value|Promise}
   */
  PointMgrModel.prototype.newInstance = function (typeInfo) {
    var that = this,
        point;

    return typeInfo.newInstance()
      .then(function (comp) {
        point = comp;
        return point.setProxyExt(baja.$(that.getProxyExtType())); // TODO : should this pass the new instance (or at least its type) through to getProxyExtType()?
      })
      .then(function () {
        return point;
      });
  };

////////////////////////////////////////////////////////////////
// Row & Column
////////////////////////////////////////////////////////////////

  /**
   * Make a row for the given subject with the appropriate icon for the row. Overrides
   * TableModel.makeRow().
   *
   * @override
   * @param subject The subject of the row. Should be a point or folder instance.
   * @returns {module:nmodule/webEditors/rc/wb/table/model/Row}
   */
  PointMgrModel.prototype.makeRow = function (subject) {
    return new Row(subject, subject.getNavIcon());
  };

  return PointMgrModel;
});