
var ColumnText = require ('../column/text');

module.exports = new Class
({
	Extends: Htk.Field
	,Implements: Vn.Iterator
	,Tag: 'htk-combo'
	,Properties:
	{
		/**
		 * The model associated to this form.
		 */
		model:
		{ 
			type: Db.Model
			,set: function (x)
			{
				this.link ({_model: x}, {'status-changed-after': this._onModelChange});
				this._onModelChange ();
			}
			,get: function ()
			{
				return this._model;
			}
		},
		/**
		 * The row where the form positioned, has -1 if the row is unselected.
		 */
		row:
		{ 
			type: Number
			,set: function (x)
			{
				if (!this._model || this._model.numRows <= x || x < -1)
					x = -1;
				if (x == this._row)
					return;

				this._row = x;
				this.rowChanged ();
			}
			,get: function ()
			{
				return this._row;
			}
		},
		/**
		 * The number of rows in the form.
		 */
		numRows:
		{
			type: Number
			,get: function ()
			{
				if (this._model)
					return this._model.numRows;

				return 0;
			}
		},
		/**
		 * Checks if the form data is ready.
		 */
		ready:
		{
			type: Boolean
			,get: function ()
			{
				return this._model && this._model.ready;
			}
		},
		/**
		 * Checks if the form data is ready.
		 */
		placeholder:
		{
			type: String
			,set: function (x)
			{
				this._placeholder = x;
				this._refreshShowText (x);
			}
			,get: function ()
			{
				return this._placeholder;
			}
		},
		/**
		 * Wether to allow null values.
		 */
		notNull:
		{
			type: Boolean
			,set: function (x)
			{
				this._notNull = x;
			}
			,get: function ()
			{
				return this._notNull;
			}
		},
		/**
		 * The field to use for internal value.
		 */
		valueField:
		{
			type: String,
			value: 'id'
		},
		/**
		 * The field to display.
		 */
		showField:
		{
			type: String,
			value: 'name'
		},
		params:
		{ 
			type: Object
			,set: function (x)
			{
				this.setAll (x);
			}
			,get: function ()
			{
				return this._params;
			}
		}
		,$:
		{
			type: Object
			,set: function (x)
			{
				this.setAll (x);
			}
			,get: function ()
			{
				return this._params;
			}
		}
	}
	
	,_row: -1
	,_model: null
	,_notNull: false
	,_selected: false

	,render: function ()
	{
		var node = this.createRoot ('div');
		Vn.Node.addClass (node, 'input clickable');
		node.tabIndex = 0;
		node.addEventListener ('mousedown',
			this._onMouseDown.bind (this));
		
		var icons = this.createElement ('div');
		icons.className = 'icons';
		node.appendChild (icons);
		
		var clearButton = this.createElement ('htk-icon');
		clearButton.className = 'clear button';
		clearButton.icon = 'close';
		clearButton.node.title = _('Clear');
		clearButton.on ('click', this._onClearClick, this);
		clearButton.on ('mousedown', this._onClearMouseDown, this);
		icons.appendChild (clearButton.node);

		var downIcon = this.createElement ('htk-icon');
		downIcon.className = 'down';
		downIcon.icon = 'down';
		icons.appendChild (downIcon.node);
	
		var text = this.createElement ('div');
		text.className = 'text';
		node.appendChild (text);

		this.text = text;
		this.clearButton = clearButton;
		this._refreshShowText ();
	}

	,_onClearClick: function ()
	{
		this.value = null;
	}

	,_onClearMouseDown: function (_, event)
	{
		event.preventDefault ();
	}
	
	,_onMouseDown: function (e)
	{
		if (e.defaultPrevented)
			return;

		if (this._popup)
		{
			this._popup.hide ();
			return;
		}
	
		var model = this._model;
		
		if (model.status === Db.Model.Status.CLEAN)
			model.refresh ();

		var menu = this.createElement ('div');
		menu.className = 'htk-combo-menu';
		
		var grid = new Htk.Grid ({showHeader: false});
		menu.appendChild (grid.node);
		
		var gridNode = grid.node;
		gridNode.addEventListener ('click',
			this._onGridClicked.bind (this, grid));
		
		var column = new ColumnText ({column: this.showField});
		grid.appendColumn (column);
		grid.model = model;
		
		var popup = this._popup = new Htk.Popup ({childNode: menu});
		popup.on ('closed', this._onPopupClose.bind (this));
		popup.show (this.node, true, e);

		this.emit ('menu-show');
	}
	
	,_onGridClicked: function (grid, e)
	{
		e.stopPropagation ();
		var target = e.target;
		var parentNode = target.parentNode;
		
		while (parentNode !== grid.tbody)
		{
			target = parentNode;
			parentNode = parentNode.parentNode;
		}

		var value;
		var row = target.rowIndex - 1;

		if (row >= 0)
			value = this._model.get (row, this.valueField);
		else
			value = null;

		this._popup.hide ();

		var changed = this._putValue (value);
		
		this._selected = false;
		this._setRow (row, true);

		if (changed)
		{
			if (this.conditionalFunc)
				this.conditionalFunc (this, newValue);

			this._notifyChanges ();
		}		
	}
	
	,_onPopupClose: function ()
	{
		this._popup = null;
		this.emit ('menu-hide');
	}
	
	,_setRow: function (row)
	{
		this._row = row;

		if (!this._selected)
		{
			if (row != -1)
				this._selected = true;
	
			this.rowChanged ();
			this._refreshShowText ();
		}
	}

	,_onModelChange: function ()
	{
		var model = this._model;
		this.emit ('status-changed');
		
		if (this._popup)
			this._popup.reset ();

		this._selectOption ();

		if (model && model.ready)
			this.emit ('ready');
	}

	,_selectOption: function ()
	{
		var row;
	
		if (this._model && this._model.ready)
			row = this._model.search (this.valueField, this._value);
		else
			row = -1;

		this._setRow (row);
	}

	,_putFieldValue: function ()
	{
		this._selected = false;
		this._selectOption ();
	}

	,_refreshShowText: function ()
	{
		var model = this._model;
	
		if (this._value != null)
			var showText = this.$[this.showField];
		else if (model && model.status === Db.Model.Status.LOADING)
			var showText = _('Loading...');
		else if (this._placeholder)
			var showText = this._placeholder;
		else
			var showText = '';

		if (this.node)
		{
			var display;

			if (this._value && !this._notNull)
				display = '';
			else
				display = 'none';

			this.clearButton.node.style.display = display;
			Vn.Node.setText (this.text, showText);
		}
	}
	
	,setEditable: function (editable)
	{
		this.node.disabled = !editable;
	}
});
