/*
	Class Slider

	To use this feature:
	1 - instantiate
	2 - set knob width and knob buffer?
	3 - init
*/
function Slider(slidebar, knob, min, max, increment, caller, callback) {
	// save the knob and slidebar ids instead of the elements because when I link the Slider object to an element in order to grab it on user events on the element (ie. in global scope) this causes circular references which in turn causes memory leaks in IE.
	this.slidebarID = slidebar.id;
	this.knobID = knob.id;
	this.min = min;
	this.max = max;
	this.increment = increment;
	this.caller = caller
	this.callback = callback;

	// get the min and max x values of the slidebar, relative to the enclosing control div
	this.slideMinX = parseInt(slidebar.style.left);	
	this.slideMaxX = this.slideMinX + parseInt(slidebar.style.width);

	// something is rotten in the state of Microsoft.... knob.width is always 0 even if I set it directly
	// so I am hard-coding the value of 31; if the knob size changes, this will have to change too by
	// setting slider.knobWidth after instantiating the slider
	if (knob.width > 0) this.knobWidth = knob.width;
	else this.knobWidth = 21;
}

// these buffer is for the difference between the edges of the image file and the edges of the actual knob
// should set prototypes to 0 and set slider.knobLeftBuffer and/or slider.knobRightBuffer after instantiating the slider, if needed
Slider.prototype.knobLeftBuffer = 0;
Slider.prototype.knobRighttBuffer = 0;

Slider.prototype.init = function(level) {
	// get the knob element
	var knob = document.getElementById(this.knobID);
	var slidebar = document.getElementById(this.slidebarID);

	// divide the bar up so each possible value has equal space on the bar ie (max-min+1) spaces
	this.dX = (this.slideMaxX - this.slideMinX) / (this.max - this.min + this.increment);	

	// adjust the minX and maxX values to represent the min and max left boundaries of the knob
	this.knobMinX = this.slideMinX - this.knobLeftBuffer;	// taking into account transparent frame around knob

	this.knobMaxX = this.slideMaxX - this.knobWidth + this.knobRightBuffer;
	this.knob_dX = (this.knobMaxX - this.knobMinX) / (this.max - this.min);

	// click events return with window relative locations but I need div relative to set so
	// I am creating a table with ((max-min+1)/increments) little divs to pass their index when clicked

	var table = document.createElement("table");

	table.width = '100%';
	table.height = '100%';
	table.vAlign = 'top';
	table.cellPadding = '0';
	table.cellSpacing = '0';

	slidebar.appendChild(table);

	// must expicitly create tBody element for IE 
	var tBody = document.createElement("tBody");
//	tBody.style.backgroundColor = "red";	// testing
	table.appendChild(tBody);

	var row = document.createElement("tr");
	row.style.height = slidebar.style.height;
	tBody.appendChild(row);

	var col, div;
	var width = Math.round(this.dX);
	for (var i=this.min; i <= this.max; i+=this.increment) {
		col = document.createElement("td")
		row.appendChild(col);

		div = document.createElement("div");
		div.id = this.slidebarID + i;
		div.className = "zoom_control_img";
		div.style.height = slidebar.style.height;	// must have this for FF
		div.style.width = width + 'px';
		div.unselectable = "on";
		div.zoomLevel = i;

		col.appendChild(div);
	}

	// place the knob in starting position if provided
	if (level)
		this.setSlider(level);

	var thisObj = this;
	// register events for the slidebar and knob
	if (slidebar.addEventListener) {
		slidebar.addEventListener("click", function(event) {thisObj.clicked(event.target.zoomLevel);}, true);
		knob.addEventListener("mousedown", function(event) {thisObj.startDrag(event);}, true);
	}
	else {
//		slidebar.attachEvent("onclick", function(event) {thisObj.handleBarEvent(event);});
		slidebar.attachEvent("onclick", function(event) {thisObj.clicked(event.srcElement.zoomLevel);});
		knob.attachEvent("onmousedown",  function(event) {thisObj.startDrag(event);});
	}
}

Slider.prototype.setSlider = function(value) {
	if (value != this.value) { 
		this.value = value;
		this.moveKnob();
	}
}

Slider.prototype.moveUp = function() {
	if (this.value < this.max) {
		this.value += this.increment;
		this.moveKnob();
	}
} 

Slider.prototype.moveDn = function() {
	if (this.value > this.min) {
		this.value -= this.increment;
		this.moveKnob();
	}
}

Slider.prototype.moveKnob = function() {
	var knob = document.getElementById(this.knobID);
	knob.style.left = this.knobMinX + Math.round((this.value-this.min) * this.knob_dX) + "px";
} 

Slider.prototype.clicked = function (level) {
	if (!level) return;
	this.setSlider(level);
	this.caller[this.callback](level);
}

Slider.prototype.startDrag = function(event) {
	var elem;
	if (event.target)
		elem = event.target;
	else
		elem = event.srcElement;
	elem.sliderObj = this;

	this.startSlideX = parseInt(elem.style.left);

	this.startWinX = event.clientX + (window.scrollX ? window.scrollX : document.body.scrollLeft);

	// register drag event handlers
	if (document.addEventListener) {
		document.addEventListener("mousemove", onDrag, true);
		document.addEventListener("mouseup", endDrag, true);
		event.preventDefault();
		event.stopPropagation();
	}
	else {	
		document.attachEvent("onmousemove", onDrag);
		document.attachEvent("onmouseup", endDrag);
		event.cancelBubble = true;
		event.returnValue = false;
	}

// Note that onDrag and endDrag are defined within Slider.startDrag, this allows us to use the local variables from startDrag in global scope when event handlers are invoked

	function onDrag(event) {
		// calculate new location
		var winX = event.clientX + (window.scrollX ? window.scrollX : document.body.scrollLeft);
		var slideX = elem.sliderObj.startSlideX + winX - elem.sliderObj.startWinX;
		// keep within the slidebar boundaries
		if (slideX < elem.sliderObj.knobMinX) slideX = elem.sliderObj.knobMinX;
		else if (slideX > elem.sliderObj.knobMaxX) slideX = elem.sliderObj.knobMaxX;

		elem.style.left = slideX + "px";

		if (event.stopPropagation) event.stopPropagation();	// FF
		else event.cancelBubble = true;			// IE
	}

	function endDrag(event) {
		// de-register drag event handlers
		if (document.removeEventListener) {
			document.removeEventListener("mouseup", endDrag, true);
			document.removeEventListener("mousemove", onDrag, true);
		}
		else {
			document.detachEvent("onmouseup", endDrag);
			document.detachEvent("onmousemove", onDrag);
		}
		var currentX = parseInt(elem.style.left);
		elem.sliderObj.value = Math.round((currentX - elem.sliderObj.knobMinX) / elem.sliderObj.knob_dX) + elem.sliderObj.min;

		elem.sliderObj.caller[elem.sliderObj.callback](elem.sliderObj.value);

		if (event.stopPropagation) {		// FF
			event.preventDefault();
			event.stopPropagation();
		}
		else {
			event.cancelBubble = true;			// IE
			event.returnValue = false;
		}
	}
}
