/**
 * Pager Class
 *
 * Creates a pager for linked Items object
 *
 * Takes in a Items object, and creates a pager at the element provided
 * The Items.updateHTML called the Pager.updateHTML to refresh the elements
 * as required with new data
 */
var Pager = Class.create({
	initialize: function(items) {
		//TODO: Append child if id not given


		if(items instanceof Items)
		{
		    this.id = items.pager_id;
		    this.info_id = items.info_id;
		    this.items = items;

		    this.create();
	    }
	    else
	    {
	    	alert('Pager only works with the Items Class');
	    }
	},
	create: function()
	{
		this.page =1;

		//Link Nodes to Object for quick access
		this.linkPrevious = Builder.node('a', {title:'Previous Page', href:'#'},'Previous');
		this.linkNext = Builder.node('a', {title:'Next Page', href:'#'},'Next');
		this.nodeLinkList =  Builder.node('ul',{className:'pagerLinkList contain'});



		var nodePrevious = Builder.node('ul', {className:'pagerPrevious'},[
									Builder.node('li',[
										this.linkPrevious
									])
								]);
		var nodeNext = Builder.node('ul', {className:'pagerNext'},[
									Builder.node('li',[
										this.linkNext
									])
								]);

		$(this.id).innerHTML = '';
		$(this.id).appendChild(nodePrevious);
		$(this.id).appendChild(nodeNext);
		$(this.id).appendChild(this.nodeLinkList);

		//Sync the nodes with the data
		this.update();

		$(this.linkPrevious).observe('click',this._pagePrevious.bind(this));
		$(this.linkNext).observe('click',this._pageNext.bind(this));


	},
	update: function()
	{
		//Update data from items and update values
		this.itemsTotal = this.items.data_filtered.length;
		this.pagesTotal = Math.ceil(this.itemsTotal / this.items.grid.items);


		this.updateLinkPrevious();
		this.updateLinkNext();
		this.updateLinkList();
		
		
		this.updateInfo();
	},
	updateInfo: function()
	{
		var infoArray = $(this.info_id).getElementsBySelector('.number');
		
		infoArray[0].innerHTML = Math.min((this.page * this.items.grid.items) - this.items.grid.items +1,this.itemsTotal);
		infoArray[1].innerHTML = Math.min((this.page * this.items.grid.items),this.itemsTotal);
		infoArray[2].innerHTML = this.itemsTotal;
	},
	updateLinkPrevious: function()
	{
		if(this.page==1)
		{
			$(this.linkPrevious.parentNode).hide();
		}
		else
		{
			$(this.linkPrevious.parentNode).show()
		}
	},
	updateLinkNext: function()
	{
		if(this.page==this.pagesTotal || this.pagesTotal <= 1)
		{
			$(this.linkNext.parentNode).hide();
		}
		else
		{
			$(this.linkNext.parentNode).show()
		}

	},
	updateLinkList: function()
	{
		this.nodeLinkList.innerHTML = '';
		var pages = [];
		var middle = false;

		//Link through pages and only show the first, last and surrounding pages.
		for(var i=0; i <= this.pagesTotal;i++)
		{
			if(i <= 3 || i > this.pagesTotal-3 || (i >= this.page-1 && i <= this.page+1))
			{
				//Set middle to show ... again
				if((i >= this.page-1 && i <= this.page+1))
				{
					middle = false;
				}

				var item = Builder.node('li',[Builder.node('a',{href:'#',title:'See page '+i},i)]);

				if(i == this.page)
				{
					$(item).addClassName('active');
				}
				else
				{
					$(item).observe('click',this._pageThis.bind(this));

				}
				this.nodeLinkList.appendChild(item);
			}
			else if(middle == false)
			{
				this.nodeLinkList.appendChild(Builder.node('li','...'));
				middle = true;
			}
		}
	},
	setPage: function(page)
	{
		this.page = page;

		this.update();
		this.items.display.update();
		
	},
	_pageThis: function(event)
	{
		var item = Event.element(event);
		var page = parseInt(item.innerHTML,10);

		if(page <= this.pagesTotal && page >= 1)
		{
			this.setPage(page);
		}

		event.stop();
	},
	_pagePrevious: function(event)
	{
		if(this.page-1 >0 )
		{
			this.setPage(this.page-1);
		}

		event.stop();
	},
	_pageNext: function(event)
	{
		if((this.page+1) <= this.pagesTotal)
		{
			this.setPage(this.page+1);
		}

		event.stop();
	}
});
var Display = Class.create({
	initialize: function(items) {
		if(items instanceof Items)
		{
		    this.id = items.display_id;
		    this.items = items;

		    this.create();
	    }
	    else
	    {
	    	alert('Display only works with the Items Class');
	    }
	},
	create: function()
	{
		//Items Vars
		var items = this.items.data_filtered;
		
		var grid = this.items.grid;
		var style = this.items.style;
		
		var start = (this.items.pager.page - 1) * grid.items;

		var cells = [];
		var rows = [];

		//TODO: Add Transitions here
		$(this.id).innerHTML = '';
		$(this.id).className = style.grid;

		//Row
		var row;

		var display = $(this.items.display_id);
		
		display.setStyle({"position":'relative'});
		
		
		this.fade = new Element('div',{style:'background:#ffffff;height:100%;width:100%;position:absolute;z-index:100'});
		display.appendChild(this.fade);
		
		if( this.items.data_filtered == 0)
		{
			display.innerHTML = '<div><p>We\'re sorry but there are no products that match your choices. Please press <a href="BeautyProducts">Refresh</a> to start your search again.</p></div>';
		}
		else
		{
		
		//TODO: Request Product Infomation foreach ID
		var items_viewable = [];
		var length = items.length;
		
		for(var i = start ; i<length && i < start+grid.items; i++)
		{
			if(items[i].information.complete != true)
			{	
				items_viewable.push(i);
			}
		}		
		
		new Ajax.Request('home',{
			method:'GET',
			parameters: 'ids='+items_viewable.join(','),
			onSuccess: this.updateInformation.bind(this),			
			onFailure: this._error.bind(this)			
		});	
		
		
		for(var i = start ; i<length && i < start+grid.items; i++)
		{
			var product = items[i].html(grid,style);

			if(i % grid.cols == 0)
			{
				var outerRow = $(Builder.node('div',{className:style.row}));
				row = $(Builder.node('div',{className:'innerRow contain'}));
				outerRow.appendChild(row);
				$(this.id).appendChild(outerRow);
				
				//if(i < (start+grid.items - grid.cols))
				//{
					outerRow.addClassName('itemRowSeperator');
				//}
				
			}
			
			var cell = 	$(Builder.node('div',{className:style.cell},product));
			row.appendChild(cell);


			if(i % grid.cols == (grid.cols-1) || i == (items.length-1))
			{
				cell.addClassName('last');
			}
		}
		}
		new Effect.Fade(this.fade,{	duration: 1.5, afterFinish: this._removeElement.bind(this) });
		
	},
	updateInformation: function(event)
	{
		
		//alert('test');
	},
	_error: function(event)
	{
		this.updateInformation(event);
		
	},
	_removeElement: function(event)
	{
		//var element = Event.element(event);
		if(this.fade)
		{
			this.fade.remove();
			this.fade= null;
		}
	},
	
	update:function()
	{
		this.create();
	}
});

