var Object = require ('./object');
var Param = require ('./param');
var Hash = require ('./hash');

module.exports = new Class
({
	Extends: Object
	,Tag: 'vn-hash-param'
	,Child: 'param'
	,Properties:
	{
		param:
		{
			type: Param
			,set: function (x)
			{
				this.link ({_param: x}, {'changed': this._onParamChange});
				this._refreshParam ();
			}
			,get: function ()
			{
				return this._param;
			}
		},
		key:
		{
			type: String
			,set: function (x)
			{
				this._key = x;
				this._onHashChange ();
			}
			,get: function ()
			{
				return this._key;
			}
		},
		value:
		{
			type: Object
			,set: function (x)
			{
				this._setValue (x, true);
			}
			,get: function ()
			{
				return this._value;
			}
		},
		type:
		{
			type: Object
			,set: function (x)
			{
				this._type = x;
				this._onHashChange ();
			}
			,get: function ()
			{
				return this._type;
			}
		}
	}
	
	,_hashLock: false
	,_paramLock: false
	,_value: undefined
	,_key: null
	,_type: null
	
	,initialize: function (props)
	{
		this.parent (props);
		var listener = Hash.getListener ();
		this.link ({_listener: listener}, {'changed': this._onHashChange});
		this._onHashChange ();
	}

	,_onHashChange: function ()
	{	
		if (this._hashLock || !this._key || !this._listener)
			return;

		var newValue = Hash.get (this._key);
		
		if (newValue === '')
			newValue = null;
		
		if (this._type && newValue !== undefined && newValue !== null)
		switch (this._type)
		{
			case Boolean:
				newValue = (/^(true|1)$/i).test (newValue);
				break;
			case Number:
				newValue = 0 + new Number (newValue);
				break;
		}

		this._hashLock = true;
		this._setValue (newValue, true);
		this._hashLock = false;
	}
	
	,_setValue: function (newValue, signal)
	{
		if (newValue == this._value)
			return;

		this._value = newValue;

		if (this._key && !this._hashLock)
		{
			this._hashLock = true;

			var map = {};
			map[this._key] = newValue;
			Hash.add (map);

			this._hashLock = false;
		}
		
		this._refreshParam ();
		
		if (signal)
			this.signalEmit ('changed', newValue);
	}

	,_refreshParam: function ()
	{
		if (this._param && !this._paramLock)
		{
			this._paramLock = true;
			this._param.value = this._value;
			this._paramLock = false;
		}
	}
	
	,_onParamChange: function ()
	{
		if (this._paramLock)
			return;

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