if(!console) var console = {log:function(){}};

var SlalomFilters = $H();

SlalomFilters.Base = new Class({
	Implements: Options,
	options: {
		// Default values
		url:		false, // Required
	    page:   	false, // Required
	    site:   	false, // Required
	    region: 	false, // Required
	    theme:  	false, // Required
	    mode:   	false,
	    group:  	false,
		container:	'slalom-filter-results',
		table:		'slalom-filter-filters',
		filters:	$H()
	},
	initialize: function(options){
		this.setOptions(options);
		this.filters = $H();
		this.rows = $H();
		this.appliedFilters = $H();
		
		console.log(options);
		
		// Error checking
		$A(['url','page','site','region','theme']).each(function(option){
			if(!this.options[option]){
				if(this.options.mode != 'publish' && this.options.mode != ""){
					alert('SlalomFilter is missing required parameter "'+option+'".');
					this.error = true;
				}
			}
		},this);
		
		if(this.error) return false;
		
		window.addEvent('domready',this.create.bind(this));
	},
	create: function(){
		this.table = new Element('tbody').inject($(this.options.table));
		this.tableExtended = new Element('tfoot').inject($(this.options.table)).fade('hide').setStyle('display','none');
		this.overlay = new Element('div',{'class':'slalom-filter-overlay','styles':{'display':'none','opacity':0.75}}).inject(document.body);

		this.request = new Request.HTML({
            url:    this.options.url,
            method: 'post',
            update: $(this.options.container),
            onRequest: function(){
            	var overlayPosition = $(this.options.container).getCoordinates();
            	overlayPosition.display = 'block';
            	this.overlay.setStyles(overlayPosition);
            }.bind(this),
            onComplete: function(){
            	this.overlay.setStyles({
            		'display':	'none'
            	});
            }.bind(this)
        });
        
        $H(this.options.filters).each(function(filter,name){
        	this.registerFilter(name,new SlalomFilters['Filter_'+filter.type](filter,name),filter.extended);
        },this);
        if(this.grabExtended)
        	this.tableExtended.inject(this.table,'after');
	},
	makeRequest: function(options){
		options = $H(options);
		// The actual request is made
		var postvalues = $H({
			ajax:	true,
		    page:   this.options.page,
		    site:   this.options.site,
		    region: this.options.region,
		    mode:   this.options.mode=='publish'?'':this.options.mode,
		    theme:  this.options.theme,
		    group:  this.options.group,
		    filters:this.options.filters
		}).extend(this.appliedFilters);
		var url = new URI(this.options.url);
		var query = new Object();
		if(options.sort){
			query.sort = new Object();
			query.sort.prod_prod = options.sort;
		}
		if(options.pager){
			query[options.pager] = options.page;
		}
		if(options.reset){
			query['search_clear'] = 'prod_prod';
		}
		url.setData(query,true);
		this.request.options.url = url.toString();
		this.request.post(postvalues);
	},
	registerFilter: function(name,filter,extended){
		// Register and create a filter
		console.log('Registering filter "%s" of type %s ',name,filter.type);
		this.filters[name] = filter;
		this.rows[name] = filter.create(this);
		if(extended){
			this.grabExtended = true;
			this.tableExtended.grab(this.rows[name]);
		} else {
			this.table.grab(this.rows[name]);
		}
	},
	applyFilters: function(filter){
		$H(filter).each(function(value,key){
			if(typeof(value) == 'object' && !value.length){
				value.push('');
			}
			console.log("Applying filter: %s",key,value);
			this.appliedFilters[key] = value;
		},this);
		this.makeRequest();
	},
	collect: function(collect){
		console.log("Collecting: %o ",collect);
		$H(collect.filters).each(function(values,filter){
			if(this.filters[filter])
				this.filters[filter].update(values);
		},this);
		
		this.hookPager();
	},
	setSort: function(sort){
		this.makeRequest({'sort':sort});
	},
	hookPager: function(){
		$$('.pagerlink').each(function(item){
			var uri,qry,pager,page;
			uri = new URI(item.href);
			qry = uri.getData();
			$H(qry).each(function(v,k){
				if(k.contains('pager')){
					pager = k;
					page = v;
				}
			});
			if(pager){
				item.addEvent('click',function(e){
					e.stop();
					this.makeRequest({'pager':pager,'page':page});
				}.bind(this));
			}
		},this);
	},
	doreset: function(){
		this.appliedFilters = $H();
        this.filters.each(function(filter,name){
        	filter.doreset();
        },this);
        this.makeRequest({'reset':true});
	},
	toggleExtended: function(){
		this.extendedVisible = !this.extendedVisible;
		if(this.extendedVisible){
			this.tableExtended.setStyle('display','').fade('in');
		} else {
			this.tableExtended.fade('hide').setStyle('display','none');
		}
		//this.tableExtended.setStyle('display',this.extendedVisible?'':'none');
	}
});

