/*----------------------------------------------------------------------------\
|                                DoubleSlider 1.02                                  |
|-----------------------------------------------------------------------------|
|                         Created by Erik Arvidsson                           |
|                  (http://webfx.eae.net/contact.html#erik)                   |
|                      For WebFX (http://webfx.eae.net/)                      |
|-----------------------------------------------------------------------------|
| A  slider  control that  degrades  to an  input control  for non  supported |
| browsers.                                                                   |
|-----------------------------------------------------------------------------|
|                Copyright (c) 2002, 2003, 2006 Erik Arvidsson                |
|-----------------------------------------------------------------------------|
| 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.                                                          |
|-----------------------------------------------------------------------------|
| Dependencies: timer.js - an OO abstraction of timers                        |
|               range.js - provides the data model for the slider             |
|               winclassic.css or any other css file describing the look      |
|-----------------------------------------------------------------------------|
| 2002-10-14 | Original version released                                      |
| 2003-03-27 | Added a test in the constructor for missing oElement arg       |
| 2003-11-27 | Only use mousewheel when focused                               |
| 2006-05-28 | Changed license to Apache Software License 2.0.                |
|-----------------------------------------------------------------------------|
| Created 2002-10-14 | All changes are in the log above. | Updated 2006-05-28 |
\----------------------------------------------------------------------------*/

DoubleSlider.isSupported = typeof document.createElement != "undefined" &&
	typeof document.documentElement != "undefined" &&
	typeof document.documentElement.offsetWidth == "number";


function DoubleSlider(oElement, oTopInput, oBottomInput, sOrientation) {
	if (!oElement) return;
	this._orientation = sOrientation || "horizontal";
	this._top_range = new Range();
	this._top_range.setExtent(0);
	this._bottom_range = new Range();
	this._bottom_range.setExtent(0);
	this._blockIncrement = 10;
	this._unitIncrement = 1;
	this._timer = new Timer(100);


	if (DoubleSlider.isSupported && oElement) {

		this.document = oElement.ownerDocument || oElement.document;

		this.element = oElement;
		this.element.double_slider = this;
		this.element.unselectable = "on";

		// add class name tag to class name
		this.element.className = this._orientation + " " + this.classNameTag + " " + this.element.className;

		// create slider field
		this.slider_field = this.document.createElement("DIV");
		this.slider_field.className = "slider_field";
		this.slider_field.unselectable = "on";
		this.slider_field.appendChild(this.document.createElement("DIV"));
		this.element.appendChild(this.slider_field);

		// create top_handle
		this.top_handle = this.document.createElement("DIV");
		this.top_handle.className = "top_handle";
		this.top_handle.unselectable = "on";
		this.top_handle.appendChild(this.document.createElement("DIV"));
		this.top_handle.firstChild.appendChild(
		this.document.createTextNode(String.fromCharCode(160)));
		this.element.appendChild(this.top_handle);

		// create bottom_handle
		this.bottom_handle = this.document.createElement("DIV");
		this.bottom_handle.className = "bottom_handle";
		this.bottom_handle.unselectable = "on";
		this.bottom_handle.appendChild(this.document.createElement("DIV"));
		this.bottom_handle.firstChild.appendChild(
		this.document.createTextNode(String.fromCharCode(160)));
		this.element.appendChild(this.bottom_handle);
	}

	this.top_input = oTopInput;
	this.bottom_input = oBottomInput;

	// events
	var oThis = this;
	this._top_range.onchange = function () {
		oThis.recalculate();
		if (typeof oThis.onchange == "function")
			oThis.onchange();
	};

	this._bottom_range.onchange = function () {
		oThis.recalculate();
		if (typeof oThis.onchange == "function")
			oThis.onchange();
	};

	if (DoubleSlider.isSupported && oElement) {
		this.element.onfocus		= DoubleSlider.eventHandlers.onfocus;
		this.element.onblur			= DoubleSlider.eventHandlers.onblur;
		this.element.onmousedown	= DoubleSlider.eventHandlers.onmousedown;
		this.element.onmouseover	= DoubleSlider.eventHandlers.onmouseover;
		this.element.onmouseout		= DoubleSlider.eventHandlers.onmouseout;
		this.element.onkeydown		= DoubleSlider.eventHandlers.onkeydown;
		this.element.onkeypress		= DoubleSlider.eventHandlers.onkeypress;
		this.element.onmousewheel	= DoubleSlider.eventHandlers.onmousewheel;
		this.top_handle.onselectstart	=
		this.bottom_handle.onselectstart	=
		this.element.onselectstart	= function () { return false; };

		this._timer.ontimer = function () {
			oThis.ontimer();
		};

		// extra recalculate for ie
		window.setTimeout(function() {
			oThis.recalculate();
		}, 1);
	}
	else 
    {
		this.top_input.onchange = function (e) 
        {
			oThis.setTopValue(oThis.top_input.value);
		};
		this.bottom_input.onchange = function (e) 
        {
			oThis.setBottomValue(oThis.bottom_input.value);
		};
	}
}

