baja/ord/HistoryScheme.js

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

/**
 * Defines {@link baja.HistoryScheme}.
 * @module baja/ord/HistoryScheme
 */
define([ "bajaScript/sys",
        "bajaScript/baja/ord/OrdQuery",
        "bajaScript/baja/ord/OrdScheme",
        "bajaScript/baja/ord/OrdTarget",
        "bajaScript/baja/ord/ordUtil" ], function (
        baja, 
        OrdQuery, 
        OrdScheme, 
        OrdTarget,
        ordUtil) {
  
  "use strict";
  
  var subclass = baja.subclass,
      callSuper = baja.callSuper,
      trimToStart = ordUtil.trimToStart,
      historySpaceTypeSpec = "history:LocalHistoryDatabase",
      historySpacePromise;

  var SPACE_REGEX = /^[\^/]|^$/;
  
  /**
   * History ORD Scheme.
   * 
   * This scheme resolves to a history space.
   *
   * @class
   * @alias baja.HistoryScheme
   * @extends baja.OrdScheme
   * @private
   */    
  var HistoryScheme = function HistoryScheme() {
    callSuper(HistoryScheme, this, arguments);
  };
  
  subclass(HistoryScheme, OrdScheme);
  
  /**
   * Default History ORD Scheme instance.
   * @private
   * @type {baja.HistoryScheme}
   */
  HistoryScheme.DEFAULT = new HistoryScheme();

  function initHistorySpace() {
    if (historySpacePromise) {
      return historySpacePromise;
    }

    var historySpace;

    baja.nav.localhost.history = historySpace = baja.nav.localhost.$addChildNode(
        baja.$(historySpaceTypeSpec));  

    historySpacePromise = historySpace
      .init()
      .then(function () {
        return historySpace;
      });

    return historySpacePromise;
  }
  
  /**
   * Called when an ORD is resolved.
   *
   * @private
   *
   * @see baja.OrdScheme#resolve
   *
   * @param {module:baja/ord/OrdTarget} target  the current ORD Target.
   * @param {baja.OrdQuery} query  the ORD Query used in resolving the ORD.
   * @param {module:baja/ord/OrdQueryListCursor} cursor  the ORD Query List 
   * cursor used for helping to asynchronously resolve the ORD.
   * @param {Object} options  options used for resolving an ORD.
   */
  HistoryScheme.prototype.resolve = function (target, query, cursor, options) {
    var newTarget = new OrdTarget(target);

    function fail(err) {
      options.callback.fail(err);
    }

    if (!query.getBody()) {
      initHistorySpace()
        .then(function (histSpace) {
          newTarget.object = histSpace;
          cursor.resolveNext(newTarget, options);
        }, fail);
    } else {
      // Resolve the ORD and force it to resolve on the Server.
      baja.Ord.make(options.ord)
        .resolve({ forceServerResolve: true })
        .then(function (target) {
          newTarget = new OrdTarget(target);
          newTarget.object = target.object;
          cursor.resolveNext(newTarget, options);
        }, fail);
    }
  };
  
  /**
   * Return an ORD Query for the scheme.
   *
   * @returns {baja.OrdQuery}
   */
  HistoryScheme.prototype.parse = function (schemeName, body) {
    return historyQuery(this, schemeName, body);
  };

  function historyQuery(scheme, schemeName, body) {
    return new OrdQuery({
      scheme: scheme,
      schemeName: schemeName,
      body: body,
      isHost: false,
      isSession: false,
      normalize: function (list, index) {
        var modified;
        if (list.isSameScheme(index, index + 1)) {
          var next = list.get(index + 1);
          var nextBody = next.getBody();
          if (!isSpaceQuery(nextBody)) {
            var merged = pathNames(body).concat(pathNames(nextBody))
              .join('/').replace(/(\^)\//, function (m, s) { return s; });

            if (!body && nextBody && !nextBody.startsWith('@')) {
              merged = '/' + merged;
            }

            list.merge(index, historyQuery(scheme, schemeName, merged));
            modified = true;
          }
        }
        return trimToStart(list, index) || modified;
      }
    });
  }

  function pathNames(body) { return body ? body.split('/') : []; }

  function isSpaceQuery(body) {
    return SPACE_REGEX.exec(body);
  }

  return HistoryScheme;
});