/**
* @copyright 2015 Tridium, Inc. All Rights Reserved.
* @author Gareth Johnson
*/
/**
* Defines {@link baja.HierarchyScheme}.
* @module baja/ord/HierarchyScheme
*/
define([
'bajaPromises',
"bajaScript/sys",
"bajaScript/baja/ord/Ord",
"bajaScript/baja/ord/OrdCoalescer",
"bajaScript/baja/ord/OrdQuery",
"bajaScript/baja/ord/OrdScheme",
"bajaScript/baja/ord/OrdTarget",
"bajaScript/baja/ord/SlotPath",
"bajaScript/baja/ord/ordUtil" ], function (
Promise,
baja,
Ord,
OrdCoalescer,
OrdQuery,
OrdScheme,
OrdTarget,
SlotPath,
ordUtil) {
"use strict";
var subclass = baja.subclass,
callSuper = baja.callSuper,
trimToStart = ordUtil.trimToStart,
hierarchySpaceTypeSpec = "hierarchy:HierarchySpace",
hierarchyLevelElemTypeSpec = "hierarchy:LevelElem",
virtualComponentTypeSpec = "baja:VirtualComponent";
/**
* Before resolving any hierarchy: ORD, the hierarchy space must be resolved
* and associated type specs must be loaded. In turn, this will lazily resolve
* the BajaScript library for managing hierarchies from the hierarchy module
* (HierarchySpace Type Extension).
* @function
*/
var ensureSpaceResolved = (function () {
var prom;
return function () {
return prom || (prom = baja.Ord.make("hierarchy:")
.resolve({ forceServerResolve: true })
.then(function () {
return baja.importTypes({
typeSpecs: [
hierarchySpaceTypeSpec,
hierarchyLevelElemTypeSpec,
virtualComponentTypeSpec
]
});
}));
};
}());
// will coalesce all duplicate hierarchy: ord requests
var coalescer = new OrdCoalescer({ delay: 0 });
coalescer.$batchResolve = function (params) {
// hierarchy ords need forceServerResolve but BatchResolve doesn't support
// this, so resolve them one by one. it's the same amount of network calls
// either way.
var ords = params.ords;
var subscriber = params.subscriber;
return Promise.all(ords.map(function (ord) {
return baja.Ord.make(ord).resolve({
forceServerResolve: true,
subscriber: subscriber
})
.catch(function (err) { return err; });
}));
};
/**
* Hierarchy ORD Scheme.
*
* This ORD scheme is used for resolving Niagara 4 hierarchies. The hierarchy
* module must be installed on the Station in order for this to successfully
* resolve.
*
* @class
* @alias baja.HierarchyScheme
* @extends baja.OrdScheme
* @private
*/
var HierarchyScheme = function HierarchyScheme() {
callSuper(HierarchyScheme, this, arguments);
};
subclass(HierarchyScheme, OrdScheme);
/**
* Default Handle ORD Scheme instance
* @private
* @type {baja.HierarchyScheme}
*/
HierarchyScheme.DEFAULT = new HierarchyScheme();
/**
* 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.
*/
HierarchyScheme.prototype.resolve = function (target, query, cursor, options) {
ensureSpaceResolved()
.then(function () {
resolveHierarchy(target, query, cursor, options);
})
.catch(function (err) {
return options.callback.fail(err);
});
};
function resolveHierarchy(target, query, cursor, options) {
// Create the hierarchy space node if it does not exist already
if (!baja.nav.localhost.hierarchy) {
baja.nav.localhost.hierarchy = baja.nav.localhost.$addChildNode(
baja.$(hierarchySpaceTypeSpec));
}
var newTarget = new OrdTarget(target);
if (!query.getBody()) {
newTarget.object = baja.nav.localhost.hierarchy;
cursor.resolveNext(newTarget, options);
} else {
// We used to short-circuit if the last item in the query body started with "station:|". This
// would, however, resolve a component even if the user did not have permission to view the
// hierarchy listed at the beginning of the query body. We did not want to add another
// network call just to check the user's permissions on a particular hierarchy. Also, we did
// not want to start caching hierarchy space nav children at this time. That would possibly
// prevent a network call: if the hierarchy is in the nav children, go ahead and
// short-circuit. But, refreshing this nav child cache would have to be considered.
// Resolve the ORD and force it to resolve on the Server.
coalescer.resolve(query.toString())
.then(function (target) {
newTarget = new OrdTarget(target);
newTarget.object = target.object;
cursor.resolveNext(newTarget, options);
})
.catch(function (err) {
options.callback.fail(err);
});
}
}
/**
* Return an ORD Query for the scheme.
*
* @returns {baja.OrdQuery}
*/
HierarchyScheme.prototype.parse = function (schemeName, body) {
return hierarchyQuery(this, schemeName, body);
};
function hierarchyQuery(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 sp1 = new SlotPath(body);
var sp2 = new SlotPath(list.get(index + 1).getBody());
list.merge(index, hierarchyQuery(scheme, schemeName, sp1.merge(sp2)));
modified = true;
}
return trimToStart(list, index) || modified;
}
});
}
return HierarchyScheme;
});