DoubleSlider.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;
	},

	getDoubleSlider:	function (e) {
		var el = e.target || e.srcElement;
		while (el != null && el.double_slider == null)	{
			el = el.parentNode;
		}
		if (el)
			return el.double_slider;
		return null;
	},

	getSliderField:	function (e) {
		var el = e.target || e.srcElement;
		while (el != null && el.className != "slider_field")	{
			el = el.parentNode;
		}
		return el;
	},

	getTopHandle:	function (e) {
		var el = e.target || e.srcElement;
		var re = /top_handle/;
		while (el != null && !re.test(el.className))	{
			el = el.parentNode;
		}
		return el;
	},
	getBottomHandle:	function (e) {
		var el = e.target || e.srcElement;
		var re = /bottom_handle/;
		while (el != null && !re.test(el.className))	{
			el = el.parentNode;
		}
		return el;
	},
	// end helpers

	onfocus:	function (e) {
		var s = this.double_slider;
		s._focused = true;
		s.top_handle.className = "top_handle hover";
		s.bottom_handle.className = "bottom_handle hover";
	},

	onblur:	function (e) {
		var s = this.double_slider
		s._focused = false;
		s.top_handle.className = "top_handle";
		s.bottom_handle.className = "bottom_handle";
	},

	onmouseover:	function (e) {
		e = DoubleSlider.eventHandlers.getEvent(e, this);
		var s = this.double_slider;
		if (e.srcElement == s.top_handle)
			s.top_handle.className = "top_handle hover";
		if (e.srcElement == s.bottom_handle)
			s.bottom_handle.className = "bottom_handle hover";
	},

	onmouseout:	function (e) {
		e = DoubleSlider.eventHandlers.getEvent(e, this);
		var s = this.double_slider;
		if (e.srcElement == s.top_handle && !s._focused)
			s.top_handle.className = "top_handle";
		if (e.srcElement == s.bottom_handle && !s._focused)
			s.bottom_handle.className = "bottom_handle";
	},

	onmousedown:	function (e) {
		e = DoubleSlider.eventHandlers.getEvent(e, this);
		var s = this.double_slider;
		if (s.element.focus)
			s.element.focus();

		DoubleSlider._currentInstance = s;
		var doc = s.document;

		if (doc.addEventListener) {
			doc.addEventListener("mousemove", DoubleSlider.eventHandlers.onmousemove, true);
			doc.addEventListener("mouseup", DoubleSlider.eventHandlers.onmouseup, true);
		}
		else if (doc.attachEvent) 
        {
			doc.attachEvent("onmousemove", DoubleSlider.eventHandlers.onmousemove);
			doc.attachEvent("onmouseup", DoubleSlider.eventHandlers.onmouseup);
			doc.attachEvent("onlosecapture", DoubleSlider.eventHandlers.onmouseup);
			s.element.setCapture();
		}

		if (DoubleSlider.eventHandlers.getTopHandle(e)) 
        {	// start drag top handle
			DoubleSlider._sliderDragData = {
				screenX:	    e.screenX,
				screenY:	    e.screenY,
				dx:			    e.screenX - s.top_handle.offsetLeft,
				dy:			    e.screenY - s.top_handle.offsetTop,
				startValue:	    s.getTopValue(),
				double_slider:  s,
                drag_handle:    s.top_handle,
                handle_offset_h:  s.top_handle.offsetWidth / 2 * -1,
                handle_offset_v:  s.top_handle.offsetHeight / 2 * -1
			};
		}
		else if (DoubleSlider.eventHandlers.getBottomHandle(e)) 
        {	// start drag top handle
			DoubleSlider._sliderDragData = {
				screenX:	    e.screenX,
				screenY:	    e.screenY,
				dx:			    e.screenX - s.bottom_handle.offsetLeft,
				dy:			    e.screenY - s.bottom_handle.offsetTop,
				startValue:	    s.getBottomValue(),
				double_slider:  s,
                drag_handle:    s.bottom_handle,
                handle_offset_h:  s.bottom_handle.offsetWidth / 2,
                handle_offset_v:  s.bottom_handle.offsetHeight / 2
			};
		}
		else 
        {
			var slider_fieldEl = DoubleSlider.eventHandlers.getSliderField(e);
			s._mouseX = e.offsetX + (slider_fieldEl ? s.slider_field.offsetLeft : 0);
			s._mouseY = e.offsetY + (slider_fieldEl ? s.slider_field.offsetTop : 0);
			s._top_increasing = null;
			s._bottom_increasing = null;
			s.ontimer();
		}
	},

	onmousemove:	function (e) {
		e = DoubleSlider.eventHandlers.getEvent(e, this);

		if (DoubleSlider._sliderDragData) {	// drag
			var s = DoubleSlider._sliderDragData.double_slider;
            var drag_handle = DoubleSlider._sliderDragData.drag_handle;

			var boundSize = s.getMaximum() - s.getMinimum();
			var size, pos, reset;
            var handle_offset;

			if (s._orientation == "horizontal") {
				size = s.element.offsetWidth - drag_handle.offsetWidth;
				pos = e.screenX - DoubleSlider._sliderDragData.dx;
				reset = Math.abs(e.screenY - DoubleSlider._sliderDragData.screenY) > 100;
                handle_offset = DoubleSlider._sliderDragData.handle_offset_h;
			}
			else {
				size = s.element.offsetHeight - drag_handle.offsetHeight;
				pos = s.element.offsetHeight - drag_handle.offsetHeight -
					(e.screenY - DoubleSlider._sliderDragData.dy);
				reset = Math.abs(e.screenX - DoubleSlider._sliderDragData.screenX) > 100;
                handle_offset = DoubleSlider._sliderDragData.handle_offset_v;
			}
            
            var newVal = s.getMinimum() + boundSize * (pos + handle_offset) / size;
            newVal = Math.round((newVal / s._unitIncrement)) * s._unitIncrement;
			s.setValue(reset ? DoubleSlider._sliderDragData.startValue : newVal, drag_handle);
			return false;
		}
		else 
        {
			var s = DoubleSlider._currentInstance;
			if (s != null) 
            {
				var slider_fieldEl = DoubleSlider.eventHandlers.getSliderField(e);
				s._mouseX = e.offsetX + (slider_fieldEl ? s.slider_field.offsetLeft : 0);
				s._mouseY = e.offsetY + (slider_fieldEl ? s.slider_field.offsetTop : 0);
			}
		}

	},

	onmouseup:	function (e) {
		e = DoubleSlider.eventHandlers.getEvent(e, this);
		var s = DoubleSlider._currentInstance;
		var doc = s.document;
		if (doc.removeEventListener) {
			doc.removeEventListener("mousemove", DoubleSlider.eventHandlers.onmousemove, true);
			doc.removeEventListener("mouseup", DoubleSlider.eventHandlers.onmouseup, true);
		}
		else if (doc.detachEvent) {
			doc.detachEvent("onmousemove", DoubleSlider.eventHandlers.onmousemove);
			doc.detachEvent("onmouseup", DoubleSlider.eventHandlers.onmouseup);
			doc.detachEvent("onlosecapture", DoubleSlider.eventHandlers.onmouseup);
			s.element.releaseCapture();
		}

		if (DoubleSlider._sliderDragData) {	// end drag
			DoubleSlider._sliderDragData = null;
		}
		else {
			s._timer.stop();
			s._top_increasing = null;
			s._bottom_increasing = null;
		}
		DoubleSlider._currentInstance = null;
	},

	onkeydown:	function (e) {
		e = DoubleSlider.eventHandlers.getEvent(e, this);
		//var s = DoubleSlider.eventHandlers.getDoubleSlider(e);
		var s = this.double_slider;
		var kc = e.keyCode;
		switch (kc) {
			case 33:	// page up
				s.setTopValue(s.getTopValue() + s.getBlockIncrement());
				break;
			case 34:	// page down
				s.setTopValue(s.getTopValue() - s.getBlockIncrement());
				break;
			case 35:	// end
				s.setTopValue(s.getOrientation() == "horizontal" ?
					s.getMaximum() :
					s.getMinimum());
				break;
			case 36:	// home
				s.setTopValue(s.getOrientation() == "horizontal" ?
					s.getMinimum() :
					s.getMaximum());
				break;
			case 38:	// up
			case 39:	// right
				s.setTopValue(s.getTopValue() + s.getUnitIncrement());
				break;

			case 37:	// left
			case 40:	// down
				s.setTopValue(s.getTopValue() - s.getUnitIncrement());
				break;
		}

		if (kc >= 33 && kc <= 40) {
			return false;
		}
	},

	onkeypress:	function (e) {
		e = DoubleSlider.eventHandlers.getEvent(e, this);
		var kc = e.keyCode;
		if (kc >= 33 && kc <= 40) {
			return false;
		}
	},

	onmousewheel:	function (e) {
		e = DoubleSlider.eventHandlers.getEvent(e, this);
		var s = this.double_slider;
		if (s._focused) {
			s.setTopValue(s.getTopValue() + e.wheelDelta / 120 * s.getUnitIncrement());
			// windows inverts this on horizontal sliders. That does not
			// make sense to me
			return false;
		}
	}
};



