
var LotIface = require ('./lot-iface');
var Type = require ('./type');
var Value = require ('./value');

/**
 * A value holder, it emits the changed signal when value is changed.
 * Also it can be linked with a lot value or another parameter.
 */
module.exports = new Class
({
	Properties:
	{
		/**
		 * The parameter value.
		 */
		value:
		{
			type: null
		},
		/**
		 * The parameter type.
		 */
		type:
		{
			type: Type
		},
		/**
		 * Another parameter to bind with.
		 */
		param:
		{
			type: Object
		},
		/**
		 * A lot to bind with.
		 */
		lot:
		{
			type: LotIface
		},
		/**
		 * The field name in the lot.
		 */
		name:
		{
			type: String
		},
		/**
		 * Determines whether the link to the lot is unidirectional, ie, a
		 * change in the lot updates the parameter but not viceversa.
		 */
		oneWay:
		{
			type: Boolean
		}
	}
	
	,_value: undefined
	,_type: null
	,_param: null
	,_paramLock: false
	,_lot: null
	,_name: null
	,_lotLock: false
	,_oneWay: false
	
	,_setValue: function (newValue)
	{
		if (Value.simpleEquals (newValue, this._value))
			return;

		this._value = Value.simpleClone (newValue);
		this._refreshLot ();
		this._refreshParam ();
		this.emit ('changed', newValue);
	}

	,_setType: function (type)
	{
		this._type = type;
		this._onLotChange ();
	}
	
	,_setParam: function (param)
	{
		this.link ({_param: param}, {changed: this._onParamChange});
		this._refreshParam ();
	}

	,_onParamChange: function ()
	{
		if (this._paramLock || !this._param)
			return;

		this._paramLock = true;
		this._setValue (this._param.value);
		this._paramLock = false;
	}

	,_refreshParam: function ()
	{
		if (this._paramLock || !this._param)
			return;

		this._paramLock = true;
		this._param.value = this._value;
		this._paramLock = false;
	}

	,_setLot: function (lot)
	{
		this.link ({_lot: lot}, {change: this._onLotChange});
		this._onLotChange ();
	}

	,_onLotChange: function ()
	{
		if (this._lotLock || !this._name || !this._lot)
			return;

		var newValue = this._lot.get (this._name, this._type);

		this._lotLock = true;
		this._setValue (newValue);
		this._lotLock = false;
	}

	,_refreshLot: function ()
	{
		if (this._lotLock || !this._name || !this._lot || this._oneWay)
			return;

		this._lotLock = true;
		this._lot.set (this._name, this._value);
		this._lotLock = false;
	}

	,_setName: function (name)
	{
		this._name = name;
		this._onLotChange ();
	}
});
