'use strict';
var Snapshot = require('br/presenter/property/Snapshot');
var WritableProperty = require('br/presenter/property/WritableProperty');
var Property = require('br/presenter/property/Property');
var PropertyListener = require('br/presenter/property/PropertyListener');
var ListenerFactory = require('br/util/ListenerFactory');
var ListenerCompatUtil = require('../util/ListenerCompatUtil');
/**
* @module br/presenter/property/Properties
*/
/**
* Constructs a new <code>Properties</code> instance containing the given list
* of {@link module:br/presenter/property/Property} objects.
*
* @class
* @alias module:br/presenter/property/Properties
*
* @classdesc
* A class used to hold collections of properties, and providing utility methods for
* performing operations over those collections.
*
* @param {Array} pProperties (optional) The initial set of properties.
*/
function Properties(pProperties) {
/** @private */
this.m_pProperties = pProperties || [];
/** @private */
this.m_oChangeListenerFactory = new ListenerFactory(PropertyListener, 'onPropertyChanged');
/** @private */
this.m_oUpdateListenerFactory = new ListenerFactory(PropertyListener, 'onPropertyUpdated');
}
/**
* Add the given properties to this collection.
*
* The single argument passed to <code>add()</code> can be any of the following types:
*
* <ul>
* <li>A single {@link module:br/presenter/property/Property} instance.</li>
* <li>An array of {@link module:br/presenter/property/Property} instances.</li>
* <li>Another <code>Properties</code> object.</li>
* </ul>
*
* @param {Object} vProperties The new properties to add.
*/
Properties.prototype.add = function(vProperties) {
if (vProperties instanceof Array) {
this._addPropertyArray(vProperties);
} else if (vProperties instanceof Property) {
this._addPropertyArray([vProperties]);
} else if (vProperties instanceof Properties) {
this._addPropertyArray(vProperties.m_pProperties);
} else {
throw 'br.presenter.property.Properties.prototype.add() unknown type';
}
};
/**
* Returns array of properties in the collection.
*
* @type Array
*/
Properties.prototype.getProperties = function() {
return this.m_pProperties.slice(0);
};
/**
* Returns the size of the collection.
*
* @type int
*/
Properties.prototype.getSize = function() {
return this.m_pProperties.length;
};
/**
* Invoke <code>setValue()</code> on all writable properties within the collection.
*
* @param {Object} vValue The value that all property instances will be set to.
*/
Properties.prototype.setValue = function(vValue) {
for (var i = 0; i < this.m_pProperties.length; i++) {
var oProperty = this.m_pProperties[i];
if (oProperty instanceof WritableProperty) {
oProperty.setValue(vValue);
}
}
};
/**
* Returns a snapshot of the current collection that can be restored at a later date.
*
* @type br.presenter.property.Snapshot
*/
Properties.prototype.snapshot = function() {
return new Snapshot(this.m_pProperties);
};
/**
* Add a listener to all properties
*/
Properties.prototype.addListener = function(oListener, bNotifyImmediately) {
for (var i = 0, l = this.m_pProperties.length; i < l; i++) {
var bLastProperty = i == (l - 1);
this.m_pProperties[i].addListener(oListener, bNotifyImmediately && bLastProperty);
}
};
/**
* Removes all the listeners attached to the properties.
*/
Properties.prototype.removeAllListeners = function() {
for (var i = 0; i < this.m_pProperties.length; i++) {
this.m_pProperties[i].removeAllListeners();
}
};
/**
* Convenience method that allows a change listener to be added to added for objects
* that do not themselves implement {@link module:br/presenter/property/PropertyListener}.
*
* <p>Listeners added using <code>addChangeListener()</code> will only be notified
* when {@link module:br/presenter/property/PropertyListener#onPropertyChanged} fires, and
* will not be notified if any of the other
* {@link module:br/presenter/property/PropertyListener} call-backs fire. The advantage to
* using this method is that objects can choose to listen to call-back events on multiple
* properties.</p>
*
* @param {Function} fCallback The call-back that will be invoked each time the property changes.
* @param {boolean} bNotifyImmediately (optional) Whether to invoke the listener immediately for the current value.
* @type br.presenter.property.PropertyListener
*/
Properties.prototype.addChangeListener = function(fCallback, bNotifyImmediately) {
var oPropertyListener = this.m_oChangeListenerFactory.createListener(fCallback);
this.addListener(oPropertyListener, bNotifyImmediately);
return oPropertyListener;
};
/**
* Convenience method that allows an update listener to be added to added for objects
* that do not themselves implement {@link module:br/presenter/property/PropertyListener}.
*
* <p>Listeners added using <code>addUpdateListener()</code> will only be notified
* when {@link module:br/presenter/property/PropertyListener#onPropertyUpdated} fires, and
* will not be notified if any of the other
* {@link module:br/presenter/property/PropertyListener} call-backs fire. The advantage to
* using this method is that objects can choose to listen to call-back events on multiple
* properties.</p>
*
* @param {Function} fCallback The call-back that will be invoked each time the property is updated.
* @param {boolean} bNotifyImmediately (optional) Whether to invoke the listener immediately for the current value.
* @type br.presenter.property.PropertyListener
*/
Properties.prototype.addUpdateListener = function(fCallback, bNotifyImmediately) {
var oPropertyListener = this.m_oUpdateListenerFactory.createListener(fCallback);
this.addListener(oPropertyListener, bNotifyImmediately);
return oPropertyListener;
};
/**
* @private
* @param pProperties
*/
Properties.prototype._addPropertyArray = function(pProperties) {
for (var i = 0; i < pProperties.length; i++) {
this.m_pProperties.push(pProperties[i]);
}
};
Properties.prototype.addChangeListener = ListenerCompatUtil.enhance(Properties.prototype.addChangeListener);
Properties.prototype.addUpdateListener = ListenerCompatUtil.enhance(Properties.prototype.addUpdateListener);
module.exports = Properties;