/*
Dual slider and range modifications by Brian Ward to Slider and Range
classes by Erik Arvidsson (http://webfx.eae.net/contact.html#erikk)
For WebFX (http://webfx.eae.net/)
Copyright (c) 2002, 2003, 2006 Erik Arvidsson, 2007 Brian Ward

Licensed under the Apache License, Version 2.0 (the "License"); you may not
use this file except in compliance with the License.  You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0

Unless  required  by  applicable law or  agreed  to  in  writing,  software
distributed under the License is distributed on an  "AS IS" BASIS,  WITHOUT
WARRANTIES OR  CONDITIONS OF ANY KIND,  either express or implied.  See the
License  for the  specific language  governing permissions  and limitations
under the License.
*/

function Range3() {
    this._value = 0;
    this._minimum = 0;
    this._maximum = 500;
    this._extent = 0;
    this._value2 = this._maximum;

    /* minimum range */
    this._minrange = 1;

    this._isChanging = false;
}

Range3.prototype.setValue = function (value) {
    value = Math.round(parseFloat(value));
    if (isNaN(value)) return;
    if (this._value != value) {
	if (value + this._extent > this._value2)
	    this._value = this._value2 - this._extent;
	else if (value < this._minimum)
	    this._value = this._minimum;
	else
	    this._value = value;

	if (this._value == this._value2)
	    this._value -= this._minrange;

	if (!this._isChanging && typeof this.onchange == "function")
	     this.onchange();
    }
};

Range3.prototype.setValue2 = function (value) {
    value = Math.round(parseFloat(value));
    if (isNaN(value)) return;
    if (this._value2 != value) {
	if (value + this._extent > this._maximum)
	    this._value2 = this._maximum - this._extent;
	else if (value < this._value)
	    this._value2 = this._value;
	else
	    this._value2 = value;

	if (this._value == this._value2)
	    this._value2 += this._minrange;

	if (!this._isChanging && typeof this.onchange == "function")
	     this.onchange();
    }
};

Range3.prototype.getValue = function () {
    return this._value;
};

Range3.prototype.getValue2 = function () {
    return this._value2;
};

Range3.prototype.setExtent = function (extent) {
    if (this._extent != extent) {
	if (extent < 0)
	    this._extent = 0;
	else if (this._value + extent > this._maximum)
	    this._extent = this._maximum - this._value;
	else
	    this._extent = extent;
	
	if (!this._isChanging && typeof this.onchange == "function")
	    this.onchange();
    }
};

Range3.prototype.getExtent = function () {
    return this._extent;
};

Range3.prototype.setMinimum = function (minimum) {
    if (this._minimum != minimum) {
	var oldIsChanging = this._isChanging;
	this._isChanging = true;

	this._minimum = minimum;

	if (minimum > this._value)
	    this.setValue(minimum);
	if (minimum > this._maximum) {
	    this._extent = 0;
	    this.setMaximum(minimum);
	    this.setValue(minimum)
	}
	if (minimum + this._extent > this._maximum)
	    this._extent = this._maximum - this._minimum;

	this._isChanging = oldIsChanging;
	if (!this._isChanging && typeof this.onchange == "function")
	    this.onchange();
    }
};

Range3.prototype.getMinimum = function () {
    return this._minimum;
};

Range3.prototype.setMaximum = function (maximum) {
    if (this._maximum != maximum) {
	var oldIsChanging = this._isChanging;
	this._isChanging = true;

	this._maximum = maximum;

	if (maximum < this._value)
	    this.setValue(maximum - this._extent);
	if (maximum < this._minimum) {
	    this._extent = 0;
	    this.setMinimum(maximum);
	    this.setValue(this._maximum);
	}
	if (maximum < this._minimum + this._extent)
	    this._extent = this._maximum - this._minimum;
	if (maximum < this._value + this._extent)
	    this._extent = this._maximum - this._value;

	this._isChanging = oldIsChanging;
	if (!this._isChanging && typeof this.onchange == "function")
	    this.onchange();
    }
};

Range3.prototype.getMaximum = function () {
    return this._maximum;
};

/* start slider */