SlalomFilters.Utils = $H();
SlalomFilters.Utils.round = function(num,dec,method){
	if(dec == undefined) return num;
	else if(dec == 0){
		num = Math.round(num)
	}
	else {
		var multiplier = Math.pow(10,dec);
		num = num * multiplier;
		switch(method){
			case 'ceil':
				num = Math.ceil(num);
				break;
			case 'floor':
				num = Math.floor(num);
				break;
			default:
				num = Math.round(num);
				break;
		}
		num = num / multiplier;
	}
	return num;
}
SlalomFilters.Utils.ceil = function(num,dec){ return SlalomFilters.Utils.round(num,dec,'ceil')}
SlalomFilters.Utils.floor = function(num,dec){ return SlalomFilters.Utils.round(num,dec,'floor')}
SlalomFilters.Utils.modify = function(num,modifier,modify){
	return eval(num+modifier+modify);
}

SlalomFilters.TmplButton = new Class({
	Implements: Options,
	options: {},
	initialize: function(value,label,place,reverse){
		this.applied = false;
		this.value = value;
		this.label = label;
		this.hit = false;
		this.reverse = reverse;
		console.log("BUTTON: %o",this);
		this.element = new Element('div',{'text':label,'class':'normal'});
		this.counter = new Element('span',{'text':''}).inject(this.element);
		this.element.addClass('slalom-filter-button');
		if(this.reverse)
			this.element.addClass('slalom-filter-button-applied');
		this.element.addClass('slalom-filter-button-disabled');
		this.element.inject(place);
	},
	setCount: function(i){
		if(i > 0){
			this.counter.set('text',' ['+i+']');
		} else {
			this.counter.set('text','');
		}
	},
	apply: function(){
		this.applied = true;
		console.log('Applying filter',this.applied);
		if(this.reverse)
			this.element.removeClass('slalom-filter-button-applied');
		else
			this.element.addClass('slalom-filter-button-applied');
	},
	unapply: function(){
		this.applied = false;
		if(this.reverse)
			this.element.addClass('slalom-filter-button-applied');
		else
			this.element.removeClass('slalom-filter-button-applied');
		}
});

// Base class for filters
SlalomFilters.FilterBase = new Class({
	initialize: function(type,params){
		this.type 	= params.type;
		this.field 	= params.field;
		this.field_send 	= params.field_send || params.field;
		this.searchtype = params.searchtype || 'search';
		this.modifier = params.modifier;
		this.modify = params.modify;
		this.title 	= params.title;
	},
	createRow: function(){
		this.row = new Element('tr');
		this.cell = new Element('td',{text:this.title,'class':'normal slalom-filter-row slalom-filter-label'}).inject(this.row);
	}
});