DoubleSlider.prototype.classNameTag = "double-slider-control",

DoubleSlider.prototype.setValue = function (v, e) {
    if (e == this.top_handle) 
    {
        this.setTopValue(v);
    }
    else
    {
        this.setBottomValue(v);
    }
};

DoubleSlider.prototype.setTopValue = function (v) 
{
    this._top_range.setValue(v);
    this.top_input.value= this.getTopValue();
    if (this.getBottomValue()>v) 
    {
        this.setBottomValue(v);
    }
}

DoubleSlider.prototype.setBottomValue = function (v)
{
    this._bottom_range.setValue(v);
    this.bottom_input.value = this.getBottomValue();
    if (this.getTopValue()<v) 
    {
        this.setTopValue(v);
    }
};

DoubleSlider.prototype.getTopValue = function () {
	return this._top_range.getValue();
};

DoubleSlider.prototype.getBottomValue = function () {
	return this._bottom_range.getValue();
};

DoubleSlider.prototype.setMinimum = function (v) {
	this._top_range.setMinimum(v);
	this._bottom_range.setMinimum(v);
	this.bottom_input.value = this.getBottomValue();
	this.top_input.value = this.getTopValue();
};

DoubleSlider.prototype.getMinimum = function () {
	return this._top_range.getMinimum();
};