var Filter = Class.create({
	initialize: function(items) {
		if(items instanceof Items)
		{
		    this.id = items.filter_id;
		    this.items = items;

		    this.filters_values = [];
		    this.create();
	    }
	    else
	    {
	    	alert('Pager only works with the Items Class');
	    	
	    }
	},
	create: function()
	{	
		//Collapse the menus down and add link to menu filters			

		this.filters = $(this.id).getElementsBySelector('.filter');
		
		this.rule_filters = [];
		
		/**
		 * Loop through all the elements that have filters and add them to an array per rule
		 */				
		for(var i = 0 ; i<this.filters.length ; i++)
		{		
			var filter = this.filters[i];
			filter.items = [];
			filter.rules = [];
			
			filter.observe('click',this._filter.bind(this));
			$(filter.parentNode).addClassName('linkFilter');
			
			var filters_rules = filter.className.replace(/^.*?filter\((.*?)\).*?$/,"$1");
			if(filters_rules)
			{
				var rules = filters_rules.split(/,/g);		
	
				for(var j=0; j < rules.length; j++)
				{	
										
					
					var rule = rules[j];
	
					filter.rules.push(rule);
				
					if(!this.rule_filters[rule])
					{
						this.rule_filters[rule] = [];
					}
					this.rule_filters[rule].push(filter);
				}
			}
		}
		
		/**
		 * Loop through all the items, and add them to the filter elements that they match against. 
		 */
		for(var i=0; i<this.items.data.length; i++)
		{
			this.items.data[i].filter_links = [];
			
			for(var type in this.items.data[i].categories)
			{
				var category_values = this.items.data[i].categories[type];
				var type_object = typeof category_values;
				
				if(type_object != 'object')
				{
					var tmp = category_values;
					category_values = [];
					
					category_values.push(tmp);
				}
				
				
				for(var j = 0; j<category_values.length; j++)
				{
					var category_value = category_values[j];
					var rule = type+":"+category_value;
					
					
					//TODO: Add all items in category
					//If the rule has filter element, add item onto each filter element
					if(this.rule_filters[rule])
					{
						for(var k=0; k<this.rule_filters[rule].length; k++)
						{
							this.rule_filters[rule][k].items.push(this.items.data[i]);
							
							this.items.data[i].filter_links.push(this.rule_filters[rule][k]);
						}
					}	
				}
			}
		}
		
		/**
		 * Calculate how many Items belong to each filter.
		 */
				
		for(var i = 0 ; i<this.filters.length ; i++)
		{
			this.filters[i].items_count = this.filters[i].items.length;
		}
		
		//Setup slider rules
		var slider_elements = $(this.id).getElementsBySelector('.filterSlider ul ul');
		for(var i = 0 ; i<slider_elements.length ; i++)
		{		
			$(slider_elements[i].parentNode).addClassName('linkSlide');
			$(slider_elements[i].parentNode).observe('click',this._slide.bind(this));
		}
		
		var reset_elements = $(this.id).getElementsBySelector('.reset a');
		for(var i = 0 ; i<reset_elements.length ; i++)
		{	
			//$(reset_elements[i]).observe('click',this.items.history.bind(this));
			$(reset_elements[i]).observe('click',this._reset.bind(this));
		}	
	},
	update: function()
	{
	
	},
	_reset: function(event)
	{
	//TODO: reset filters as well
		this.reset();
		

		dhtmlHistory.add('');
		
		event.stop();
	},
	reset: function()
	{

		
		
		for(var i = 0 ; i<this.filters.length ; i++)
		{
			$(this.filters[i].parentNode).removeClassName('active');
		}
		
		this.items.filters_required = [];
		this.filters_values = [];
		
		for(var i = 0 ; i<this.items.data.length ; i++)
		{
			$(this.items.data[i]).filtered_values = [];
			$(this.items.data[i]).filtered_types = [];
			$(this.items.data[i]).filtered = false;
		}
		
		this.items.resetData();
		this.items.updateHTML();
		
	},
	parentStack: [],
	_slide: function(event)
	{
		var item = Event.element(event);
		var itemText = item.firstChild.nodeValue;
		var itemFilterNode = $(item.parentNode.parentNode.parentNode);
		var itemFilterContentNode = $(item.parentNode.parentNode);
		
		
		var itemParentList = $(item.parentNode);
		this.parentStack.push(itemParentList);
		
		if(item.childList)
		{
			var itemList = item.childList;
			
		}
		else
		{
			var itemList = item.firstDescendant();
		}
		
		itemFilterContentNode.appendChild(itemList);

		var filterCategory = $(Builder.node('span',{className: 'categoryFilter'},itemText));
		
		filterCategory.filterParent = itemParentList;
		filterCategory.filterList = itemList;
		filterCategory.filterItem = item;
		filterCategory.filterControls = itemFilterContentNode;
		filterCategory.observe('click',this._slideReverse.bind(this));	

		itemFilterContentNode.stopObserving('click');
		itemFilterContentNode.observe('click',this._slideReverse.bind(this));


		itemFilterContentNode.addClassName('filterSliderBack');	
		
		var currentCategory = itemFilterNode.getElementsBySelector('h2 span').reduce();
		if(currentCategory)
		{
			filterCategory.previousCategory = currentCategory;	
			currentCategory.remove();
			
			
		}
		else
		{

			
			filterCategory.previousCategory = 'Products';	
		
		}
		
		var catHeader = itemFilterNode.getElementsBySelector('h2').reduce();
		catHeader.innerHTML = '';
		catHeader.appendChild(filterCategory);
		
		if(!itemFilterContentNode.titleNode)
		{
			itemFilterContentNode.titleNode = [];		
		}
		itemFilterContentNode.titleNode.push(filterCategory);
		
		var height = Math.max(itemList.clientHeight,itemParentList.clientHeight)+'px'
		//itemFilterNode.setStyle({height:height});	
		
		itemFilterContentNode.setStyle({height:height});	
		itemList.setStyle({left:'195px',top:'0px',position:'absolute',width:'161px'});//,height:height});	
		new Effect.Move(itemList, { x: -180, y: 0, mode: 'relative',transition:Effect.Transitions.linear,duration:0.5, fps: 22});
		
		//itemFilterContentNode.appendChild(itemParentList);
		itemParentList.setStyle({left:'0px',top:'0px',width:'161px',position:'absolute'});	
		new Effect.Move(itemParentList, 
							{ x: -180, y: 0, mode: 'relative',transition:Effect.Transitions.linear,duration: 0.5, fps: 22 }
						);
		
		Event.stop(event);
		return false;
			
	},
	_slideReverse: function(event)
	{
		var item = Event.element(event);
		var node = false;
		if(item.nodeName == 'SPAN')
		{
			node = item;
			
		}
		else if(item.nodeName == 'DIV')
		{			
			node = item.titleNode.pop();
			
		}
	
		if(!node)
		{
			Event.stop(event);
			return false;
			
		}
		
		node.filterItem.childList = node.filterList;

		node.filterList.setStyle({left:'15px',position:'absolute'});	
		node.filterParent.setStyle({left:'-180px',position:'absolute'});
		
		new Effect.Move(node.filterParent, { x: 195, y: 0, mode: 'relative'});
		new Effect.Move(node.filterList, { x: 165, y: 0, mode: 'relative'});

		
		if(node.previousCategory == 'Products')
		{
			node.filterControls.removeClassName('filterSliderBack');	
		}
		
		//Set position post move
		if(item.nodeName == 'SPAN' && item.previousCategory)
		{
			item.replace(item.previousCategory);
		}
		else if(item.nodeName == 'DIV' && node.parentNode)
		{
			node.replace(node.previousCategory);
		}
		Event.stop(event);
		return false;
		
	},
	_filter: function(event)
	{
		var item = Event.element(event);
		
		// Toggle Filter State.
		if($(item.parentNode).hasClassName('active'))
		{
			item.activeFilter = false;
			$(item.parentNode).removeClassName('active');
			
		}
		else
		{
			item.activeFilter = true;
			$(item.parentNode).addClassName('active');
		}
		
		for(var k=0; k < item.rules.length; k++)
		{	
			var rule_array = item.rules[k].split(/:/);
			var type = rule_array[0];
			var value = rule_array[1];
			this.items_to_filter = item.items;
				
			this.filterItems( type, value, item.activeFilter );
		}
		var query = '';
		for(var i=(this.filters_values.length-1); i>=0; i--)
		{
			query += this.filters_values[i][0]+":"+this.filters_values[i][1]+";";
		
		}
		

		dhtmlHistory.add('#'+query);
		
		this.items.filterData();
		this.items.updateHTML();
		event.stop();
	},
	filterItems: function(type, value, activeFilter)
	{
		var ruleAdded = 0;
		items = this.items_to_filter;
		for(var j=0; j < items.length; j++)
		{
				
			if(activeFilter==false)
			{
				ruleAdded--;
				items[j].filtered = false;
				items[j].filtered_values[type] = items[j].filtered_values[type].without(value);
									
				if(items[j].filtered_values[type].length==0)
				{
					items[j].filtered_types = items[j].filtered_types.without(type);			
				}					
			}
			else
			{	
								
				if(!items[j].filtered_values[type])
				{
					items[j].filtered_values[type] = [];
				}
				
				ruleAdded++;
				
				
				items[j].filtered_types.push(type);
				items[j].filtered_values[type].push(value);					
				items[j].filtered = true;	


					
				
				for(var l = 0; l < items[j].filter_links.length; l++ )
				{
					element_item_count = items[j].filter_links[l].items_count-1;
				}	
			}	
		}
		if(ruleAdded>0)
		{
			this.items.filters_required.push(type);
			this.filters_values.push([type,value]);
		}
		else if(ruleAdded<0)
		{
			this.items.filters_required.splice(this.items.filters_required.indexOf(type),1);
			for(var i=(this.filters_values.length-1); i>=0; i--)
			{
				if(this.filters_values[i][0]==type && this.filters_values[i][1] == value)
				{
					this.filters_values.splice(i,1);					
				}
				
			}
			
		}	
	
	}
	
});

