/*******************************************************************************

FILE: mud_Scroll.js
REQUIRES: prototype.js
AUTHOR: Takashi Okamoto mud(tm) - http://www.mudcorp.com/
VERSION: 2.0
DATE: 01/21/2006

--------------------------------------------------------------------------------

This file is part of MudScroll.

	MudScroll is free for anyone to use, but this header MUST be
	included, and may not be modified.
	
--------------------------------------------------------------------------------

Usage:

MudScroll(id, content, contentheight, barheight, scrollheight, topOffset)

options:
	startNum: (int) image number to start with.
	preload: (bool) set whether you want to initially preload images.
	autoplay: (int) set if you want to autoplay the image slide, and define
					the time for switch in seconds. default: 0 (no autoplay)

*******************************************************************************/

var MudScroll = Class.create();

// 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) {
		selectedObj = $(divID);
		$(selectedObj).style.zIndex = 100;
		return;
	}
	selectedObj = null;
}

MudScroll.prototype = {
	
	initialize: function(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
	engage: function(evt) {
		evt = (evt) ? evt : event;
		setSelectedElem(evt);
		if (selectedObj) {
			this.calcOffset(evt);
			if (!/MSIE/.test(navigator.userAgent) || /Mac/.test(navigator.userAgent)) evt.stopPropagation();
			else evt.cancelBubble = true;
			return false;
		}
	},

	// called onmousemove
	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
	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;
	},

	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);
		}
	},

	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);
		}
	},

	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;
		}
	},

	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;
	},

	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;
	},

	movePos: function(posX, posY) {
		// move scroll
		$(this.id).style.left = posX + "px";
		$(this.id).style.top = posY + "px";
		// move content
		var contX = this.contentscale * posX;
		var contY = this.contentscale * posY;
		if (contY > 0) contY = -contY;
		$(this.content).style.left = -contX +"px";
		$(this.content).style.top = contY + "px";
	}
}