var ItemsList = new Class({

	initialize: function(container, options) {		
		this.containerObj = $(container);		
		if (!this.containerObj) return;			
		this.id = this.containerObj.id;
		
		this.container = $(options.container);	
		if(!this.container) return;
		
		/**
		 * Indicate if action is a action URL
		 */
		/* boolean */ this.actionUrl = options.actionUrl;
		
		/**
		 * Action how and where to get the items [js|url] 
		 */
		/* js function or url */ this.action = options.action;
		
		/**
		 * Indicate the number of item to show to user
		 */
		/* int */this.numberItemsToShow = options.numberItemsToShow;	
		
		/**
		 * Indicate the number of item to load in each request
		 */	
		/* int */this.numberItemsToLoad = options.numberItemsToLoad;
		
		/**
		 * Name of parameter that indicate the number of items to load.
	 	 * Is used on action URL.
		 */
		/* string */this.nameParamNumberItemsToLoad = options.nameParamNumberItemsToLoad;
		
		/**
		 * Name of parameter that indicate the start index of items to load.
	 	 * Is used on action URL.
		 */
		/* string */this.nameParamStartIdx = options.nameParamStartIdx;	
		
		/**
		 * Js function name that will be executed
		 * before the load of json object that will
	 	 * contains the query parameters.
		 */					
		/* js function */this.beforeLoad = undefined;
		if(options.beforeLoad != undefined)
			this.beforeLoad = window[options.beforeLoad];	
		
		/**
		 * Js function name that will be executed
		 * on load of items.
		 */
		/* js function */this.onLoadItems = undefined;
		if(options.onLoadItems != undefined)
			this.onLoadItems = window[options.onLoadItems];	
		
		/**
		 * Js function name that will be executed
	 	 * after added new load items.
		 */
		/* js function */this.afterLoad = undefined;
		if(options.afterLoad != undefined)
			this.afterLoad = window[options.afterLoad];	
				
		/**
		 * Message showed on items when content isn't loaded
		 */
		/* string */this.loadingItemMsg = options.loadingItemMsg;
				
		/**
		 * Location of image to move up (disable mode)
		 */
		/* string */this.imageUpSrcDisable = options.imageUpSrcDisable;
		
		/**
		 * Location of image to move down (disable mode)
		 */
		/* string */this.imageDownSrcDisable = options.imageDownSrcDisable;
		
		/**
		 * Location of image to move down up
		 */
		/* string */this.imageUpSrc = options.imageUpSrc;
		
		/**
		 * Location of image to move down
		 */
		/* string */this.imageDownSrc = options.imageDownSrc;
		
		
		/**
		 * Actual idx to control pagging (idx of first item on visible items)
		 */
		/* int */ this.actualIdx = 0;
		
		/**
		 * This boolean indicates if componenet is loading item (do a request for more item)
		 */
		/* boolean */ this.isLoadingData = false;
		
		/**
		 * Indicate if after finish loading items exist more items to load
		 * Is used when have some request for more item and actual state is loading item (isLoadingData = true)
		 */			
		/* boolean */ this.loadingMoreItems = false;
		
		/**
		 * Last number of item requested.
		 * (For verify is the last loading)
		 */
		/* int */ this.lastNumberItemsToLoad = 0;
		
		/**
		 * Boolean to control is was necessary to call event eventLoadItems one more time.
		 * This value is false when returned items was less than last request
		 */
		/* boolean */ this.existMoreItems = (this.action != undefined);
		
		/**
		 * flag to block multiple mouse scroll event
		 */
		/* boolean */ this.evenScrollRun = false;		
				
		/**
		 * Array with all items IDs.
		 * FIX-ME IS NOT NECESSARY
		 */
		/* Array */ this.loadItems = new Array();	
					
		for(var i=0; i < options.numberOfItems; i++) 
			this.loadItems[i] = (this.id+'Item'+this.loadItems.length);	
			
		/**
		 * Number of item add to container
		 */
		/* int */ this.numberOfItems =  parseInt(options.numberOfItems);	
		
			
		var elemItem;		
		//show all possivel items
		for(var i=0; i<this.loadItems.length && i < this.numberItemsToShow; i++) 
		{
			elemItem = document.getElementById(this.loadItems[i]);
			if(elemItem != undefined)
				elemItem.style.display = "block";
		}
		
		//init events
		var objID = this.id;				
		//move down
		var func = function (){window[objID].showNextItem();}
		$(this.id+"DownNav").addEvent('click', func);				
		//move up
		func = function (){window[objID].showBackItem();}
		$(this.id+"TopNav").addEvent('click', func);
				
		this._updateArrows();		
		//add event for mouse scroll
		var itemListObj = this;		
		var mouseScrollEvent = function(event)
		{	
			var delta = 0;
			if (!event) /* For IE. */
				event = window.event;
			            
			try
			{
				//verify if is possible to execute event
				if(itemListObj.evenScrollRun == false)
				{					
					//block the event access 
					itemListObj.evenScrollRun = true;	
			            
			        if (event.wheelDelta) { /* IE/Opera. */
				        delta = event.wheelDelta/120;
				        /** In Opera 9, delta differs in sign as compared to IE.
				         */
				        if (window.opera)
				        	delta = -delta;
			        } else if (event.detail) { /** Mozilla case. */
			             /** In Mozilla, sign of delta is different than in IE.
			              * Also, delta is multiple of 3.
			              */
			             delta = -event.detail/3;
			        }
			        /** If delta is nonzero, handle it.
			         * Basically, delta is now positive if wheel was scrolled up,
			         * and negative, if wheel was scrolled down.
			         */
			        if (delta)
			        {				        	
			        	if(itemListObj.loadItems.length > itemListObj.numberItemsToShow)
			        	{	
			        		var funcMove = function()
			        		{
			        			try
			        			{
					        		//move items UP delta > 0 or DOWN if delta < 0
					        		if(delta < 0)					        		
					        			itemListObj.showNextItem();
					        		else if (delta > 0)
					        			itemListObj.showBackItem();
			        			}
			        			catch(err)
			        			{
			        				throw "funcMove:"+err;
			        			}	
			        			
				        		//unblock acess of event mouse
				        		itemListObj.evenScrollRun = false;
			        		}	
			        		
			        		var t=setTimeout(funcMove, 50);
			        	}
			        	else
			        		itemListObj.evenScrollRun = false;
			        }
				}
			}
			catch(err)
			{
				throw "mouseScrollEvent:"+err;
			}	
			 /** Prevent default actions caused by mouse wheel.
	         * That might be ugly, but we handle scrolls somehow
	         * anyway, so don't bother here..
	         */
	        if (event.preventDefault)
	        	event.preventDefault();
			event.returnValue = false;	
		}
		
		var element = document.getElementById(this.id+"ItemListContainer");		
		
		if (element.addEventListener) // DOMMouseScroll is for mozilla.
			element.addEventListener('DOMMouseScroll', mouseScrollEvent , false);	

		//IE/Opera.
		element.onmousewheel = element.onmousewheel = mouseScrollEvent;
	},	
	
	/**
	* Method called to show next item. 
	* If not exist more items loaded, load more items and show loading item. 
	*/
	showNextItem : function ()
	{
		try
		{	
			var idx = this.actualIdx + this.numberItemsToShow;
			var itemID = this.loadItems[idx];
			var actIdx = this.actualIdx
			
			this.actualIdx += 1;
																
			if(this.existMoreItems == true)
			{	
				this._drawItems(idx, actIdx, this.loadingItemMsg);					
				// verify if is necessary to load more item					
				if( (idx + this.numberItemsToLoad) >= this.loadItems.length)//+ this.numberItemsToLoad //fixme
				{					
					this._getNextItems(this.numberItemsToLoad);	
				}
			}
			else 		
			{		
				if( itemID != undefined )	
					this._drawItems(idx, actIdx, "");						
				else				
					this.actualIdx -= 1;															
			}	
			this._updateArrows();			
		}
		catch(err)
		{
			throw "showNextItem:"+err;
		}		
	},		
		
	/**
	* Method called to show previous item. 
	*/
	showBackItem : function ()
	{
		try
		{
			if(this.actualIdx > 0)
			{							
				this.actualIdx -= 1;								
				//var item = this.loadItems[this.actualIdx];						
				this._drawItems(this.actualIdx, this.actualIdx + this.numberItemsToShow, "");
			}
			this._updateArrows();
		}
		catch(err)
		{
			throw "showBackItem:"+err;
		}				
	}, 
	
	/**
	 * Clear all item and reset actual state of ListItem
	 * @param numItemToShow - the number of items to show (optional)
	 */
	clearItems : function (/* int */ numItemToShow )
	{
		try
		{			
			this.container.innerHTML = '';
			this.actualIdx = 0;
			this.loadItems = new Array();				
			this.numberOfItems =  0;
			this.existMoreItems = (this.action != undefined);
			this.lastNumberItemsToLoad = 0;
			if(numItemToShow != undefined && (!isNaN(numItemToShow)) && numItemToShow > 0)
			{				
				this.numberItemsToShow = parseInt(numItemToShow);
			}
			this.isLoadingData = false;
			this._updateArrows(false);
		}
		catch(err)
		{
			throw "clearItems:"+err;
		}
	},
	
	/**
	 * Execute object action (js|url).
	 * Get next item - execute action
	 */
	executeAction : function()
	{
		try
		{			
			this.existMoreItems == true;				
			return this._getNextItems(this.numberItemsToLoad);	
		}
		catch(err)
		{
			throw "executeAction:"+err;
		}
	},
	
	
	showTop : function()
	{		
		var i, elem, lim = this.actualIdx+this.numberItemsToShow;
		
		for(i = this.actualIdx; i < lim; i++)
		{
			elem = document.getElementById(this.loadItems[i]);
			if(elem != undefined)
				elem.style.display = "none";
		}

		this.actualIdx = 0;		
		for(i = 0; i < this.numberItemsToShow && i < this.loadItems[i].length ; i++)
		{
			elem = document.getElementById(this.loadItems[i]);
			if(elem != undefined)
				elem.style.display = "block";
		}
		this._updateArrows();
	},	
	
	/**
	 * Method to change the number of visivel items. 
	 */
	setNumberItemsToShow : function(/* int */ num)
	{
		try
		{
			if(isNaN(num) || num < 1)
				return;
				
			var antNum = this.numberItemsToShow;
			this.numberItemsToShow = parseInt(num);			
			var elemItem, i, lim = this.actualIdx+this.numberItemsToShow;		
			
			//hidden excess of items 
			if(antNum > this.numberItemsToShow)
			{	
				var end = this.actualIdx + antNum;				
				
				for(i = lim; i < this.loadItems.length && i < end; i++)
				{
					elemItem = document.getElementById(this.loadItems[i]);
					if(elemItem != undefined)
						elemItem.style.display = "none";
				}
			}
			
			//show all item between the interval
			for( i = this.actualIdx; i < this.loadItems.length && i < lim; i++) 
			{
				elemItem = document.getElementById(this.loadItems[i]);
				if(elemItem != undefined)
					elemItem.style.display = "block";
			}	
	
			//if actual idx not permit show th number of item, go back
			if(lim > this.loadItems.length && this.loadItems.length > 0)
			{					
				if(!this.executeAction())
				{					
					antNum = (this.actualIdx - (lim - this.loadItems.length) );
					antNum = antNum < 0 ? 0 : antNum;
					for( i = antNum; i < this.actualIdx; i++) 
					{
						elemItem = document.getElementById(this.loadItems[i]);
						if(elemItem != undefined)
							elemItem.style.display = "block";
					}
					this.actualIdx = antNum;
				}
			}
			
			this._updateArrows();
		}
		catch(err)
		{
			throw "setNumberItemsToShow:"+err;
		}
	},
	
	/**
	* Method called when was need more items to show. 
	* If action is a url execute a request, else execute a js function.
	* @param numItemsLoad - number of item to load
	*/
	_getNextItems :	function (/* int */ numItemsLoad)
	{
		try
		{				
			this.lastNumberItemsToLoad = numItemsLoad;
				
			if(this.actionUrl == true)
			{		
				if(this.existMoreItems == false)
					return false;
												
				if(this.isLoadingData == false)
				{								
					this.isLoadingData = true;
					try
					{					
						//parameters of request	
						var parameters = {};
						
						// Before load, add another user parameters 
						if (this.beforeLoad != null)
							continueSubmit = this.beforeLoad(this, parameters);
						//verify if is possible to continue
						if (continueSubmit == false)
							return false;	
						//internal parameters (pagination parameters)
						parameters[this.nameParamNumberItemsToLoad] = this.lastNumberItemsToLoad;
						parameters[this.nameParamStartIdx] = this.loadItems.length;												
						//auxiliar variable
						var itemList = this;	
						
						var ajax = new Ajax(this.action, {
							method: "post",							
							async: true,						
							postBody: parameters,	
							onFailure: function(){																						
								if(itemList.afterLoad)								
									itemList.afterLoad(itemList);
								//FIX-ME SHOW A DIALOG
								throw 'Error loading items ' + itemList.id;
							},
							onSuccess: function (response, xml) {	
								
								// Insert the new items
								var numberItems = 0;							
								var nodes = itemList._createNodesFromText(response);	
								var nodesSize = nodes.length;
								var i = 0, node, nodeName;
								for (i = 0; i < nodesSize; i ++){	
									node = nodes[i];
									nodeName = node.nodeName.toUpperCase();
									if (nodeName == 'DIV')																					
									{
										itemList._addItem(node);																							
										numberItems += 1;
									}
									else if (nodeName == "script")
										eval(node.innerHTML);
								}
								
								//verify if is possible to load more items														
								itemList.existMoreItems = (numberItems >= itemList.lastNumberItemsToLoad);								
								
								itemList.isLoadingData = false;
								
								if(itemList.existMoreItems)
								{
									if(itemList.loadingMoreItems)
									{							
										//calculate the number of item to load
										var numItem = itemList.loadItems.length - (itemList.actualIdx + itemList.numberItemsToShow);							
										if(numItem >= 0)
											numItem = itemList.numberItemsToLoad;
										else
											numItem = Math.abs(numItem) + itemList.numberItemsToLoad;
																					
										itemList._getNextItems(numItem);											
										itemList.loadingMoreItems = false;
									}
								}
								else																
									itemList._clearEmptyItems();	
								
								itemList._updateArrows();									
								
								if(itemList.afterLoad)								
									itemList.afterLoad(itemList);							
								
							}
						} );
						
						if(this.onLoadItems)
							this.onLoadItems(this);											
					
						ajax.request();	
						return true;
					}
					catch(err)
					{
						throw '_getNextItems: '+err;
					}
				}	
				else
					this.loadingMoreItems = true;	
			}
			else
			{
				//call JS function
				var func = dj_global[this.action];
				if(func)
				{
					var itemsArray = func(this.loadItems.length, this.numberItemsToLoad);
					this.addItems(itemsArray);
					return true;
				}				
			}							
		}
		catch(err)
		{
			throw '_getNextItems: '+err;
		}
		return false;
	},
	
	_createNodesFromText : function (text)
	{
		var elem = document.createElement("div");
		elem.style.display= "none";
		document.body.appendChild(elem);
		elem.innerHTML = text;
		var elems = $$(elem.childNodes);		
		document.body.removeChild(elem);
		return elems;
	},
	
	/**
	 * Verify if item is visible
	 * @param itemIdx - item index
	 * @return true if is visible
	 */
	_itemIsVisible : function (/* int */itemIdx)
	{
		return (itemIdx >= this.actualIdx && itemIdx < (this.actualIdx + this.numberItemsToShow));
	},
	
	/**
	* Method to draw next item on container.
	* Hidden one item, add show another. If item to show not exist create one auxiliar 
	* @param idxItemAdd - index of item to draw
	* @param idxItemRemove - index of item to remove 
	* @param loadingMsg - loading msg (optional)
	*/
	_drawItems : function ( /* int */ idxItemAdd, /* int */ idxItemRemove, /*string*/ loadingMsg )
	{
		try
		{				
			var itemAdd = document.getElementById(this.id+'Item'+idxItemAdd);
			var itemRem = document.getElementById(this.id+'Item'+idxItemRemove);
			
			if(itemRem != undefined)						
				itemRem.style.display = "none";				
				
			if(itemAdd != undefined)								
				itemAdd.style.display = "block";							
			else if(loadingMsg != undefined)	
				this._createNewItem(this.numberOfItems, loadingMsg, true);
		}
		catch(err)
		{
			throw "_drawNextItem:"+err;
		}
	},
	
	/**
	 * Update the state of arrows (UP and DOWN)
	 * @param showArrows - boolean that indicate the state of arrows (optional)
	 */
	_updateArrows : function (/* boolean */ showArrows )
	{
		try
		{
			if(showArrows != undefined)
			{
				this._showArrow(showArrows, this.id+"ImgDown");
				this._showArrow(showArrows, this.id+"ImgUp");	
			}
			else
			{
				//update arrows
				var show = ((this.actualIdx + this.numberItemsToShow) <  this.loadItems.length)
				if(show == false && this.existMoreItems == true)				
					show = this.loadItems.length > 0;				
				
				this._showArrow(show, this.id+"ImgDown");
				this._showArrow(this.actualIdx > 0, this.id+"ImgUp");	
			}
		}
		catch(err)
		{
			throw "_updateArrows:"+err;
		}
	},
	
	/**
	 * Show one arrow 
	 * @param show - true to show arrow, false to hidden
	 * @param elemID - element ID
	 */
	_showArrow : function (/* boolean */ show, /* string */ elemID)
	{
		try
		{
			var elem = document.getElementById(elemID);
			var elemDisable = document.getElementById(elemID+"Disable");
			if(show == true)		
			{	
				//elem.style.visibility = "visible";			
				elem.style.display = "inline";
				elemDisable.style.display = "none";
			}
			else
			{
				//elem.style.visibility = "hidden";
				elem.style.display = "none";
				elemDisable.style.display = "inline";
			}
		}
		catch(err)
		{
			throw "_showArrow:"+err;
		}
	},
	
	/**
	 * Add one node that represent one item, and update arrows.
	 * @param node - html node
	 */	
	addItem : function (/* Node */ node)
	{
		try
		{	
			this._addItem(node);
			this._updateArrows();
		}
		catch(err)
		{
			throw "addItem:"+err;
		}				
	},
	
	/**
	 * Add one node that represent one item.
	 * @param node - html node
	 */	
	_addItem : function (/* Node */ node)
	{
		try
		{	
			if(node == undefined)
				return;
			var divItem = this._createNewItem(this.loadItems.length, "", false);			
			divItem.innerHTML = '';						
			divItem.appendChild(node);	
			this.loadItems[this.loadItems.length] = divItem.id;					
		}
		catch(err)
		{
			throw "addItem:"+err;
		}				
	},
	
	/**
	 * Add many items that represent one item.
	 * @param Items - array of new item to add
	 */
	addItemNodes : function (/* array */ nodes)
	{
		try
		{	
			var divItem = this._createNewItem(this.loadItems.length, "", false);			
			divItem.innerHTML = '';	
			
			var node, nodeName;
			for(var i=0; i < nodes.length; i++) {
				node = nodes[i];
				if(node != undefined)
				{				
					divItem.appendChild(node);
									
					if (node.nodeName.toLowerCase() == "script")
						eval(node.innerHTML);
				}
			}				
				
			this.loadItems[this.loadItems.length] = divItem.id;		
			
			this._updateArrows();
		}
		catch(err)
		{
			throw "addItem:"+err;
		}				
	},
	
	/**
	 * Add multiple item.
	 * @param Items - array of item to add
	 */
	addItems : function (/* array */ items)
	{
		try
		{				
			for(var i=0; i<items.length; i++) 
				this._addItem(items[i]);
			
			this._updateArrows();
		}
		catch(err)
		{
			throw "addItems:"+err;
		}				
	},
	
	/**
	 * Create new item and add to container
	 * @param itemIdx - item index
	 * @param msg - message to show on item (for exemplo loading msg)
	 */
	_createNewItem : function (/* int */itemIdx, /* string */ msg)
	{
		try
		{			
			var itemID = this.id+'Item'+itemIdx;
			var divItem = document.getElementById(itemID);
			
			if(divItem == undefined)
			{			
				//create new div element and put portlet info	
				divItem = document.createElement("div");
				divItem.id = itemID;
				//divItem.className = this.defaultItemContainerClass;		
				
				if(this._itemIsVisible(itemIdx))
					divItem.style.display = "block";
				else
					divItem.style.display = "none";
					
				divItem.innerHTML = msg;				
				this.container.appendChild(divItem);
								
				this.numberOfItems += 1;
			}
			
			return divItem;
		}
		catch(err)
		{
			throw "_createNewItem:"+err;
		}
		return undefined;
	},
	
	/**
	 * Clear all excess of loading items and show the last items with contents 
	 */
	_clearEmptyItems : function ()
	{
		try
		{				
			var itemNode, i;			
			
			//remove all unecessary loading items
			for(i = this.numberOfItems; i >= this.loadItems.length; i--) 
			{
				itemNode = document.getElementById(this.id+'Item'+i);
				if(itemNode != undefined)
					this.container.removeChild(itemNode);				
			}				
			
			if( (this.actualIdx + this.numberItemsToShow) >=  this.loadItems.length)
			{			
				//show last items and remove the other items
				var start = this.loadItems.length - this.numberItemsToShow;// - 1;					
				start = start < 0 ? 0 : start;
				var end = start + this.numberItemsToShow;
				
				//remove other items 
				for(i = this.actualIdx; i < start; i++)
				{
					divItem = document.getElementById(this.id+'Item'+i);
					if(divItem != undefined)
						divItem.style.display = "none";
				}				
				
				for(i = start; i < end; i++) 
				{
					divItem = document.getElementById(this.id+'Item'+i);
					if(divItem != undefined)
						divItem.style.display = "block";
				}
				
				this.actualIdx = start;					
			}
		}
		catch(err)
		{
			throw "_clearEmptyItems:"+err;
		}
	}
	
	
	
});