DoubleSlider.prototype.setMaximum = function (v) {
	this._top_range.setMaximum(v);
	this.top_input.value = this.getTopValue();
	this._bottom_range.setMaximum(v);
	this.bottom_input.value = this.getBottomValue();
};

DoubleSlider.prototype.getMaximum = function () {
	return this._top_range.getMaximum();
};

DoubleSlider.prototype.setUnitIncrement = function (v) {
	this._unitIncrement = v;
};

DoubleSlider.prototype.getUnitIncrement = function () {
	return this._unitIncrement;
};

DoubleSlider.prototype.setBlockIncrement = function (v) {
	this._blockIncrement = v;
};

DoubleSlider.prototype.getBlockIncrement = function () {
	return this._blockIncrement;
};

DoubleSlider.prototype.getOrientation = function () {
	return this._orientation;
};

DoubleSlider.prototype.setOrientation = function (sOrientation) {
	if (sOrientation != this._orientation) {
		if (DoubleSlider.isSupported && this.element) {
			// add class name tag to class name
			this.element.className = this.element.className.replace(this._orientation,
									sOrientation);
		}
		this._orientation = sOrientation;
		this.recalculate();

	}
};

DoubleSlider.prototype.recalculate = function() {
	if (!DoubleSlider.isSupported || !this.element) return;

	var w = this.element.offsetWidth;
	var h = this.element.offsetHeight;
	var thw = this.top_handle.offsetWidth;
	var thh = this.top_handle.offsetHeight;
	var bhw = this.bottom_handle.offsetWidth;
	var bhh = this.bottom_handle.offsetHeight;
	var lw = this.slider_field.offsetWidth;
	var lh = this.slider_field.offsetHeight;

	// this assumes a border-box layout
    // top handle
	if (this._orientation == "horizontal") {
		this.top_handle.style.left = (w - thw) * (this.getTopValue() - this.getMinimum()) /
			(this.getMaximum() - this.getMinimum())+6 + "px";
		this.top_handle.style.top = (h - thh) / 2 + "px";

		this.slider_field.style.top = (h - lh) / 2 + "px";
		this.slider_field.style.left = thw / 2 + "px";
		//this.slider_field.style.right = thw / 2 + "px";
		this.slider_field.style.width = Math.max(0, w - thw - 2)+ "px";
		this.slider_field.firstChild.style.width = Math.max(0, w - thw - 4)+ "px";
	}
	else {
		this.top_handle.style.left = (w - thw) / 2 + "px";
//		this.top_handle.style.top = (h - thh - (h - thh) * (this.getTopValue() - this.getMinimum()) /
//			(this.getMaximum() - this.getMinimum()))-6 + "px";
        this.top_handle.style.top = (h - thh - (h - thh) * (this.getTopValue() - this.getMinimum()) /
            (this.getMaximum() - this.getMinimum()))-6 + "px";

		this.slider_field.style.left = (w - lw) / 2 + "px";
		this.slider_field.style.top = thh / 2 + "px";
//        this.slider_field.style.top = thh + "px";
		this.slider_field.style.height = Math.max(0, h - thh - 2) + "px";	//hard coded border width
		//this.slider_field.style.bottom = thh / 2 + "px";
		this.slider_field.firstChild.style.height = Math.max(0, h - thh - 4) + "px";	//hard coded border width
	}

	if (this._orientation == "horizontal") {
		this.bottom_handle.style.left = (w - bhw) * (this.getBottomValue() - this.getMinimum()) /
			(this.getMaximum() - this.getMinimum())-6 + "px";
		this.bottom_handle.style.top = (h - bhh) / 2 + "px";

		this.slider_field.style.top = (h - lh) / 2 + "px";
		this.slider_field.style.left = bhw / 2 + "px";
		//this.slider_field.style.right = bhw / 2 + "px";
		this.slider_field.style.width = Math.max(0, w - bhw - 2)+ "px";
		this.slider_field.firstChild.style.width = Math.max(0, w - bhw - 4)+ "px";
	}
	else {
		this.bottom_handle.style.left = (w - bhw) / 2 + "px";
		this.bottom_handle.style.top = (h - bhh - (h - bhh) * (this.getBottomValue() - this.getMinimum()) /
			(this.getMaximum() - this.getMinimum()))+6 + "px";

		this.slider_field.style.left = (w - lw) / 2 + "px";
		this.slider_field.style.top = bhh / 2 + "px";
		this.slider_field.style.height = Math.max(0, h - bhh - 2) + "px";	//hard coded border width
		//this.slider_field.style.bottom = bhh / 2 + "px";
		this.slider_field.firstChild.style.height = Math.max(0, h - bhh - 4) + "px";	//hard coded border width
	}
};