// Options filter class
SlalomFilters.Filter_options = new Class({
	Extends: SlalomFilters.FilterBase,
	initialize: function(params,name){
		console.log(params);
		this.name = name;
		this.parent('options',params);
		this.multi = params.multi;
		this.reverse = params.reverse && params.multi;
		this.populate = params.populate;
		this.separator = params.separator;
		this.populated = false;
		this.hideifempty = params.hideifempty;
		this.options = $H(params.options);
		this.values = $A([]);
	},
	create: function(Base){
		this.Base = Base;
		this.createRow();
		
		this.cell 		= new Element('td',{'class':'slalom-filter-row'}).inject(this.row);
		
		this.buttons = $H();
		
		if(!this.populate){
			this.options.each(function(option,k){
				this.buttons[k] 	= new SlalomFilters.TmplButton(option.value,option.title,this.cell,this.reverse);
				if(this.reverse)
					this.values.push(this.buttons[k].value);
			},this);
			new Element('div',{'styles':{'clear':'both'}}).inject(this.cell);
		}

		return this.row;
	},
	update: function(collect){
		console.log("Filter %s recieved values: %o",this.name,collect);
		if(this.populate && !this.populated){
			console.log("Populating filter %s with values %o",this.name,collect.populate);
			
			console.log("#########",$H(collect.populate).getLength());
		
			this.options = this.Base.options.filters[this.name].options = collect.populate;
			$H(collect.populate).each(function(option,k){
				this.buttons[k] = new SlalomFilters.TmplButton(option.value,option.title,this.cell,this.reverse);
				if(this.reverse)
					this.values.push(this.buttons[k].value);
			},this);

			if(this.hideifempty && !$H(this.buttons).getLength()){
				console.log('Removing filter ',this.name);
				this.Base.rows[this.name].dispose();
				return false;
			}

			new Element('div',{'styles':{'clear':'both'}}).inject(this.cell);
			this.Base.options.filters[this.name].populated = this.populated = true;
		}
		$H(this.buttons).each(function(button,k){
			console.log("Button object: %o",button);
			if(!this.multi){
				button.setCount(collect.options[k]);
			}
			button.element.removeEvents();
			if(button.applied){
				console.log("Modifying button events");
				button.element.addEvent('click',this.removefilter.pass(k,this));
			} else if(collect.options[k] > 0){
				this.buttons[k].hit = true;
				console.log("Adding event to and activating button %s",button.label);
				button.element.removeClass('slalom-filter-button-disabled').addEvent('click',this.applyfilter.pass(k,this));
			} else if(this.multi && button.hit) {
				console.log("Adding event to button %s",button.label);
				button.element.addEvent('click',this.applyfilter.pass(k,this));
			} else {
				console.log("Unapplying and disabling button %s",button.label);
				button.element.removeClass('slalom-filter-button-applied');
				button.element.addClass('slalom-filter-button-disabled');
			}
		},this);
	},
	applyfilter: function(button){
		this.buttons[button].apply();
		var value 	= this.buttons[button].value,
			values 	= [value],
			like	= '%',
			sep		= this.separator,
			operator= sep ? 'like' : 'equal';
			
		if(sep){
			values.combine([like+sep+value,value+sep+like,like+sep+value+sep+like]);
		}

		if(this.reverse){
			for(var i=0;i<values.length;i++){
				this.values.erase(values[i]);
			}
		} else {
			for(var i=0;i<values.length;i++){
				this.values.push(values[i]);
			}
		}
		console.log('Setting button state to true ',this.buttons[button]);
		
		var filters = $H();
		filters[this.searchtype+'/'+this.field_send+'/'+operator] = this.values;
		this.Base.applyFilters(filters);
	},
	removefilter: function(button){
		this.buttons[button].unapply();
		var value 	= this.buttons[button].value,
			values 	= [value],
			like	= '%',
			sep		= this.separator,
			operator= sep ? 'like' : 'equal';
			
		if(sep){
			values.combine([like+sep+value,value+sep+like,like+sep+value+sep+like]);
		}

		if(this.reverse){
			for(var i=0;i<values.length;i++){
				this.values.push(values[i]);
			}
		} else {
			for(var i=0;i<values.length;i++){
				this.values.erase(values[i]);
			}
		}
		console.log('Setting button state to false ',this.buttons[button]);
		var filters = $H();
		filters[this.searchtype+'/'+this.field_send+'/'+operator] = this.values;
		this.Base.applyFilters(filters);
	},
	doreset: function(){
		this.buttons.each(function(button){
			button.unapply();
			if(this.reverse)
				this.values.push(button.value);
			else
				this.values.erase(button.value);
		},this);
	}
});