var Order = Class.create({
	initialize: function(items) {
		if(items instanceof Items)
		{
		    this.id = items.order_id;
		    this.items = items;

		    this.create();
	    }
	    else
	    {
	    	alert('Order only works with the Items Class');
	    	
	    }
	},
	create: function()
	{	
		if($(this.id))
		{
			$(this.id).observe('change',this._order.bind(this));
		}				
	},
	update: function()
	{
	
	},
	_order: function(event)
	{
		var item = Event.element(event);
		
		//item.reverseOrder = !item.reverseOrder;
		if(item.options[item.selectedIndex])
		{
			if(order_rule = item.options[item.selectedIndex].className.replace(/^.*?order\((.*?)\).*?$/,"$1"))
			{
				this.items.orderData(order_rule);//, item.reverseOrder);
				this.items.updateHTML();
				event.stop();
			}
		}
	}
});
var Item = Class.create({
	initialize: function(categories,order,information)
	{
		
	    this.information = information;
	    this.categories = categories;
	    this.order = order;
	    this.filtered_values = [];
	    this.filtered_types = [];	    
	    
	},
	html: function(grid,style)
	{
		var node = Builder.node('div',{className: style.item},[
										Builder.node('div',[
											Builder.node('p','Item Template')
										])
									]);
									
									
									
		return node;
		
	}
});


