'use strict';
var CLASS_NAME = 'PropertyContext';
var Argument = require('../system/argument-check.js');
var ModelError = require('./model-error.js');
var PropertyInfo = require('./property-info.js');
/**
* @classdesc
* Provides the context for custom property functions.
* @description
* Creates a new property context object.
* </br></br>
* <i><b>Warning:</b> Property context objects are created in models internally.
* They are intended only to make publicly available the context
* for custom property functions.</i>
*
* @memberof bo.shared
* @constructor
* @param {Array.<bo.shared.PropertyInfo>} properties - An array of property definitions.
* @param {internal~getValue} [getValue] - A function that returns the current value of a property.
* @param {internal~setValue} [setValue] - A function that changes the current value of a property.
*
* @throws {@link bo.system.ArgumentError Argument error}: The properties must be an array
* of PropertyInfo objects, or a single PropertyInfo object or null.
* @throws {@link bo.system.ArgumentError Argument error}: The getValue argument must be a function.
* @throws {@link bo.system.ArgumentError Argument error}: The setValue argument must be a function.
*/
function PropertyContext (properties, getValue, setValue) {
var self = this;
var primaryProperty = null;
var check = Argument.inConstructor(CLASS_NAME);
/**
* The primary property of the custom function.
* @name bo.shared.PropertyContext#primaryProperty
* @type {bo.shared.PropertyInfo}
* @readonly
*/
Object.defineProperty(self, 'primaryProperty', {
get: function () {
return primaryProperty;
},
enumerable: true
});
/**
* Array of property definitions that may used by the custom function.
* @type {Array.<bo.shared.PropertyInfo>}
* @readonly
*/
this.properties = check(properties).forOptional('properties').asArray(PropertyInfo);
getValue = check(getValue).forOptional('getValue').asFunction();
setValue = check(setValue).forOptional('setValue').asFunction();
/**
* Sets the primary property of the custom function.
*
* @param {bo.shared.PropertyInfo} property - The primary property of the custom function.
* @returns {bo.shared.PropertyContext} The property context object itself.
*/
this.with = function (property) {
primaryProperty = Argument.inMethod(CLASS_NAME, 'with')
.check(property).forMandatory('property').asType(PropertyInfo);
return this;
};
function getByName (name) {
for (var i = 0; i < self.properties.length; i++) {
if (self.properties[i].name === name)
return self.properties[i];
}
throw new ModelError('noProperty', properties.name, name);
}
/**
* Gets the current value of a model property.
*
* @param {string} propertyName - The name of the property.
* @returns {*} The value of the model property.
*
* @throws {@link bo.system.ArgumentError Argument error}: The name must be a non-empty string.
* @throws {@link bo.system.ArgumentError Argument error}: The model has no property with the given name.
* @throws {@link bo.shared.ModelError Model error}: The property cannot be read.
*/
this.getValue = function (propertyName) {
propertyName = Argument.inMethod(CLASS_NAME, 'getValue')
.check(propertyName).forMandatory('propertyName').asString();
if (getValue)
return getValue(getByName(propertyName));
else
throw new ModelError('readProperty', properties.name, propertyName);
};
/**
* Sets the current value of a model property.
*
* @param {string} propertyName - The name of the property.
* @param {*} value - The new value of the property.
*
* @throws {@link bo.system.ArgumentError Argument error}: The name must be a non-empty string.
* @throws {@link bo.system.ArgumentError Argument error}: The model has no property with the given name.
* @throws {@link bo.shared.ModelError Model error}: The property cannot be written.
*/
this.setValue = function (propertyName, value) {
propertyName = Argument.inMethod(CLASS_NAME, 'setValue')
.check(propertyName).forMandatory('propertyName').asString();
if (setValue) {
if (value !== undefined) {
setValue(getByName(propertyName), value);
}
} else
throw new ModelError('writeProperty', properties.name, propertyName);
};
// Immutable object.
Object.freeze(this);
}
module.exports = PropertyContext;