SlalomFilters.Filter_range = new Class({
	Extends: SlalomFilters.FilterBase,
	Implements: Options,
	options: {
		minlabel: 'Min',
		maxlabel: 'Max',
		decimals: 0,
		snappy: false
	},
	initialize: function(options,name){
		this.name = name;
		this.parent('range',options);
		this.setOptions(options);
	},
	create: function(Base){
		this.Base = Base;
		this.createRow();
		
		this.cell 	= new Element('td',{'class':'slalom-filter-row'}).inject(this.row);
		
		this.activated = false;
		this.applied = false;
		console.log("SLIDER: %o",this);
		
		this.scale = 100;

		this.table 	= new Element('table',{'cellpadding':'2','cellspacing':'0'});
		this.tbody  = new Element('tbody').inject(this.table);
		var row 	= new Element('tr').inject(this.tbody);

		this.minInput = new Element('input',{'class':'slalom-filter-slider-input'}).addEvent('blur',this.setRange.pass('min',this));
		this.minInput.disabled = true;
		this.container= new Element('div',{'class':'slalom-filter-slider-container'});
		this.maxInput = new Element('input',{'class':'slalom-filter-slider-input'}).addEvent('blur',this.setRange.pass('max',this));
		this.maxInput.disabled = true;

		new Element('td').adopt([this.minInput]).inject(row);
		new Element('td').adopt(this.container).inject(row);
		new Element('td').adopt([this.maxInput]).inject(row);

		this.gutter = new Element('div',{'class':'slalom-filter-slider-gutter'}).inject(this.container);
		this.gutter_ol = new Element('div',{'class':'slalom-filter-slider-gutter-ol'});

		this.table.inject(this.cell);			
		
		return this.row;
	},
	update: function(collect){
		console.log('Slider Collect %o',collect);
		if(!this.activated){
			if(this.modifier){
			    collect.min = SlalomFilters.Utils.modify(collect.min,this.modifier,this.modify);
			    collect.max = SlalomFilters.Utils.modify(collect.max,this.modifier,this.modify);
            }    
			
			this.scaleMin = this.minInput.value = SlalomFilters.Utils.floor(collect.min,this.options.decimals);
			this.scaleMax = this.maxInput.value = SlalomFilters.Utils.ceil(collect.max,this.options.decimals);
			
			if(this.scaleMin == this.scaleMax){
				this.activated = false;
				if(this.options.hideifempty){
					console.log('Removing filter ',this.name);
					this.Base.rows[this.name].dispose();
				}
				return false;
			}
			
			this.minInput.disabled = false;
			this.maxInput.disabled = false;

			this.minKnob = new Element('div',{'class':'slalom-filter-slider-knob slalom-filter-slider-knob-min'});
			this.maxKnob = new Element('div',{'class':'slalom-filter-slider-knob slalom-filter-slider-knob-max'});

			this.container.adopt([this.minKnob,this.gutter_ol,this.maxKnob]);
			
			this.knobWidth = this.maxKnob.getStyle('width').toInt();
			this.knobHeight = this.maxKnob.getStyle('height').toInt();
			this.gutterWidth = this.gutter.getStyle('width').toInt();

			this.scale = this.scaleMax - this.scaleMin;
			this.ratio = this.gutterWidth / this.scale;
			
			this.minDrag = new Drag(this.minKnob,{
				modifiers: {x: 'margin-left', y: false},
				limit: {x:[0,(this.gutterWidth)]},
				onDrag: this.dragDrag.bind(this),
				onComplete:  this.dragStop.bind(this)
			});
			this.maxDrag = new Drag(this.maxKnob,{
				modifiers: {x: 'margin-left', y: false},
				limit: {x:[this.knobWidth,(this.gutterWidth+this.knobWidth)]},
				onDrag: this.dragDrag.bind(this),
				onComplete:  this.dragStop.bind(this)
			});
			
			this.activated = true;
		}		
	},
	disable: function(){},
	dragDrag: function(knob,event){
		var range = this.getRange();
		
		var dragMin = SlalomFilters.Utils.round(range.min,this.options.decimals);
		var dragMax = SlalomFilters.Utils.round(range.max,this.options.decimals);
		
		console.log(dragMin,dragMax);

		this.min = this.minInput.value = dragMin;
		this.max = this.maxInput.value = dragMax;
		
		this.position(false,this.options.snappy);
	},
	dragStop: function(knob,event){
		//console.log("Knob %o stopped draggin.",knob);
		var maxForMin = this.maxKnob.getStyle('margin-left').toInt() - this.knobWidth;
		var minForMax = this.minKnob.getStyle('margin-left').toInt() + this.knobWidth;
		this.minDrag.options.limit.x[1] = maxForMin;
		this.maxDrag.options.limit.x[0] = minForMax;
		this.position(true,true);
	},
	getRange: function(){
		return {
			min: ((this.minKnob.getStyle('margin-left').toInt())/this.ratio)+this.scaleMin,
			max: ((this.maxKnob.getStyle('margin-left').toInt()-this.knobWidth)/this.ratio)+this.scaleMin
		}
	},
	setRange: function(end,noapply){
		var input = this[end+'Input'];
		
		if(end == 'min'){
			if(input.value < this.scaleMin) input.value = this.scaleMin;
			else if (input.value > this.max) input.value = this.max;
		} else if(end == 'max'){
			if(input.value > this.scaleMax) input.value = this.scaleMax;
			else if (input.value < this.min) input.value = this.min;
		}
		
		this.min = SlalomFilters.Utils.round(this.minInput.value,this.options.decimals) || this.scaleMin;
		this.max = SlalomFilters.Utils.round(this.maxInput.value,this.options.decimals) || this.scaleMax;
		
		this.position(!noapply,true);
		console.log(this.min,this.max);
	},
	position: function(apply,snap){
		var min, max;
		this.minInput.value = this.min;
		this.maxInput.value = this.max;
	
		if(snap){
			min = ((this.min-this.scaleMin)*this.ratio).toInt();
			max = ((this.max-this.scaleMin)*this.ratio+this.knobWidth).toInt();

			this.minKnob.setStyle('margin-left',min);
			this.maxKnob.setStyle('margin-left',max);
		} else {
			min = this.minKnob.getStyle('margin-left').toInt();
			max = this.maxKnob.getStyle('margin-left').toInt();
		}
		
		this.gutter_ol.setStyle('clip','rect(0px,'+(max-this.knobWidth)+'px,'+this.knobHeight+'px,'+min+'px)');
		if(apply){
			this.applyfilter();
		}
	},
	applyfilter: function(){
		console.log(this.min,this.max);
		var filters = $H();
		filters[this.searchtype+'/'+this.field_send+'/greater_or_equal'] = this.min;
		filters[this.searchtype+'/'+this.field_send+'/lesser_or_equal'] = this.max;
		this.Base.applyFilters(filters);
	},
	removefilter: function(){
		var filters = $H();
		filters[this.searchtype+'/'+this.field_send+'/greater_or_equal'] = '';
		filters[this.searchtype+'/'+this.field_send+'/lesser_or_equal'] = '';
		this.Base.applyFilters(filters);
	},
	doreset: function(){
		if(this.activated){
			this.minInput.value = this.scaleMin;
			this.maxInput.value = this.scaleMax;
			this.setRange('min',true);
			this.setRange('max',true);
		}
	}
});
