Control.filterSlider = Class.create({
	conf: {},
	
	inizialized: false,
	
	track: null,
	minValue: 0,
	maxValue: 0,
	
	formElements: null,
	rangeDisplay: null,
	handles: null,
	quiet: false,
	labels: [],

	sliderHop: 1, //minimal amout that could be moved
	sliderMaxSteps: 20, //maximal slider steps
	
	initialize: function(track, formElements, labels, display, handles, options){
		this.conf = {
			span: false,
			ruler: false,
			resetButtons: false
		};
		Object.extend(this.conf,options || {});
		
		if(!track){return;}
		if(!labels || labels.size() < 2){return;}
		this.labels = labels;
		if(!formElements || !formElements[1]){return;}
		this.formElements = formElements;
		if(!display){return;}
		display.hide();
		this.rangeDisplay = display.select(".number");
		if(!this.rangeDisplay || this.rangeDisplay.size() < 2){return;}
		var fs = this;
		
		fs.labels.each(function(label,i){
			if(i==0){
				fs.labels[0] = label.select(".number")[0];
				fs.minValue = parseInt(fs.labels[0].innerHTML,10);
			}
			else if(i==1){
				fs.labels[1] = label.select(".number")[0];
				fs.maxValue = parseInt(fs.labels[1].innerHTML,10);
			}
		});
		
		//the range-display		
		track.updateRangeDisplay = function(low, high){
			this.rangeDisplay[0].update(low);
			this.rangeDisplay[1].update(high);
		}.bind(this);
		
		this.onChangeListener = function(value){
			//check the range, correct if wrong
			if(value[1]-value[0]<1){
				fs.quiet = true;
				if(handles[0].hasClassName("selected")){
					track.sliderControl.setValue(value[0]-fs.sliderHop, 0);
				}else if(handles[1].hasClassName("selected")){
					track.sliderControl.setValue(value[1]+fs.sliderHop, 1);
				}
				else{
					track.sliderControl.setValue(value[1]+fs.sliderHop, 1);
				}					
				fs.quiet = false;				
				track.updateRangeDisplay(value[0], value[1]);					
			}
			
			//hide/show rangeDisplay
			//and control form element
			if(value[0]==fs.minValue && value[1]==fs.maxValue){
				if(display.visible()){ //speed optimization
					display.hide();
				}
				fs.formElements[0].value = "";
				fs.formElements[1].value = "";
			}
			else{
				if(!display.visible()){ //speed optimization
					display.show();
				}
				fs.formElements[0].value = value[0].toString();
				fs.formElements[1].value = value[1].toString();
			}
			
			//fire filter:changed on the track element
			if(fs.inizialized && !fs.quiet){
				fs.track.fire("filter:changed", {
					filter: fs,
					filterValue: fs.val()
				});
			}
		}
		this.onSlideListener = function(value){				
			track.updateRangeDisplay(value[0], value[1]);
		}
		this.track = track;
		this.handles = handles;
		this.initializeSlider();
		
		//make the reset button with btn-del
		$(this.conf.resetButtons || []).each(function(button){
			button.observe('click', function(event){
				event.stop();
				fs.clear();
			});
		});
		
		//set initial value
		var value = [ parseInt(this.formElements[0].value, 10),  parseInt(this.formElements[1].value, 10) ];
		this.val(value);
		if(value[0]==fs.minValue && value[1]==fs.maxValue){
			if(display.visible()){ //speed optimization
				display.hide();
			}
			fs.formElements[0].value = "";
			fs.formElements[1].value = "";
		}
		
		//fire all events now
		this.inizialized = true;		
	},
	calculateSliderHop: function(cs_hop,cs_min,cs_max,cs_maxSteps){
		cs_hop = cs_hop? cs_hop : 1;
		cs_min = cs_min? cs_min : this.minValue;
		cs_max = cs_max? cs_max : this.maxValue;
		cs_maxSteps = cs_maxSteps? cs_maxSteps : this.sliderMaxSteps;
		cs_max += (cs_max-cs_min)%cs_hop; //elevate the max value to generate nice rulers
		if(cs_max-cs_min > cs_maxSteps*cs_hop){
			cs_hop = cs_hop*2;
			return this.calculateSliderHop(cs_hop, cs_min, cs_max, cs_maxSteps);
		}
		//bingo
		return {"hop":cs_hop, "min":cs_min, "max":cs_max, "maxSteps":cs_maxSteps};
	},
	initializeSlider: function(){
		var fs = this;
		var sliderHop = this.calculateSliderHop();
		fs.formElements[0].value = fs.formElements[0].value != fs.minValue.toString()? fs.formElements[0].value : sliderHop.min.toString();
		fs.formElements[1].value = fs.formElements[1].value != fs.maxValue.toString()? fs.formElements[1].value : sliderHop.max.toString();
		fs.minValue = sliderHop.min;
		fs.maxValue = sliderHop.max;
		fs.sliderHop = sliderHop.hop;
		fs.sliderMaxSteps = sliderHop.maxSteps;
		var values = [];
		var steps = (fs.maxValue - fs.minValue)/this.sliderHop;

		$(steps).times(function(cnt){
			values.push(this.minValue+cnt*this.sliderHop);
		}.bind(this));
		values.push(this.maxValue);

		this.track.sliderControl = new Control.Slider(fs.handles, fs.track, {
			range: $R(fs.minValue, fs.maxValue),
			values: values,
	      	sliderValue: [fs.minValue, fs.maxValue],
		    spans: fs.conf.span || [],
			restricted: true,
			onChange: fs.onChangeListener,
			onSlide: fs.onSlideListener
		});	
		
		//insert the ruler values
		if(fs.conf.ruler){
			fs.conf.ruler.innerHTML = "";
			$(steps).times(function(i){
				var elem = "<div style='width:" + fs.track.sliderControl.translateToPx(fs.minValue + i*this.sliderHop) + "'></div>";
				fs.conf.ruler.innerHTML += elem;
			}.bind(this));
		}
		
		//inizialize labels
		fs.updateLabels();
	},
	updateLabels: function(){
		var fs = this;
		fs.labels[0].update(fs.minValue);
		fs.labels[1].update(fs.maxValue);
	},
	clear: function(quiet){
		//mute the slider, if desired
		var fs = this;
		var oldQuiet = fs.quiet;
		fs.quiet = quiet? true : false;
		this.val([this.minValue,this.maxValue]);
		fs.quiet = oldQuiet;
		return true;
	},
	val: function(newVal){
		if(newVal){

			//setter
			//several types are accepted
			// - string: "low,high"
			// - array: [low,high]
			// - obj:
			if(typeof newVal == "string"){
				newVal = newVal.split(",");
				newVal[0] = parseInt(newVal[0], 10);
				newVal[1] = parseInt(newVal[1], 10);
			}
			else if(newVal[0] && newVal[0].name){
				var newValTmp = [];
				newVal.each(function(aNewValue){
					if(aNewValue.name == "from"){
						newValTmp[0] =  parseInt(aNewValue.value, 10);
					}
					else if(aNewValue.name == "to"){
						newValTmp[1] =  parseInt(aNewValue.value, 10);
					}
				});
				newVal = newValTmp;
				if(!newVal){
					return false;
				}
			}
			
			//only set new values, if they differ, to not trigger unnessesary change events
			if(this.track.sliderControl.values[1] !== newVal[1]){
				this.track.sliderControl.setValue(newVal[1], 1);
			}
			if(this.track.sliderControl.values[0] !== newVal[0]){
				this.track.sliderControl.setValue(newVal[0], 0);
			}
			this.track.updateRangeDisplay(this.track.sliderControl.values[0],this.track.sliderControl.values[1]);	
			return this.val();			
		}
		else{
			//getter
			var fromValue = parseInt(this.formElements[0].value,10);
			var toValue = parseInt(this.formElements[1].value,10);
			var ret = false;
			if((fromValue || toValue) && (fromValue != this.minValue || toValue != this.maxValue)){
				ret = [
					{name: "from", value: fromValue.toString()},
					{name: "to", value: toValue.toString()}
				]
			}
			return ret;
		}		
	},
	update: function(options){
		var fs = this;
		if(!options || options.length < 2){return fs;}

		var minMax = [fs.minValue, fs.maxValue];
		var selected = [];
		var oldValueRaw = this.val() || [];
		var oldValue = [];
		$(oldValueRaw).each(function(val,i){
			if(val.name=="from"){
				oldValue[0] =  parseInt(val, 10);
			}
			else if(val.name=="to"){
				oldValue[1] =  parseInt(val, 10);
			}
		});

		var remaining = 0;
		options.each(function(opt){
			if(opt.title == "from"){
				minMax[0] = opt.value;
				selected[0] = opt.selected || fs.minValue;
			}
			else if(opt.title == "to"){
				minMax[1] = opt.value;
				selected[1] = opt.selected || fs.maxValue;
			}
			remaining = opt.remaining;
		});

		//validate imput, to avoid infinite recursion
		if(minMax[1]-minMax[0]<1){
			minMax[1] = minMax[1]+1;

			this.isInvalid = true;
			return fs;
		}
		else{
			this.isInvalid = false;
		}

		//check if change is needed?
		if(	minMax[0]===fs.minValue &&
			minMax[1]===fs.maxValue &&
			selected[0]===oldValue[0] &&
			selected[1]===oldValue[1]
			){
			//do not need to reinitialize, everything is fine
			return fs;
		}

		//mute the slider, because we are manipulating its values
		var oldQuiet = fs.quiet;
		fs.quiet = true;
		
		//destroy old slider
		fs.track.sliderControl.dispose();
			
		//create a new one
		fs.minValue = minMax[0];
		fs.maxValue = minMax[1];
		fs.initializeSlider();
		
		//set the value back
		fs.val(selected);

		//turn on event firing
		fs.quiet = oldQuiet;
		
		return fs;
	},
	hasVisibleOptions: function(){
		//return has selectable range
		if(!this.isInvalid && this.maxValue-this.minValue > 0){
			return true;
		}
		return false;
	}
});
