/**
* @copyright 2020 Tridium, Inc. All Rights Reserved.
* @author Vikram Nagulan
*/
/**
* Defines {@link baja.NSpaceScheme}.
* @module baja/ord/NSpaceScheme
*/
define([
"bajaScript/sys",
"bajaScript/baja/ord/OrdQuery",
"bajaScript/baja/ord/OrdScheme",
"bajaScript/baja/ord/OrdTarget",
"bajaScript/baja/ord/SlotPath"
], function (
baja,
OrdQuery,
OrdScheme,
OrdTarget,
SlotPath
) {
'use strict';
var subclass = baja.subclass,
callSuper = baja.callSuper;
/**
* NSpace ORD Scheme.
*
* This scheme resolves to Component Space or Virtual Component Space.
*
* @class
* @alias baja.NSpaceScheme
* @extends baja.OrdScheme
* @private
*/
var NSpaceScheme = function NSpaceScheme() {
callSuper(NSpaceScheme, this, arguments);
};
subclass(NSpaceScheme, OrdScheme);
/**
* Default NSpace ORD Scheme instance.
* @private
* @type {baja.NSpaceScheme}
*/
NSpaceScheme.DEFAULT = new NSpaceScheme();
NSpaceScheme.prototype.resolve = function (target, query, cursor, options) {
var body = query.getBody();
var newTarget = new OrdTarget(target);
newTarget.object = target.object;
if (!body) {
newTarget.object = baja.nav.localhost.station;
return cursor.resolveNext(newTarget, options);
}
return baja.rpc({
typeSpec: "niagaraDriver:NiagaraNetwork",
method: "getStationSpaceOrdByName",
args: [ body ]
})
.then(function (stationSpaceOrd) {
return baja.Ord.make(stationSpaceOrd).resolve()
.then(function (target) {
newTarget.object = target.object;
return cursor.resolveNext(newTarget, options);
});
})
.catch(function (err) {
options.callback.fail(err);
});
};
/**
* Return an ORD Query for the scheme.
*
* @returns {baja.OrdQuery}
*/
NSpaceScheme.prototype.parse = function (schemeName, body) {
return new OrdQuery({
scheme: this,
schemeName: schemeName,
body: body,
isHost: false,
isSession: false,
normalize: function (list, index, cx) {
// Only when this normalize() call happens at ORD resolution time (as
// determined by the Context parameter), check to see if the OrdQuery
// immediately trailing this "nspace" one is a SlotPath (or VirtualPath).
// If so, and it's absolute, then replace it with an equivalent relative
// SlotPath. This is necessary because a trailing absolute SlotPath,
// when resolved, could clobber the virtual path ORD that gets
// substituted for this "nspace" OrdQuery at resolution time, and that's
// particularly problematic when targeting a reachable station (one that
// isn't directly specified in the local station's NiagaraNetwork).
// Since "nspace" is a space Ord scheme, it's fine to convert an
// absolute SlotPath (or VirtualPath) that immediately trails it to a
// relative one at resolution time. For compatibility reasons with
// older versions (and persisted BOrds in the old format), we don't
// want to do this conversion when normalize() is called for the non-ORD
// resolution case. For example, consider the following ORD:
//
// nspace:JaceB|slot:/a/b/c
//
// At ORD resolution time, the OrdQueries are resolved from left to
// right. If "JaceB" is a reachable station (not a direct
// BNiagaraStation child in the local NiagaraNetwork, but reachable thru
// "JaceA" which is in the local station's NiagaraNetwork), then just the
// "nspace:JaceB" part would resolve to something like:
//
// station:|slot:/Drivers/NiagaraNetwork/JaceA/virtual|virtual:/Drivers/NiagaraNetwork/JaceB/virtual/virtual
//
// If the trailing absolute SlotPath "slot:/a/b/c" was left to resolve
// after the full virtual path substituted above, it would look like this:
//
// station:|slot:/Drivers/NiagaraNetwork/JaceA/virtual|virtual:/Drivers/NiagaraNetwork/JaceB/virtual/virtual|slot:/a/b/c
//
// When resolved, because of how absolute SlotPaths clobber any
// SlotPaths (including VirtualPaths) to their left until it reaches
// a space (virtual space in this case), it would incorrectly resolve to:
//
// station:|slot:/Drivers/NiagaraNetwork/JaceA/virtual|virtual:|slot:/a/b/c
//
// That's obviously not right. Therefore we need to change the absolute
// "slot:/a/b/c" part to a relative form: "slot:a/b/c". That way the
// example ORD above will correctly resolve to the following, without
// clobbering the virtual path that was substituted for the "nspace"
// part (because relative SlotPaths don't clobber like absolute ones):
//
// station:|slot:/Drivers/NiagaraNetwork/JaceA/virtual|virtual:/Drivers/NiagaraNetwork/JaceB/virtual/virtual|slot:a/b/c
if (cx && cx === OrdQuery.RESOLVING_ORD_CX) {
var i, q, nextQuery, slotPathBody, modified = false,
nextIdx = index + 1;
if (nextIdx < list.size()) {
nextQuery = list.get(nextIdx);
if (nextQuery && nextQuery instanceof baja.SlotPath) {
slotPathBody = nextQuery.getBody();
if (nextQuery.isAbsolute()) {
if (slotPathBody && slotPathBody.startsWith('/')) {
if (slotPathBody.length === 1) {
list.set(nextIdx, new SlotPath(''));
} else {
list.set(nextIdx, nextQuery.makeSlotPath(slotPathBody.substr(1)));
}
modified = true;
}
} else if ((!slotPathBody || slotPathBody === '') && nextQuery instanceof baja.VirtualPath) {
// If the next path is simply "virtual:", then just remove it
// since this "nspace" ORD resolves to the proper virtual space
list.remove(nextIdx);
modified = true;
}
}
}
}
// Always shift to session just like the "station" component space ORD scheme
// (since "nspace" is similar in that it resolves to a virtual component
// space)
for (i = index - 1; i >= 0; --i) {
q = list.get(i);
if (!q.isHost() && !q.isSession()) {
list.remove(i);
modified = true;
}
}
return modified;
}
});
};
return NSpaceScheme;
});