Slider2.isSupported = typeof document.createElement != "undefined" &&
    typeof document.documentElement != "undefined" &&
    typeof document.documentElement.offsetWidth == "number";


function Slider2(oElement, oInput) {
    if (!oElement) return;
    this._orientation = "price_sliderhorizontal";
    this._range = new Range3();
    this._range.setExtent(0);
    this._blockIncrement = 10;
    this._unitIncrement = 1;

    if (Slider2.isSupported && oElement) {

	this.document = oElement.ownerDocument || oElement.document;
		
	this.element = oElement;
	this.element.slider = this;
	this.element.unselectable = "on";

	this.onrelease = function() { return true; };

	// add class name tag to class name
	this.element.className = this._orientation + " " + this.classNameTag + " " + this.element.className;

	// create line
	this.line = this.document.createElement("DIV");
	this.line.className = "price_line";
	this.line.unselectable = "on";
	this.line.appendChild(this.document.createElement("DIV"));
	this.element.appendChild(this.line);

	// create handle
	this.handle1 = this.document.createElement("DIV");
	this.handle1.className = "price_handle_left";
	this.handle1.unselectable = "on";
	this.handle1.appendChild(this.document.createElement("DIV"));
	this.handle1.firstChild.appendChild(
	    this.document.createTextNode(String.fromCharCode(160)));
	this.element.appendChild(this.handle1);

	// create handle #2
	this.handle2 = this.document.createElement("DIV");
	this.handle2.className = "price_handle_right";
	this.handle2.unselectable = "on";
	this.handle2.appendChild(this.document.createElement("DIV"));
	this.handle2.firstChild.appendChild(
	    this.document.createTextNode(String.fromCharCode(160)));
	this.element.appendChild(this.handle2);

    }

    this.input = oInput;

    // events
    var oThis = this;
    this._range.onchange = function () {
	oThis.recalculate();
	if (typeof oThis.onchange == "function")
	    oThis.onchange();
    };
    if (Slider2.isSupported && oElement) {
	this.element.onfocus = Slider2.eventHandlers.onfocus;
	this.element.onblur = Slider2.eventHandlers.onblur;
	this.element.onmousedown = Slider2.eventHandlers.onmousedown;
	this.element.onmouseover = Slider2.eventHandlers.onmouseover;
	this.element.onmouseout	= Slider2.eventHandlers.onmouseout;
	this.element.onkeydown	= Slider2.eventHandlers.onkeydown;
	this.element.onkeypress	= Slider2.eventHandlers.onkeypress;
	this.element.onmousewheel = Slider2.eventHandlers.onmousewheel;
	this.handle1.onselectstart =
	this.handle2.onselectstart =
	this.element.onselectstart = function () { return false; };

	// extra recalculate for ie
	window.setTimeout(function() {
	    oThis.recalculate();
	}, 1);
    }
    else {
	this.input.onchange = function (e) {
	    oThis.setValue(oThis.input.value);
	};
    }
}