var Items = Class.create({
	initialize: function(display_id, pager_id, filter_id, order_id, info_id, data, grid, style) {

		
		
	    this.grid = Object.extend({items: 9, cols: 3}, grid || {});
	    this.style = Object.extend({row: 'itemRow',cell: 'itemCell',grid: 'items',item: 'productSmall'}, style || {});


	    this.display_id = display_id;
	    this.pager_id = pager_id;
	    this.info_id = info_id;
	    this.filter_id = filter_id;
	    this.order_id = order_id;

	    this.data = [];
	    this.data_filtered = [];
	    this.data_typed = [];
	    
		this.filters_required = [];
	    

		this.getData(data);
		this.orderData('brand');
		this.pager = new Pager(this);
		this.filter = new Filter(this);
		this.order = new Order(this);
		this.display = new Display(this);
		

		

	},
	history: function(newLocation, historyData)
	{
		
		var history_state = newLocation;
		var current_state = this.filter.filters_values;
		
		var filters_missing = [];
		var filters_extra = [];
		
		var history_array = history_state.split(/;/);
		
		for(var i=(current_state.length-1); i>=0; i--)
		{
			if(current_state[i])
			{
				var matches = history_array.include(current_state[i].join(':'));
				
				if(!matches)
				{
					item = this.filter.rule_filters[current_state[i][0]+":"+current_state[i][1]][0];
					$(item.parentNode).removeClassName('active');
					
					this.filter.items_to_filter = item.items;
					this.filter.filterItems( current_state[i][0], current_state[i][1], false);                                                          
							
				}
				else
				{
					history_array = history_array.without(current_state[i].join(':'));
				}
			}
			
		}
		for(var i=(history_array.length-1); i>=0; i--)
		{
			if(this.filter.rule_filters[history_array[i]])				
			{
				item = this.filter.rule_filters[history_array[i]][0];
				$(item.parentNode).addClassName('active');
				
				
				rule = history_array[i].split(':');
				this.filter.items_to_filter = item.items;
				this.filter.filterItems(rule[0], rule[1], true);
			}
			
		}
		

		this.filterData();
		this.updateHTML();
		
	},
	getData: function(data) {

		this.data = data;

		//TODO: Inital data filter state, all data may do
		this.data_filtered = this.data;

	},	
	resetData: function() 
	{
		this.data_filtered = this.data;
	},
	filterData: function(type,value,keepFilter) 
	{
		
		//window.location.href =  window.location.href+"#type";
		
		
		this.data_filtered = [];
		//alert(this.data_typed.length);
	
		//var test = this.filters_required.uniq();
	
		//Loop through and add new filter and add to filtered_data
		var length = this.data.length;
		
		for(var i=0; i < length; i++)
		{	
			var item = this.data[i];
				
			if(item.filtered_types.length >= this.filters_required.uniq().length)
			{
				this.data_filtered.push(item);
			}
						
		}
	},
	orderData: function(type)//, reverse) 
	{
		this.data_filtered;		
	
		//var reverse = reverse || false;
		
		//Loop through and add new filter and add to filtered_data

		this.data_filtered.sort(function(b,a)
				{
					a1 = 0;
					b1 = 0;
					if(a.order[type])
					{
						a1 = a.order[type];
					}
					
					if(b.order[type])
					{
						b1 = b.order[type];
					}
					
				   if(a1 > b1)      //a comes after b, alphabetically
					      return(-1); //so sequence it earlier
					   if(a1 < b1)      //a comes before b, alphabetically
					      return(1);  //so sequence it later
					   return(0);
						   
				}); 
			 

	

	},
	updateHTML: function() {

		this.pager.page = 1;

		this.filter.update();
		this.pager.update();
		this.display.update();
	}



});