DoubleSlider.prototype.ontimer = function () {
	var hw = this.top_handle.offsetWidth;
	var hh = this.top_handle.offsetHeight;
	var hl = this.top_handle.offsetLeft;
	var ht = this.top_handle.offsetTop;

	if (this._orientation == "horizontal") {
		if (this._mouseX > hl + hw &&
			(this._top_increasing == null || this._top_increasing)) {
			this.setTopValue(this.getTopValue() + this.getBlockIncrement());
			this._top_increasing = true;
		}
		else if (this._mouseX < hl &&
			(this._top_increasing == null || !this._top_increasing)) {
			this.setTopValue(this.getTopValue() - this.getBlockIncrement());
			this._top_increasing = false;
		}
	}
	else {
		if (this._mouseY > ht + hh &&
			(this._top_increasing == null || !this._top_increasing)) {
			this.setTopValue(this.getTopValue() - this.getBlockIncrement());
			this._top_increasing = false;
		}
		else if (this._mouseY < ht &&
			(this._top_increasing == null || this._top_increasing)) {
			this.setTopValue(this.getTopValue() + this.getBlockIncrement());
			this._top_increasing = true;
		}
	}

	hw = this.bottom_handle.offsetWidth;
	hh = this.bottom_handle.offsetHeight;
	hl = this.bottom_handle.offsetLeft;
	ht = this.bottom_handle.offsetTop;

	if (this._orientation == "horizontal") {
		if (this._mouseX > hl + hw &&
			(this._bottom_increasing == null || this._bottom_increasing)) {
			this.setBottomValue(this.getBottomValue() + this.getBlockIncrement());
			this._bottom_increasing = true;
		}
		else if (this._mouseX < hl &&
			(this._bottom_increasing == null || !this._bottom_increasing)) {
			this.setBottomValue(this.getBottomValue() - this.getBlockIncrement());
			this._bottom_increasing = false;
		}
	}
	else {
		if (this._mouseY > ht + hh &&
			(this._bottom_increasing == null || !this._bottom_increasing)) {
			this.setBottomValue(this.getBottomValue() - this.getBlockIncrement());
			this._bottom_increasing = false;
		}
		else if (this._mouseY < ht &&
			(this._bottom_increasing == null || this._bottom_increasing)) {
			this.setBottomValue(this.getBottomValue() + this.getBlockIncrement());
			this._bottom_increasing = true;
		}
	}
	this._timer.start();
};