Slider2.eventHandlers = {

    // helpers to make events a bit easier
    getEvent:	function (e, el) {
	if (!e) {
	    if (el)
		e = el.document.parentWindow.event;
	    else
		e = window.event;
	}
	if (!e.srcElement) {
	    var el = e.target;
	    while (el != null && el.nodeType != 1)
		el = el.parentNode;
	    e.srcElement = el;
	}
	if (typeof e.offsetX == "undefined") {
	    e.offsetX = e.layerX;
	    e.offsetY = e.layerY;
	}

	return e;
    },

    getDocument:	function (e) {
	if (e.target)
	    return e.target.ownerDocument;
	return e.srcElement.document;
    },

    getSlider:	function (e) {
	var el = e.target || e.srcElement;
	while (el != null && el.slider == null)	{
	    el = el.parentNode;
	}
	if (el)
	    return el.slider;
	return null;
    },

    getLine:	function (e) {
	var el = e.target || e.srcElement;
	while (el != null && el.className != "line")	{
	    el = el.parentNode;
	}
	return el;
    },

    getHandle:	function (e) {
	var el = e.target || e.srcElement;
	var re = /handle/;
	while (el != null && !re.test(el.className))	{
	    el = el.parentNode;
	}
	return el;
    },
    // end helpers

    onfocus:	function (e) {
	var s = this.slider;
	s._focused = true;
	s.handle1.className = "price_handle hover";
    },

    onblur:	function (e) {
	var s = this.slider
	s._focused = false;
	s.handle1.className = "price_handle";
    },

    onmouseover:	function (e) {
	e = Slider2.eventHandlers.getEvent(e, this);
	var s = this.slider;
	if (e.srcElement == s.handle1)
	    s.handle1.className = "price_handle hover";
    },

    onmouseout:	function (e) {
	e = Slider2.eventHandlers.getEvent(e, this);
	var s = this.slider;
	if (e.srcElement == s.handle1 && !s._focused)
	    s.handle1.className = "price_handle";
    },

    onmousedown:	function (e) {
	e = Slider2.eventHandlers.getEvent(e, this);
	var s = this.slider;
	if (s.element.focus)
	    s.element.focus();

	Slider2._currentInstance = s;
	var doc = s.document;

	if (doc.addEventListener) {
	    doc.addEventListener("mousemove", Slider2.eventHandlers.onmousemove, true);
	    doc.addEventListener("mouseup", Slider2.eventHandlers.onmouseup, true);
	}
	else if (doc.attachEvent) {
	    doc.attachEvent("onmousemove", Slider2.eventHandlers.onmousemove);
	    doc.attachEvent("onmouseup", Slider2.eventHandlers.onmouseup);
	    doc.attachEvent("onlosecapture", Slider2.eventHandlers.onmouseup);
	    s.element.setCapture();
	}

	handle = Slider2.eventHandlers.getHandle(e);
	if (handle) {	// start drag
	    if (handle == s.handle2) {
		v  = s.getValue2();
	    } else {
		v  = s.getValue();
	    }
	    Slider2._sliderDragData = {
		handle:		handle,
		screenX:	e.screenX,
		screenY:	e.screenY,
		dx:		e.screenX - handle.offsetLeft,
		dy:		e.screenY - handle.offsetTop,
		startValue:	v,
		slider:		s
	    };
	}
    },

    onmousemove:	function (e) {
	e = Slider2.eventHandlers.getEvent(e, this);

	if (Slider2._sliderDragData) {	// drag
	    var s = Slider2._sliderDragData.slider;

	    var boundSize = s.getMaximum() - s.getMinimum();
	    var size, pos, reset;
	    var handle = Slider2._sliderDragData.handle;

	    size = s.element.offsetWidth - handle.offsetWidth;
	    pos = e.screenX - Slider2._sliderDragData.dx;
	    reset = Math.abs(e.screenY - Slider2._sliderDragData.screenY) > 100;

	    if (handle == s.handle1) {
		s.setValue(reset ? Slider2._sliderDragData.startValue :
		    s.getMinimum() + boundSize * pos / size);
	    } else {
		s.setValue2(reset ? Slider2._sliderDragData.startValue :
		    s.getMinimum() + boundSize * pos / size);
	    }
	    return false;
	}
	else {
	    var s = Slider2._currentInstance;
	    if (s != null) {
		var lineEl = Slider2.eventHandlers.getLine(e);
		s._mouseX = e.offsetX + (lineEl ? s.line.offsetLeft : 0);
		s._mouseY = e.offsetY + (lineEl ? s.line.offsetTop : 0);
	    }
	}

    },

    onmouseup:	function (e) {
	e = Slider2.eventHandlers.getEvent(e, this);
	var s = Slider2._currentInstance;
	var doc = s.document;
	if (doc.removeEventListener) {
	    doc.removeEventListener("mousemove", Slider2.eventHandlers.onmousemove, true);
	    doc.removeEventListener("mouseup", Slider2.eventHandlers.onmouseup, true);
	}
	else if (doc.detachEvent) {
	    doc.detachEvent("onmousemove", Slider2.eventHandlers.onmousemove);
	    doc.detachEvent("onmouseup", Slider2.eventHandlers.onmouseup);
	    doc.detachEvent("onlosecapture", Slider2.eventHandlers.onmouseup);
	    s.element.releaseCapture();
	}

	if (Slider2._sliderDragData) {	// end drag
	    Slider2._sliderDragData = null;
	}
	else {
	    s._increasing = null;
	}

	Slider2._currentInstance.onrelease();

	Slider2._currentInstance = null;
    },

    onkeydown:	function (e) {
	e = Slider2.eventHandlers.getEvent(e, this);
	//var s = Slider2.eventHandlers.getSlider(e);
	var s = this.slider;
	var kc = e.keyCode;
	switch (kc) {
	    case 33:	// page up
		s.setValue(s.getValue() + s.getBlockIncrement());
		break;
	    case 34:	// page down
		s.setValue(s.getValue() - s.getBlockIncrement());
		break;
	    case 38:	// up
	    case 39:	// right
		s.setValue(s.getValue() + s.getUnitIncrement());
		break;

	    case 37:	// left
	    case 40:	// down
		s.setValue(s.getValue() - s.getUnitIncrement());
		break;
	}

	if (kc >= 33 && kc <= 40) {
	    return false;
	}
    },

    onkeypress:	function (e) {
	e = Slider2.eventHandlers.getEvent(e, this);
	var kc = e.keyCode;
	if (kc >= 33 && kc <= 40) {
	    return false;
	}
    },

    onmousewheel:	function (e) {
	e = Slider2.eventHandlers.getEvent(e, this);
	var s = this.slider;
	if (s._focused) {
	    s.setValue(s.getValue() + e.wheelDelta / 120 * s.getUnitIncrement());
	    // windows inverts this on horizontal sliders. That does not
	    // make sense to me
	    return false;
	}
    }
};



