
module.exports = new Class
({
	Extends: Vn.Component
	,Tag: 'htk-repeater'
	,Child: 'model'
	,Properties:
	{
		/**
		 * The source data model.
		 */
		model:
		{
			type: Db.Model
			,set: function (x)
			{
				this.link ({_model: x},
				{
					 'status-changed': this._onModelChange
					,'row-deleted': this._onRowDelete
					,'row-updated': this._onRowUpdate
					,'row-inserted': this._onRowInsert
				});
				
				this._onModelChange ();
			}
			,get: function ()
			{
				this._model;
			}
		}
		/**
		 * The identifier for internal iterator.
		 */
		,formId:
		{
			type: String
			,set: function (x)
			{
				this._formId = x;
			}
			,get: function ()
			{
				this._formId;
			}
		}
		/**
		 * {Function (Vn.BuilderResult, Vn.Iterator)} Function to call after
		 * every box rendering.
		 */
		,renderer:
		{
			type: Function
			,set: function (x)
			{
				this._renderer = x;
			}
			,get: function ()
			{
				this._renderer;
			}
		}
		/**
		 * Message that should be displayed when source model is not ready.
		 */
		,emptyMessage:
		{
			type: String
			,value: null
		}
	}
	
	,_builder: null
	,_formId: 'iter'
	,_parentScope: null
	
	,render: function ()
	{
		var div = this.createRoot ('div');
		
		this._container = this.createElement ('div');
		this._container.className = 'htk-repeater';
		div.appendChild (this._container);
	}
	
	,loadXml: function (scope, node)
	{
		this.parent (scope, node);

		var builder = this._builder = new Vn.Builder ();
		builder.compileNode (node.firstElementChild);

		this._parentScope = scope;
		this._onModelChange ();
	}
	
	,getChild: function (index)
	{
		return this._container.childNodes[index];
	}
	
	,getScope: function (index)
	{
		return this._childsData[index].scope;
	}
	
	,getForm: function (index)
	{
		return this._childsData[index].set;
	}
	
	,_buildBox: function (index)
	{
		var set = new Vn.Iterator ({
			model: this._model,
			row: index
		});
		
		var extraObjects = {};
		extraObjects[this._formId] = set;

		var scope = this._builder.load (this.doc, null, this._parentScope, extraObjects, set);
		scope.link ();

		this._childsData.push ({
			scope: scope,
			set: set
		});
		
		if (this._renderer)
			this._renderer (scope, set);
			
		return scope.getMain ();
	}

	,_onModelChange: function ()
	{
		if (!this._model || !this._builder)
			return;

		this.node.removeChild (this._container);
		Vn.Node.removeChilds (this._container);

		this._freeChildsData ();
		this._childsData = [];

		switch (this._model.status)
		{
			case Db.Model.Status.READY:
			{
				for (var i = 0; i < this._model.numRows; i++)
					this._container.appendChild (this._buildBox (i));

				this._showNoRecordsFound ();
				break;
			}
			case Db.Model.Status.LOADING:
				this._showMessage (_('Loading'), null);
				break;
			case Db.Model.Status.CLEAN:
			{	
				var emptyMessage = this.emptyMessage ?
					this.emptyMessage : _('NoData');
				this._showMessage (emptyMessage, 'refresh');
				break;
			}
			case Db.Model.Status.ERROR:
				this._showMessage (_('ErrorLoadingData'), 'error');
				break;
		}
	
		this.node.appendChild (this._container);
		this.emit ('change');
	}

	,_showNoRecordsFound: function ()
	{
		if (this._model.numRows === 0)
			this._showMessage (_('EmptyList'), 'clean');
	}

	,_showMessage: function (message, src)
	{	
		var div =  this.createElement ('div');
		div.className = 'message';
		this._container.appendChild (div);
		
		if (src)
		{
			var img = this.createElement ('img');
			img.alt = '';
			img.src = 'image/icon/light/'+ src +'.svg';
			div.appendChild (img);
		}
		else
		{
			var spinner = new Htk.Spinner ();
			spinner.start ();
			div.appendChild (spinner.node);
		}
		
		div.appendChild (this.createTextNode (message));
	}

	,_onRowDelete: function (model, row)
	{
		Vn.Node.remove (this._container.childNodes[row]);
		this._unrefChildData (row);
		this._childsData.splice (row, 1);		
		
		for (var i = row; i < this._model.numRows; i++)
			this._childsData[i].set.row = i;
		
		this._showNoRecordsFound ();
	}

	,_onRowUpdate: function (model, row, columns)
	{
		this._childsData[row].set.changed ();
	}

	,_onRowInsert: function (model, row)
	{
		var box = this._buildBox (row);
		this._container.appendChild (box);
	}
	
	,_freeChildsData: function ()
	{
		if (this._childsData)
		for (var i = 0; i < this._childsData.length; i++)
			this._unrefChildData (i);
	}
	
	,_unrefChildData: function (index)
	{
		var childData = this._childsData[index];
		childData.set.unref ();
		childData.scope.unref ();
	}

	,_destroy: function ()
	{
		this._freeChildsData ();
		this.parent ();
	}
});

