'use strict';
var Errors = require('br/Errors');
var Core = require('br/Core');
var NodeList = require('br/presenter/node/NodeList');
/**
* @module br/presenter/node/MappedNodeList
*/
/**
* @class
* @alias module:br/presenter/node/MappedNodeList
* @extends module:br/presenter/node/NodeList
*
* @classdesc
* <code>MappedNodeList</code> is a {@link module:br/presenter/node/NodeList}.
*
* <p>The <code>MappedNodeList</code> class is useful when you want to refer to items in
* a {@link module:br/presenter/node/NodeList} (which stores items in an array) using a name, rather
* than then ordinal position within the array. The mappings are only accessible via the <code>PresentationNode</code>
* representation of the list and not from the view i.e. can't refer to the mappings in templates.
*
* <p>The contents of the <code>MappedNodeList</code> class should only be modified using the {@link #updateList}
* method, and this will cause the view to immediately update to reflect the contents of the new
* Map. </p>
*
* <p>If the optional second parameter to the constructor, <code>fNodeClass</code>, is
* provided, then the <code>MappedNodeList</code> will need all the nodes it is expected to contain to be
* instances of <code>fNodeClass</code> (i.e. subclasses are allowed), otherwise it throws
* a {@link module:br/Errors/CustomError}.
* </p>
*
* @param {Map} mPresentationNodes The initial map of {@link module:br/presenter/node/PresentationNode} instances.
* @param {Function} fNodeClass (optional) The class/interface that all nodes in this list should be an instance of.
*/
function MappedNodeList(mPresentationNodes, fNodeClass) {
/** @private */
this.m_mMappings = {};
var pPresentationNodes = this._doMapping(mPresentationNodes);
NodeList.call(this, pPresentationNodes, fNodeClass);
}
Core.extend(MappedNodeList, NodeList);
/**
* Returns the string-to-node mapping. Treat as immutable.
* @type Object
*/
MappedNodeList.prototype.getPresentationNodesMap = function() {
return this.m_mMappings;
};
/**
* Updates the node list with a new Map of {@link module:br/presenter/node/PresentationNode} instances.
*
* <p>Care must be taken to always invoke this method when the contents of the node list change. The
* array returned by {@link #getPresentationNodesArray} should be treated as being immutable.</p>
*
* @param {Array} mPresentationNodes The new map of {@link module:br/presenter/node/PresentationNode} instances.
*/
MappedNodeList.prototype.updateList = function(mPresentationNodes) {
var pPresentationNodes = this._doMapping(mPresentationNodes);
NodeList.prototype.updateList.call(this, pPresentationNodes);
return this;
};
/**
* @private
*/
MappedNodeList.prototype._doMapping = function(mPresentationNodes) {
if (mPresentationNodes instanceof Array) {
throw new Errors.InvalidParametersError('Cannot use an array to update values in a MappedNodeList, use a map.');
}
this._cleanUpMappings();
var pResult = [];
for (var sKey in mPresentationNodes) {
var oNode = mPresentationNodes[sKey];
pResult.push(oNode);
this[sKey] = oNode;
this.m_mMappings[sKey] = oNode;
}
this._setPathsOfNewlyAddedNodes();
return pResult;
};
/**
* @private
*/
MappedNodeList.prototype._setPathsOfNewlyAddedNodes = function() {
if (this.getPath() !== undefined) {
for (var s in this.m_mMappings) {
if (this.m_mMappings[s].getPath() === undefined) {
this.m_mMappings[s]._$setPath(this.getPath() + '.' + s, this.__oPresenterComponent);
}
}
}
};
/**
* @private
*/
MappedNodeList.prototype._cleanUpMappings = function() {
for (var sKey in this.m_mMappings) {
if (this[sKey]) {
delete this[sKey];
}
}
this.m_mMappings = {};
};
module.exports = MappedNodeList;