Slider2.prototype.classNameTag = "dynamic-slider-control",

Slider2.prototype.setValue = function (v) {
	this._range.setValue(v);
	this.input.value = this.getValue();
};
Slider2.prototype.setValue2 = function (v) {
	this._range.setValue2(v);
	this.input.value = this.getValue2();
};

Slider2.prototype.getValue = function () {
	return this._range.getValue();
};
Slider2.prototype.getValue2 = function () {
	return this._range.getValue2();
};

Slider2.prototype.setMinimum = function (v) {
	this._range.setMinimum(v);
	this.input.value = this.getValue();
};

Slider2.prototype.getMinimum = function () {
	return this._range.getMinimum();
};

Slider2.prototype.setMaximum = function (v) {
	this._range.setMaximum(v);
	this.input.value = this.getValue();
};

Slider2.prototype.getMaximum = function () {
	return this._range.getMaximum();
};

Slider2.prototype.setUnitIncrement = function (v) {
	this._unitIncrement = v;
};

Slider2.prototype.getUnitIncrement = function () {
	return this._unitIncrement;
};

Slider2.prototype.setBlockIncrement = function (v) {
	this._blockIncrement = v;
};

Slider2.prototype.getBlockIncrement = function () {
	return this._blockIncrement;
};

Slider2.prototype.recalculate = function() {
	if (!Slider2.isSupported || !this.element) return;

	var w = this.element.offsetWidth;
	var h = this.element.offsetHeight;
	var hw = this.handle1.offsetWidth;
	var hh = this.handle1.offsetHeight;
	var hw2 = this.handle2.offsetWidth;
	var hh2 = this.handle2.offsetHeight;
	var lw = this.line.offsetWidth;
	var lh = this.line.offsetHeight;

	// this assumes a border-box layout

	this.handle1.style.left = (w - hw) * (this.getValue() - this.getMinimum()) / (this.getMaximum() - this.getMinimum()) + "px";
	this.handle1.style.top = (h - hh) + "px";

	/* handle 2 */
	this.handle2.style.left = (w - hw2) * (this.getValue2() - this.getMinimum()) / (this.getMaximum() - this.getMinimum()) + "px";
	this.handle2.style.top = (h - hh2) / 2 + "px";

	this.line.style.top = (h - lh) / 2 + "px";
	this.line.style.left = hw / 2 + "px";
	//this.line.style.right = hw / 2 + "px";
	this.line.style.width = Math.max(0, w - hw - 2)+ "px";
	this.line.firstChild.style.width = Math.max(0, w - hw - 4)+ "px";
};


