if(!window.Richfaces) window.Richfaces = {};
Richfaces.Slider = Class.create();
Richfaces.Slider.prototype = {
	initialize: function(handle, track, tip, table, handleSelectedClass, options) {
		var slider = this;
		this.handle = $( handle );
		this.tip	= $( tip );
		this.track	= $( track );
		this.mainTable	= $( table );
		
		//this.optionsInputId = options.optionsInputId;
		
		//this.optionInput = $(this.optionsInputId) || document.getElementById(this.optionsInputId);
				
		this.input	= $( options.inputId ) || document.getElementsByName(options.inputId)[0];
		this.options= options || {};
		
		this.classes = {};
		this.classes.arrow = "dr-insldr-handler rich-inslider-handler";
		this.classes.arrowSelected = "dr-insldr-handler-sel rich-inslider-handler-selected";
		this.classes.temp = this.handle.className;
		this.classes.base = " " + this.trim(this.classes.temp.replace("dr-insldr-handler rich-inslider-handler",""));
		this.classes.handleSelected = " " + handleSelectedClass;

		this.table = this.findTableForTrack(this.track);
		
		this.input.value = this.options.sliderValue;
		this.prevInputValue = this.input.value;
		this.graggedImageOn = false;
		this.range	 = this.options.range || $R(0,1);
		this.value	 = 0;
		this.minimum = this.options.minimum || this.range.start;
		this.maximum = this.options.maximum || this.range.end;
		this.digCount = 0;

		this.step = this.options.step;
		if ( (this.step+"").indexOf(".")!=-1 ){
			var stepStr = (this.step+"");
			this.digCount = (stepStr.substring(stepStr.indexOf(".")+1,stepStr.length)).length;
		}
		this.availableValues = this.calculateAvailableValues();

		this.tip.maxlength = (this.maximum + "").length + (this.digCount != 0 ? this.digCount + 1 : 0);

		this.handleLength = 9;

		this.active	 = false;
		this.dragging = false;
		this.editInFocus = false;

		this.disabled = this.options.disabled ? true : false;

		var tr = this.track.childNodes[0];

		this.prevMouseUp = window.document.onmouseup;
		this.prevMouseMove = window.document.onmousemove;

		this.documentBodyOload	= this.load.bindAsEventListener(this);
		Event.observe(window, "load", this.documentBodyOload);

		this.eventWindowResized = this.windowResized.bindAsEventListener(this);
		Event.observe(window, "resize", this.eventWindowResized);

		if(!this.options.disabled){
			//this.eventMouseUp		= this.endDrag.bindAsEventListener(this);
			this.eventMouseUp		= this.processMouseUp.bindAsEventListener(this);
			this.eventMouseMove		= this.update.bindAsEventListener(this);
			this.eventMouseDown		= this.startDrag.bindAsEventListener(this);
			this.eventEditFocus		= this.editFocus.bindAsEventListener(this);
			this.eventEditBlur		= this.editBlur.bindAsEventListener(this);
			this.eventEditChange	= this.editChange.bindAsEventListener(this);
			this.eventEditValidate	= this.inputValidate.bindAsEventListener(this);
			this.eventInputChange	= this.inputChange.bindAsEventListener(this);
			this.eventWindowMouseOut= this.windowMouseOut.bindAsEventListener(this);

			if (this.options.onerr != ""){
				this.eventError = new Function(this.options.onerr).bindAsEventListener(this);
			}
			if (this.options.onchange != ""){
				this.eventChanged = new Function("event",this.options.onchange).bindAsEventListener(this);
			}

			Event.observe(this.track, "mousedown", this.eventMouseDown);
			Event.observe(tr, "mousedown", this.eventMouseDown);
			Event.observe(this.input, "keydown", this.eventEditValidate);
			Event.observe(this.input, "keyup", this.eventEditChange);
			Event.observe(this.input, "focus", this.eventEditFocus);
			Event.observe(this.input, "blur", this.eventEditBlur);
			Event.observe(document, "mouseout", this.eventWindowMouseOut);
			if(this.input.onchange){
				this.eventInputOnChange = this.input.onchange.bindAsEventListener(this.input);
				this.input.onchange = null;
			}
			Event.observe(this.input, "change", this.eventInputChange);
		}
		this.initialized = true;

        //this.setInitialValue(); 
        //Event.observe(window, "load", this.setInitialValue.bindAsEventListener(this)); //FIX RFA-190
		//Event.observe($(input), "propertychange", this.setInitialValue.bindAsEventListener(this));
			
		this.required = options.required;
	},

	setInitialValue: function(){
		this.setValue(parseFloat(this.options.sliderValue || this.range.start));
        this.handle.style.visibility="visible";
		this.prevValue = this.value;
		this.valueChanged = false;
	},

   calculateAvailableValues : function(){
        var values = new Array();
        var value = this.roundFloat(this.minimum);
        var i = 0;
        while (value < this.maximum){
            values[i] = value;
            value = this.roundFloat(value + parseFloat(this.step));
            i++;
        }
        values[i] = this.roundFloat(this.maximum);

        return values;
    },

	roundFloat: function(x){
		if (!this.digCount)
			return Math.round(x);

		return parseFloat(Number(x).toFixed(this.digCount));
	},

	windowMouseOut : function(evt){
		var elt = null;
		if (evt.srcElement){
			elt = evt.toElement;
		} else {
			elt = evt.relatedTarget;
		}
		if (elt == null) {
			this.endDrag(evt);
		}
	},

	windowResized : function(evt){
		this.setValue(this.value);
	},

	findTableForTrack: function(elem) {
		var parent = elem.parentElement || elem.parentNode;
		if (parent.tagName.toUpperCase()=="TABLE") {
			return parent;
		} else {
			return this.findTableForTrack(parent);
		}
	},

    getNearestValue: function(value){
        var pos;
        pos = this.binsearch(this.availableValues, value);
        if (pos>0) {
        	var prevPos = pos-1;
        	if ( Math.abs(value-this.availableValues[prevPos])<
        		 Math.abs(this.availableValues[pos]-value) ) {
        		pos = prevPos;
        	}
        }
        return this.roundFloat(this.availableValues[pos]);
    },

    binsearch: function(v, t) {
        var i = 0;
        var j = v.length - 1;
        var k;
        while (i < j) {
            k = Math.round((i + j) / 2 + 0.5) - 1;
            if (t <= v[k]) j = k;
            else i = k + 1;
        }

        return i;
    },


    setValue: function(sliderValue){
	    if (isNaN(sliderValue)){
	     sliderValue=0;
	    }
		sliderValue = this.getNearestValue(sliderValue);
		this.value = sliderValue;
		if (!this.editInFocus && (this.required || "" != this.input.value || this.updating)){
			this.input.value = this.value;
	//		this.optionInput.value = this.value;
			this.handle.style.left = this.translateToPx(sliderValue);
		} else {
			this.handle.style.left = "-2px";
		}
		if (!this.tip.firstChild) {
			this.tip.appendChild(window.document.createTextNode(this.value));
		}
		this.tip.firstChild.nodeValue= this.value;
 		this.tip.style.left = this.handle.offsetLeft /*+ this.handle.offsetWidth*/ + "px";
	},

	translateToPx: function(value) {
		return Math.round(
			((this.maximumOffset() - this.handleLength)/(this.range.end-this.range.start)) *
			(value - this.range.start)) + "px";
	},

	translateToValue: function(offset) {
		return ((offset/(this.maximumOffset() - this.handleLength) *
			(this.range.end-this.range.start)) + this.range.start);
	},

	maximumOffset: function(){
		return this.removePx(this.track.style.width || this.track.offsetWidth);
	},

	removePx: function(e){
		if ((e+"").indexOf("px")!=-1)
			return (e+"").substring(0,e.length-2);
		else
			return e;
	},

	startDrag: function(event) {
		if (this.editInFocus)
			this.input.blur();
		window.document.onmouseup		= this.eventMouseUp.bindAsEventListener(this);
		window.document.onmousemove		= this.eventMouseMove.bindAsEventListener(this);
		this.editBlur();
		this.prevMouseDownEvent = event;

		if(Event.isLeftClick(event)) {
			if(!this.disabled){
				this.handle.className = this.classes.arrowSelected + this.classes.base + this.classes.handleSelected;
				if (this.options.currValue){
					this.tip.style.display = "block";
				}
				Richfaces.createEvent("mousedown", this.mainTable, null, null).fire();
				this.active = true;
				var handle = Event.element(event);
				var pointer	= Event.pointerX(event);
				var offsets	= Position.cumulativeOffset(this.track);
				this.updating = true;
				this.setValue(this.translateToValue( ( pointer - offsets[0] ) -(this.handleLength/2)));
				this.updating = false;
				var offsets	= Position.cumulativeOffset(this.handle);
				this.offsetX = pointer - offsets[0];
			}
			Event.stop(event);
		}
	},

	update: function(event) {
		this.updating = true;
		if(this.active) {

			if(!this.dragging) this.dragging = true;
			this.draw(event);
			Event.stop(event);
		}
		this.updating = false;
	},

	draw: function(event) {
		var pointer = Event.pointerX(event);
		var offsets = Position.cumulativeOffset(this.track);
		pointer -= this.offsetX + offsets[0];
		this.setValue(this.translateToValue( pointer ));
	},

	processMouseUp: function(event) {
		this.endDrag(event);
		this.fireClickIfNeeded(event);
	},

	endDrag: function(event) {
		window.document.onmouseup = this.prevMouseUp;
		window.document.onmousemove = this.prevMouseMove;
		if (this.options.currValue){
			Element.hide(this.tip);
		}
		if (this.eventChanged && this.isValueChanged()){
			this.eventChanged(event);
		}
		this.handle.className = this.classes.arrow + this.classes.base;
		if(this.active && this.dragging) {
			this.active = false;
			this.dragging = false;
			Richfaces.createEvent("mouseup", this.mainTable, null, null).fire();
			Event.stop(event);
		}
		if (RichFaces.navigatorType() != "MSIE")
			Richfaces.createEvent("change", this.input, null, null).fire();
	},

	fireClickIfNeeded: function(event){
		if ((this.prevMouseDownEvent.target != event.target
			&& RichFaces.navigatorType() == "FF")
			|| (RichFaces.getOperaVersion()
			&& RichFaces.getOperaVersion() < 9.0
			&& event.target.tagName.toLowerCase() != "div")) {
				Richfaces.createEvent("click", this.mainTable, null, null).fire();
		}
	},

	isValueChanged : function(){
		var ret =this.prevValue != this.value
		this.prevValue = this.value;
		return ret;
	},

	inputChange: function(e) {
		this.editInFocus = false;
		if (isNaN(Number(this.input.value))){
			this.setValue(this.value);
		} else {
			if (this.outOfRange)
				if (this.eventError)
					this.eventError();
			this.setValue(Number(this.input.value));
		}
		this.value = this.input.value ? this.input.value : this.minimum;
		if(this.eventInputOnChange){
			this.eventInputOnChange();
		}
		if (this.eventChanged && this.isValueChanged()){
			this.eventChanged(e);
		}
	},

	inputValidate: function(e) {
		if ( e.keyCode == 13 ){
			if (isNaN(Number(this.input.value))){
				this.input.value = this.value;
				this.editBlur();
				this.setValue(this.value);
			}
		}
	},

	editChange: function(e) {
		if (isNaN(Number(this.input.value))){
			this.setValue(Number(this.value));
			this.input.value = this.value;
			
			if (this.eventError){
				this.eventError();
			}
		} else {
			if (!( e.keyCode > 37 && e.keyCode < 40 )){
				this.setValue(Number(this.input.value));
			}
		}

		if (e.keyCode == 13) {
			if (this.required || "" != this.input.value)
			    this.input.value=this.getNearestValue(this.value);
			this.input.form.submit();
		}
		if (this.eventChanged && this.isValueChanged()){
			this.eventChanged(e);
		}

	},

	editFocus: function(){
		this.editInFocus = true;
	},

	editBlur: function(){
		this.editInFocus = false;
	    if ((this.input.value+"").indexOf(this.value) != 0){
    		 this.setValue(this.input.value);
             this.eventInputChange();
	    }
	    else{
		     this.setValue(this.input.value);
		}
	},

	load: function(){
		// fix RF-895
		if(this.input.value){
			this.options.sliderValue = this.input.value;
		}
	
		this.setInitialValue();
		//this.setValue( this.value );
	},

	trim : function(str){
		return str.replace(/^\s+|\s+$/, '');
	}
}
