/*******************************************************************************/
/* mud_Scroll.js                                                               */
/* REQUIRES mud_API.js
/* author: Takashi Okamoto mud(tm) - http://mudcorp.com
/*******************************************************************************/

// LIST OF CONSTANTS/VARS
var selectedObj;
var offsetX, offsetY;
var animateID;

MudScroll.DELAY = 10;

// FUNCTIONS
function setSelectedElem(evt) {
	evt = (evt) ? evt : event;
    var target = (evt.target) ? evt.target : evt.srcElement;
    var divID = (target.id) ? target.id : target.name;
    if (divID) {
		if (document.layers) {
			selectedObj = document.layers[divID];
		} else if (document.all) {
			selectedObj = document.all(divID);
		} else if (document.getElementById) {
			selectedObj = document.getElementById(divID);
		}
		setZIndex(selectedObj, 100);
		return;
	}
	selectedObj = null;
}

// CONSTRUCTOR
function MudScroll(id, content, contentheight, barheight, scrollheight, topOffset) {
	this.id = id;
	this.wrapper = this.id + "-wrapper";
	this.content = content;
	this.contentheight = contentheight - barheight;
	this.barheight = barheight;
	this.scrollheight = scrollheight;
	this.barlength = barheight - scrollheight;
	this.topOffset = topOffset;
	
	this.contentscale = this.contentheight / this.barlength;
	
	this.posX = 0;
	this.posY = 0;
	this.tmpX = 0;
	this.tmpY = 0;
	this.oldX = 0;
	this.oldY = 0;
	this.scrolling = false;
	this.unit = 0;
	this.res = 20;
	this.frame = 0;
	// flag to set whether to animate when scrolling
	this.animation = true;
}

// called onmousedown
MudScroll.prototype.engage = function(evt) {
	evt = (evt) ? evt : event;
	setSelectedElem(evt);
	if (selectedObj) {
		this.calcOffset(evt);
		if (!isIE4 || isMac) evt.stopPropagation();
		else evt.cancelBubble = true;
		return false;
	}
}

// called onmousemove
MudScroll.prototype.drag = function(evt) {
	evt = (evt) ? evt : event;
	if (selectedObj.id != this.wrapper) {
		// set positions
		if (evt.pageY) {
			this.posY = evt.pageY - offsetY;
		} else if (evt.clientY) {
			this.posY = evt.clientY - offsetY - this.topOffset;
		}
		this.posX = 0;
		this.limitPos();
		this.movePos(this.posX, this.posY);
	}
	return false;
}

// called onmouseup
MudScroll.prototype.release = function(evt) {
	if (selectedObj.id == this.wrapper) {
		evt = (evt) ? evt : event;
		// calculate offset
		this.calcOffset(evt);
		// setting positions
		this.oldX = this.posX;
		this.oldY = this.posY;
		this.posY = offsetY - this.scrollheight/2;
		this.posX = 0;
		this.limitPos();
		// see if scroll animation is turned on
		if (this.animation) {
			this.animate();
		}
		else {
			this.movePos(this.posX, this.posY);
		}
	}
	if (selectedObj) {
		selectedObj = null;
	}
	return false;
}

MudScroll.prototype.scrollTo = function(px, py) {
	this.oldX = this.posX;
	this.oldY = this.posY;
	this.posX = px / this.contentscale;
	this.posY = py / this.contentscale;
	this.limitPos();
	if (this.animation) {
		this.animate();
	}
	else {
		this.movePos(this.posX, this.posY);
	}
}

MudScroll.prototype.scrollBy = function(px, py) {
	this.oldX = this.posX;
	this.oldY = this.posY;
	this.posX += px;
	this.posY += py;
	this.limitPos();
	if (this.animation) {
		this.animate();
	}
	else {
		this.movePos(this.posX, this.posY);
	}
}

MudScroll.prototype.animate = function() {
	if (animateID) animateID = null;
	if (!this.scrolling) {
		this.unitY = (this.posY - this.oldY) / this.res;
		this.scrolling = true;
	}
	var posX, posY;
	posY = this.unitY * this.frame;
	posX = 0;
	this.movePos(this.oldX + posX, this.oldY + posY);
	if (this.frame < this.res) {
		animateID = window.setTimeout(this.id + ".animate()", MudScroll.DELAY);
		this.frame++;
	}
	else {
		this.scrolling = false;
		this.frame = 0;
	}
}

MudScroll.prototype.calcOffset = function(evt) {
	evt = (evt) ? evt : event;
	if (evt.pageX) {
		offsetX = evt.pageX - ((selectedObj.offsetLeft) ? selectedObj.offsetLeft : 0);
		if (evt.target.id == "scroll-wrapper") offsetY = evt.pageY - this.topOffset - ((selectedObj.offsetTop) ? selectedObj.offsetTop : 0);
		else offsetY = evt.pageY - ((selectedObj.offsetTop) ? selectedObj.offsetTop : 0);
	} else if (evt.offsetX) {
		offsetX = evt.offsetX - ((evt.offsetX < -2) ? 0 : document.body.scrollLeft);
		offsetY = evt.offsetY - ((evt.offsetY < -2) ? 0 : document.body.scrollTop);
	} else if (evt.clientX) {
		offsetX = evt.clientX - ((selectedObj.offsetLeft) ? selectedObj.offsetLeft : 0);
		offsetY = evt.clientY - ((selectedObj.offsetTop) ? selectedObj.offsetTop : 0);
	}
	// make sure offsetX, offsetY is not NaN
	if (isNaN(offsetX)) offsetX = 0;
	if (isNaN(offsetY)) offsetY = 0;
}

MudScroll.prototype.limitPos = function() {
	// constrain posX to wrapper
	this.posY = Math.max(this.posY, 0);
	this.posY = Math.min(this.posY, this.barheight - this.scrollheight);
	// constrain posX
	this.posX = 0;
}

MudScroll.prototype.movePos = function(posX, posY) {
	// move scroll
	shiftTo(getRawObject(this.id), posX, posY);
	// move content
	var contX = this.contentscale * posX;
	var contY = this.contentscale * posY;
	if (contY > 0) contY = -contY;
	shiftTo(getRawObject(this.content), -contX, contY);
}

// METHODS TO OVERRIDE
MudScroll.prototype.onSlideStart = function() {} // called when MudScroll.slideStart is called
MudScroll.prototype.onSlideStop = function() {} // called when MudScroll.slideStop is called