
function JRng() {
	this.val = 0;
	this.min = 0;
	this.max = 100;
	this.step = 10;
}
JRng.prototype.setValue = function (value) {
	value = parseInt(value);
	if (this.step > 1) {
		value = Math.round(value/this.step)*this.step;
	}
	if (isNaN(value)) return;
    this.val = Math.max (this.min, Math.min (this.max, value));
	if (typeof this.onchange == "function")
		 this.onchange();
};
JRng.prototype.getValue = function () {
	return this.val;
};
JRng.prototype.getMinimum = function () {
	return this.min;
};
JRng.prototype.getMaximum = function () {
	return this.max;
};


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

Slider.$ = function (ele) {
	if (typeof ele == "string") return document.getElementById(ele);
	else return ele;
}

function Slider(sElement, sInput, nTotalWidth, nTotalHeight, nValue) {
	var oElement = Slider.$(sElement);
	var oInput = Slider.$(sInput);
	if (!oElement || !oInput) return;
	this._range = new JRng();
	this._blockIncrement = 10;
	this._unitIncrement = 10;
	this.nTotalWidth_ = nTotalWidth;
	this.nTotalHeight_ = nTotalHeight;
	if (Slider.isSupported && oElement) {
		this.document = oElement.ownerDocument || oElement.document;
		this.element = oElement;
		this.element.slider = this;
		this.element.unselectable = "on";
		this.element.className = this.classNameTag + " " + this.element.className;
		this.linel = this.document.createElement("DIV");
		this.linel.className = "line ll";
		this.linel.unselectable = "on";
		this.element.appendChild(this.linel);
		this.liner = this.document.createElement("DIV");
		this.liner.className = "line lr";
		this.liner.unselectable = "on";
		this.element.appendChild(this.liner);
		this.handle = this.document.createElement("DIV");
		this.handle.className = "handle";
		this.handle.unselectable = "on";
		this.handle.appendChild(this.document.createElement("DIV"));
		this.handle.firstChild.appendChild(this.document.createTextNode(String.fromCharCode(160)));
		this.element.appendChild(this.handle);
	}

	this.input = oInput;

	// events
	var oThis = this;
	this._range.onchange = function () {
		oThis.recalculate();
		if (typeof oThis.onchange == "function")
			oThis.onchange(oThis);
	};

	if (Slider.isSupported && oElement) {
		this.element.onfocus		= Slider.eventHandlers.onfocus;
		this.element.onblur			= Slider.eventHandlers.onblur;
		this.element.onmousedown	= Slider.eventHandlers.onmousedown;
		this.element.onmouseover	= Slider.eventHandlers.onmouseover;
		this.element.onmouseout		= Slider.eventHandlers.onmouseout;
		this.element.onkeydown		= Slider.eventHandlers.onkeydown;
		this.element.onkeypress		= Slider.eventHandlers.onkeypress;
		this.handle.onselectstart	=
		this.element.onselectstart	= function () { return false; };
	} else {
		this.input.onchange = function (e) {
			oThis.setValue(oThis.input.value);
		};
	}
	if (nValue) oThis.setValue (nValue);
}

Slider.prototype.setStep = function (nStep) {
    this._range.step = nStep;
}

Slider.prototype.setMinimum = function (nMin) {
    this._range.min = nMin;
}

Slider.prototype.setMaximum = function (nMax) {
    this._range.max = nMax;
}

Slider.prototype.getComputedStyle = function (oEle, sStyle) {
	if (oEle.currentStyle)
		return oEle.currentStyle[sStyle];
	else if (window.getComputedStyle)
		return document.defaultView.getComputedStyle(oEle,null).getPropertyValue(sStyle);
	return null;
}

Slider.prototype.getStyleHeight = function (oEle) {
	return parseInt(this.getComputedStyle (oEle, 'height'));
}

Slider.prototype.getStyleWidth = function (oEle) {
	return parseInt(this.getComputedStyle (oEle, 'width'));
}


Slider.eventHandlers = {

	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;
		var re = /line/;
		while (el != null && !re.test(el.className)) {
			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;
	},

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

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

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

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

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

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

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

		if (Slider.eventHandlers.getHandle(e)) {	// start drag
			Slider._sliderDragData = {
				screenX:	e.screenX,
				screenY:	e.screenY,
				dx:			e.screenX - s.handle.offsetLeft,
				dy:			e.screenY - s.handle.offsetTop,
				startValue:	s.getValue(),
				slider:		s
			};
		}
		else {
		    // set value to location
        	var w = s.element.offsetWidth;
        	var hw = s.handle.offsetWidth;
        	var posx = e.screenX - hw/2;
        	var srng = s.getMaximum() - s.getMinimum();
			var lineEl = Slider.eventHandlers.getLine(e);
			var lineOffset = 0;
			if (lineEl) lineOffset = lineEl.offsetLeft;
			var posx = e.offsetX + lineOffset;
		    s.setValue((posx-hw/2)*srng/(w-hw)+s.getMinimum());
		}
	},

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

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

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

			size = s.element.offsetWidth - s.handle.offsetWidth;
			pos = e.screenX - Slider._sliderDragData.dx;
			reset = Math.abs(e.screenY - Slider._sliderDragData.screenY) > 100;
			s.setValue(reset ? Slider._sliderDragData.startValue :
						s.getMinimum() + boundSize * pos / size);
			return false;
		}
		else {
			var s = Slider._currentInstance;
			if (s != null) {
				var lineEl = Slider.eventHandlers.getLine(e);
				s._mouseX = e.offsetX + (lineEl ? s.linel.offsetLeft : 0);
				s._mouseY = e.offsetY + (lineEl ? s.linel.offsetTop : 0);
			}
		}

	},

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

		if (Slider._sliderDragData) {	// end drag
			Slider._sliderDragData = null;
		}
		Slider._currentInstance = null;
	},

	onkeydown:	function (e) {
		e = Slider.eventHandlers.getEvent(e, this);
		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 = Slider.eventHandlers.getEvent(e, this);
		var kc = e.keyCode;
		if (kc >= 33 && kc <= 40) {
			return false;
		}
	}
	
};



Slider.prototype.classNameTag = "dslc";

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

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

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

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

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

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

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

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

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

	var w = this.element.offsetWidth;
	if (!w) w = this.nTotalWidth_;
	var h = this.element.offsetHeight;
	if (!h) h = this.nTotalHeight_;
	var hw = 18; // this.handle.offsetWidth;
	var hh = 11; // this.handle.offsetHeight;
	var lh = 5;  // this.linel.offsetHeight;
	var lw = Math.max(0, w - hw - 2);
	var hl = (w - hw) * (this.getValue() - this.getMinimum()) /
         		(this.getMaximum() - this.getMinimum());
    var hmid = hl + hw/2;
    var llw = Math.max(hmid-hw/2, 0).toFixed(0);
    var lrw = Math.max(lw-llw, 0);
    var lrleft = w - hw/2 - lrw - 2;
	
	this.handle.style.left = hl + "px";
	this.handle.style.top = (h - hh) / 2 + "px";
	this.linel.style.top = (h - lh) / 2 + "px";
	this.linel.style.left = hw / 2 + "px";
    this.linel.style.width = llw + "px";
	this.liner.style.top = (h - lh) / 2 + "px";
	this.liner.style.left = lrleft + "px";
    this.liner.style.width = lrw + "px";

};

