var Filter = new Class({
	
	Implements: [Options, Events],
	
	options: {
		dynamicfilters    : true,   //Build dynamic filter list, such as shown on the left side at the resultlist
		resultlist        : true,   //Build resultlist, set this to false for performance if you don't want a resultlist
		updateafterchange : true,  //Excecutes Json request, updates elements after a filter change (otherwise excecute updateResult manually)
		loader            : true,   //Display loaders
		debug             : false,  //Debug
		trans             : {choosemore: 'kies meer', removeall: 'alles wissen', remove: 'wis'},
		maxitems          : 10,
		multipleselect    : $empty, //Overwrite multipleselect defined in filterconfig for this filter instance
		availablefilters  : [],     //Filter elements which are used. If empty all filters are valid
		onFilterChange    : $empty, //Custom event handler which is excecuted on change of filters
		onFilterAdd       : $empty, //Custom event handler which is excecuted on add of filters
		onFilterRemove    : $empty, //Custom event handler which is excecuted on removal of filters
		onAfterFilterAdd    : $empty, //Custom event handler which is excecuted on add of filters
		onAfterFilterRemove : $empty, //Custom event handler which is excecuted on removal of filters
		onRequestStart    : $empty, //Custom event handler when request is started
		onRequestComplete : $empty, //Custom event handler when request is finished
		sFormID						: $empty
	},

	initialize: function(options)
	{
		this.setOptions(options);
		this.bActiveRequest = false;
		this.aActiveFilters = new Hash({});
		this.oParams = new Hash({}); //Initialize parameter object to send with Json
		this.aAddFilters = new Hash({}); //Initialize filter array
		this.aRemoveFilters = new Hash({}); //Initialize filter array
		this.oParams.set('availablefilters', this.options.availablefilters);
		this.sActiveURI = '';
		
		this.URIListener.periodical(1000, this); //Scans URL for changes (when user navigates back and forth in browser)
		
		//Save resultcount HTML to replace later on
		this.aResultcountHtml = [];
		var i = 0;
		$$('.resultcount').each(function(el)
		{
			this.aResultcountHtml[i] = el.get('text');
			i++;
		}.bind(this));

		this.updateResult(false);
	},

	addFilter: function(sKey, vVal) //setting filter to 0 will remove the filter
	{
		if (this.aAddFilters.has(sKey)) //Filter key already exists. add Value to array
		{
			vExistingVal = this.aAddFilters.get(sKey);
			if (typeof(vExistingVal) != 'object') {
				aValues = [vExistingVal];
			}
			else 
			{
				aValues = vExistingVal;
			}
			aValues.push(vVal);
			vAddVal = aValues;
		}
		else
		{
			vAddVal = vVal;
		}
		this.aAddFilters.set(sKey, vAddVal);
		this.oParams.set('addfilters', this.aAddFilters);
		this.fireEvent("onFilterAdd", [sKey, vVal]);
		this.onFilterChange();
	},
	
	addMultipleFilters: function(aFilters)
	{
		this.aAddFilters.extend(aFilters);
		this.oParams.set('addfilters', this.aAddFilters);
		aFilters.each(function(vVal, sKey) {
			this.fireEvent("onFilterAdd", [sKey, vVal]);
		}.bind(this));  
		this.onFilterChange();
	},

	removeFilter: function(sKey, vVal)
	{
		this.aRemoveFilters.set(sKey, vVal);
		this.oParams.set('removefilters', this.aRemoveFilters);
		
		if (this.aAddFilters.has(sKey))
		{
			if (typeof(this.aAddFilters.get(sKey)) == 'object' && this.aAddFilters.get(sKey).contains(vVal))
			{
				this.aAddFilters.get(sKey).erase(vVal);
			}
			else
			{
				this.aAddFilters.erase(sKey);
			}
			this.oParams.set('addfilters', this.aAddFilters);
		}
		
		this.fireEvent("onFilterRemove", [sKey, vVal]);
		this.onFilterChange();
	},

	removeFilters: function(aFilters)
	{
		aFilters.each(function(sKey) {
			this.aRemoveFilters.set(sKey);
			this.fireEvent("onFilterRemove", [sKey]);
		}.bind(this));
		this.oParams.set('removefilters', this.aRemoveFilters);
		this.onFilterChange();
	},

	removeAll: function()
	{
		this.oParams.set('removefilters', 'all');
		this.fireEvent("onFilterRemove", ['all', 0]);
		if (!this.options.bRedirAfterRemove)
			this.onFilterChange();
	},

	onFilterChange: function()
	{
		this.fireEvent("onFilterChange");
		if (this.options.updateafterchange)
		{
			this.updateResult(true); //Excecute JSON request and update all DOM
		}
	},

	updateResult: function(bFetchResultlist)
	{
		this.oParams.set('resultlist', bFetchResultlist);
		this.oParams.set('dynamicfilters', this.options.dynamicfilters);
		this.oParams.set('debug', this.options.debug);
		this.oParams.set('multipleselect', this.options.multipleselect);
		
		oResultlistWrapper = $('resultlist_wrapper');
		if ($chk(oResultlistWrapper) && bFetchResultlist)
		{
			oResultlistWrapper.empty(); //Empty resultlist
			
			if (this.options.loader)
			{
				$$('.resultlist_loader').each(function(el)
				{
					el.setStyle('display', 'block'); //Display loader icon
				});
			}
			
			$$('div.pagebrowser').each(function(el)
			{							
				el.empty()
			}.bind(this));
		}

		if ($chk($('filterlist')))
		{
			this.oFilterList = $('filterlist');
			this.oFilterList.empty();
			if (this.options.loader)
			{
				$$('.filter_loader').each(function(el)
				{
					el.setStyle('display', 'block'); //Display loader icon
				});
			}
		}
			
		$$('.resultcount').each(function(el)
		{
			el.setStyle('visibility', 'visible');
			if (this.options.loader)
			{
				el.empty();
				el.addClass('count_loader'); //Display loader	
			}
		}.bind(this));
		
		//Filter JSON request uitvoeren
		if (this.oJsonRequest == null || (this.oJsonRequest && !this.oJsonRequest.running)) //Check if no json request is running
		//if (!this.bActiveRequest) //Check if JSON request is still running
		{
			this.fireEvent("onRequestStart");
			this.bActiveRequest = true;
			this.oJsonRequest = new Request.JSON({url: '/phplib/dataservice/filter/filter.php', 
				onFailure: function()
				{
					this.fireEvent("onRequestComplete");
					//this.bActiveRequest = false;
				},
				onSuccess: function(oJson) { //Correcte response van PHP
					if (oJson['query'] && this.options.debug) 
					{
						document.all ? alert(oJson['query']) : console.log(oJson['query']);
					}
					
					if (oJson['error'])
						alert(oJson['error']);
					else
					{
						this.aAddFilters.each(function(vValue, sKey) {
							this.fireEvent("onAfterFilterAdd", [sKey, vValue]);
						}.bind(this));
						
						this.aRemoveFilters.each(function(sKey) {
							this.fireEvent("onAfterFilterRemove", [sKey]);
						}.bind(this));
						
						//Update active filter list, and add links to remove filters
						if ($chk($('activefilters')) && oJson['activefilters'])
						{
							$('activefilters').empty(); //Clear active filter list
							this.aActiveFilters = oJson['activefilters'];
							this.showActiveFilters(oJson['activefilters']);
						}
									
						//Update Resultcount
						this.iResultCount = oJson['resultcount'];
						var i = 0;		
						$$('.resultcount').each(function(el)
						{
							sResultcountHtml = this.aResultcountHtml[i];
							if (sResultcountHtml.test("count"))
							{							
								var oReplacements = {count: this.iResultCount};
								var sResultCount = sResultcountHtml.substitute(oReplacements);
							}
							else
							{
								var sResultCount = this.iResultCount;
							}
							
							if (this.options.loader)
								el.removeClass('count_loader');
							
							el.set('html', sResultCount);
							i++;		
						}.bind(this));
						
						
						
						// Update resultstart
						this.iResultStart = oJson['resultstart'];
						$$('.resultstart').each(function(el)
						{							
							if (this.iResultStart>0)
								el.set('html', this.iResultStart);
						}.bind(this));
						
						// Update resultend
						this.iResultEnd = oJson['resultend'];
						$$('.resultend').each(function(el)
						{
							if (this.iResultEnd>0)
								el.set('html', this.iResultEnd);
						}.bind(this));
												
						//Stop loader
						if (this.options.loader)
						{
							$$('.filter_loader').each(function(el)
							{
								el.setStyle('display', 'none'); //Display loader icon
							});
							$$('.resultlist_loader').each(function(el)
							{
								el.setStyle('display', 'none'); //Display loader icon
							});
						}
						
						//Update resultlist
						if ($chk($('resultlist_wrapper')) && bFetchResultlist)
						{
							$('resultlist_wrapper').set('html', oJson['resultlist']);
						}
						
						// div elementen met class pagebrowser setten
						$$('div.pagebrowser').each(function(el)
						{							
							if (oJson['pagebrowser']) el.set('html', oJson['pagebrowser']);
						}.bind(this));
						
						//update dynamic filterlist
						if (this.options.dynamicfilters)
						{
							this.buildFilterList(oJson['filters']);
						}
						
						//reset parameters
						this.buildURIParams();
						this.oParams.empty();
						this.aRemoveFilters.empty();
						this.aAddFilters.empty();

						this.fireEvent("onRequestComplete");
					}
				}.bind(this)
			}).send('data='+JSON.encode(this.oParams));
		}
	},

	showActiveFilters: function(aActiveFilters)
	{
		if (aActiveFilters.length > 0)
		{
			$('no_selection').setStyle('display', 'none');
			aActiveFilters.each(function(item, index) {
				oActiveFilterItem = new Element('li').set('html', item['grouplabel'] + ' : <span class="value">' + item['display'] + '</span> <a>'+this.options.trans.remove+'</a>').injectInside($('activefilters'));
				oActiveFilterRemove = oActiveFilterItem.getElement('a');
				oActiveFilterRemove.addEvent('click', function() {
					this.removeFilter(item['key'], item['value']); //Remove filter
					this.updateResult(true);
				}.bind(this));
			}.bind(this));
			oRemoveAll = new Element('li', {'class' : 'removeall'}).set('html', this.options.trans.removeall).injectInside($('activefilters'));
			oRemoveAll.addEvent('click', function() {
				this.removeAll(); //Remove all filters
				this.updateResult(true);
			}.bind(this));
		}
		else
		{
			$('no_selection').setStyle('display', 'block');
		}
	},

	buildFilterList: function(aFilters)
	{
		$each(aFilters, function(aFilterGroup, sIdentifier) { //Iterate through all filtergroups
			iActiveCount = 0;
			iInactiveCount = 0;
			iFilterCount = 0;
			bDisplayFilter = false;                                       
			oFilterGroupHeader       = new Element('li', {'id' : sIdentifier, 'class' : 'filter_list_header', 'text' : aFilterGroup['label']});
			oFilterGroupListActive   = new Element('ul', {'class' : 'filter_list_active'}).injectInside(oFilterGroupHeader);
			oFilterGroupListInactive = new Element('ul', {'class' : 'filter_list_inactive'}).injectAfter(oFilterGroupListActive);
			oFilterGroupListMore     = new Element('ul', {'class' : 'filter_list_inactive_more'}).injectAfter(oFilterGroupListInactive);
			$each(aFilterGroup['items'], function(item, sValue) //Iterate through filters
			{
				if (item['active'])
				{
					iActiveCount++;
				}
				else
				{
					iInactiveCount++;
				}
				iFilterCount++;
			});
			
			var iCounter = 0;
			$each(aFilterGroup['items'], function(item, sValue) { //Iterate through filters
				//Uitzondering voor Pools - Voorzieningen bevatten htmlentities. escapen
				if (sIdentifier == 'facility')
				{
					item['display'] = unescapeHtml(item['display']);
				}
				
				if (item['resultcount'] == this.iResultCount && !bDisplayFilter && !item['active'])
					bDisplayFilter = false;
				else
					bDisplayFilter = true;
				if (item['active'])
				{
					oFilterItemActive = new Element('li', {'id' : sIdentifier + '_' + sValue, 'class' : 'selected'}).injectInside(oFilterGroupListActive);
					oFilterItemActiveLink = new Element('a', {'class' : 'remove', 'href' : '', 'text' : item['display']}).inject(oFilterItemActive);
					oFilterItemActiveLink.addEvent('click', function(e) 
					{
						e.stop();
						this.removeFilter(sIdentifier, sValue);
						if (this.options.updateafterchange)
						{
							this.updateResult(true);
						}
					}.bind(this));
				}
				else
				{
					if (iCounter > this.options.maxitems && iActiveCount == 0 && sIdentifier != 'country') //Inject inside UL.filter_list_more
					{
						oFilterList = oFilterGroupListMore;
					}
					else //Inject inside UL.filter_list_inactive
					{
						oFilterList = oFilterGroupListInactive;
					}
					oFilterItem = new Element('li', {'id' : sIdentifier + '_' + sValue}).injectInside(oFilterList); //Add filter to list
					oFilterItemLink = new Element('a', {'href' : ''}).set('text', item['display']+' ('+item['resultcount']+')').inject(oFilterItem);
					if (item['resultcount'] > 0) 
					{
						oFilterItemLink.addEvent('click', function(e) 
						{
							e.stop();
							if (this.options.updateafterchange)
							{
								this.addFilter(sIdentifier, sValue);
								this.updateResult(true);
							}
							else
							{
								if ($(sIdentifier + '_' + sValue).hasClass('selected'))
								{
									this.removeFilter(sIdentifier, sValue);
									$(sIdentifier + '_' + sValue).removeClass('selected');
								}
								else
								{
									this.addFilter(sIdentifier, sValue);
									$(sIdentifier + '_' + sValue).addClass('selected');
								}
							}
						}.bind(this));
					}
					iCounter++;
				}

			}.bind(this));
			
			if (iInactiveCount == 0 && iActiveCount == 0)
			{
				bDisplayFilter = false;
			}

			if (bDisplayFilter && $chk(this.oFilterList))
			{
				oFilterGroupHeader.injectInside(this.oFilterList); //Add filter to list
			}
			
			if (iInactiveCount > 0)
			{
				//bCollapsible = ((iInactiveCount > this.options.maxitems) || iActiveCount > 0); //Minimaal 1 filter actief, in/uitklapmechanisme voor extra filters
				if (iActiveCount > 0) 
				{
					this.addChooseMoreButton(oFilterGroupListInactive);
				}
				else if (iInactiveCount > this.options.maxitems && sIdentifier != 'country')
				{
					this.addChooseMoreButton(oFilterGroupListMore);     
				}
			}
		}.bind(this));
	},
	
	addChooseMoreButton: function(oULToToggle)
	{
		oChooseMore = new Element('li', {'class' : 'filter_list_more'}).set('text', this.options.trans.choosemore).injectBefore(oULToToggle);
		var collapsible = new Fx.Slide(oChooseMore.getNext(), { 
			duration: 500, 
			transition: Fx.Transitions.linear
		});
		oChooseMore.addEvent('click', function() {
			this.toggleClass('filter_list_more');
			this.toggleClass('filter_list_less');
			collapsible.toggle();
		});
		collapsible.hide();
	},
	
	addFormEvents: function()
	{
		this.options.availablefilters.each( function(sElement) 
		{
			$(this.options.sFormID).getElements("*[name^="+sElement+"]").each(function(oElement)
			{
				//Add onchange events
				oElement.addEvent('change', function() 
				{
					aElementNameParts = oElement.name.split("[");
					sFilterName  = aElementNameParts[0];
					vFilterValue = oElement.value;
					
					if (oElement.get("type") == "checkbox")
					{
						if (oElement.get("checked"))
						{
							this.addFilter(sFilterName, vFilterValue); //Add filter
						}
						else
						{
							this.removeFilter(sFilterName, vFilterValue); //Remove filter
						}
					}
					else
					{
						this.addFilter(sFilterName, vFilterValue); //Add filter
					}
					
					if (this.options.updateafterchange)
					{
						this.updateResult(true);
					}
				}.bind(this) );
			}.bind(this) );
		}.bind(this) );
	},
	
	buildURIParams : function() 
	{
		if (this.aActiveFilters.length > 0)
		{
			sParams = '#';
			var i = 0;
			this.aActiveFilters.each(function(item, index) {
				sParams += (i==0) ? '' : '&';
				sParams += item['key'] + '=' + item['value'];
				i++;
			});
			document.location.href = sParams;
		}
		this.sActiveURI = document.location.href;
	},
	
	readURIParams : function() 
	{
		if (this.sActiveURI.test('#') || this.sActiveURI.substring(this.sActiveURI.length-1) == '/')
		{
			aURIParts = this.sActiveURI.split('#');
			this.oParams.set('removefilters', 'all'); //Reset all filters
			if (aURIParts.length > 1)
			{
				aURIParts[1].split('&').each(function(sParamValuePair)
				{
					aSplit = sParamValuePair.split('=');
					if (aSplit.length == 2)
					{
						this.aAddFilters.set(aSplit[0], aSplit[1]);
					}
					this.oParams.set('addfilters', this.aAddFilters);
				}.bind(this));
			} 
			this.oJsonRequest.cancel(); //Cancel JSON request if running already. if a user click back fast                                                          
			this.updateResult(true);
		}   
	},
	
	URIListener : function() 
	{
		if (this.sActiveURI.length == 0) //Set active URI initial
		{
			this.sActiveURI = document.location.href;
		}
		if (this.sActiveURI != document.location.href) //URI is veranderd. (gebruiker heeft bv. back button geklikt)
		{
			this.sActiveURI = document.location.href;
			this.readURIParams(); //Parameters uit URI vissen
		}
	},
	
	getResultCount : function()
	{
		return this.iResultCount;
	}
});

function unescapeHtml(tsString) 
{
	var oTemp = new Element("div");
	oTemp.set('html', tsString);
	var sResult = oTemp.get('text');
	oTemp.dispose();    
	return sResult;
} 
