var arrowTimeLag = 500;
var scrollDistanceOnClick = 30;
var arrowPressTimeout;
var scrollbars = new Array();
var currentScrollbar;

function ScrollPanel(scrollPanelID, scrollBarID, scrollButtonUpID, scrollButtonDownID) {
	this.scrollPanelID = scrollPanelID;
	this.scrollBarID = scrollBarID;
	this.scrollPanel = $("#" + this.scrollPanelID);
	this.contentBox = $("#" + this.scrollPanelID + " > .scrollContent:first-child");
	this.scrollBar = $("#" + this.scrollBarID);
	if (this.getMaxScrollDistance() > 0) {
		this.scrollBar.css("display", "block");
		this.scrollHead = $("#" + this.scrollBarID + " > .scrollHead:first-child");
		this.scrollHead.data("scrollPanel", this);
		this.scrollHead.draggable({
			containment: 'parent',
			drag: this.drag});
	}
	this.observers = new Array();
	this.scrollButtonUpID = scrollButtonUpID;
	this.scrollButtonDownID = scrollButtonDownID;
	if (scrollButtonUpID) {
		$('#' + scrollButtonUpID).mousedown(this.handleButtonUpPressed);
		$('#' + scrollButtonUpID).mouseup(this.handleButtonUpReleased);
	}
	if (scrollButtonDownID) {
		$('#' + scrollButtonDownID).mousedown(this.handleButtonDownPressed);
		$('#' + scrollButtonDownID).mouseup(this.handleButtonDownReleased);
	}
	// store scroll bar with id
	scrollbars[scrollBarID] = this;
}

ScrollPanel.prototype.getMaxScrollDistance = function () {
	var distance = this.contentBox.height() - this.scrollPanel.height();
	if (distance > 0) {
		return distance;
	} else {
		return 0;
	}
};

ScrollPanel.prototype.toString = function() {
	return "[ScrollPanel object {scrollPanelID: " + this.scrollPanelID + ", scrollBarID: " + this.scrollBarID + ", scrollPanel.height(): " + this.scrollPanel.height() + ", content height: "+ this.contentBox.height() +", max scroll distance: " + this.getMaxScrollDistance() + "}]";
}

ScrollPanel.prototype.drag = function(event, ui) {
	var scrollHeadHeight = ui.helper.height();
	var maxScrollPosition = ui.helper.parent().height() - scrollHeadHeight;
	var scrollPanelObject = ui.helper.data("scrollPanel"); 
	var position = ui.position.top / maxScrollPosition;
	var scrollDistance = scrollPanelObject.getMaxScrollDistance() * position;
	scrollPanelObject.contentBox.css("top", "-"+scrollDistance+"px");
}

ScrollPanel.prototype.addObserver = function(observerKey, observer) {
	if (observerKey && observer) {
		this.observers[observerKey] = observer;
	}
}

ScrollPanel.prototype.removeObserver = function(observerKey) {
	if (observerKey && this.observers[observerKey]) {
		delete this.observers[observerKey];
	}
}

ScrollPanel.prototype.handleButtonUpPressed = function(event, ui) {
	// although this function was passed to the button as "this.handleButtonUpPressed it somehow
	// lost the connection to it's ScrollPanel object. "this" returns the window instead of the 
	// ScrollPanel object! We therefore need to find the id of the scrollBar and retreive the
	// object from there :-/
	var target
	if (event.target) {
		target = event.target;
	} else if (event.srcElement) {
		target = event.srcElement;
	}
	var helperElement = target;
	while (helperElement != null && (!$(helperElement).hasClass("scrollBar"))) {
		helperElement = helperElement.parentNode;
	}
	var thisScrollPane = scrollbars[helperElement.id];
	if (thisScrollPane) {
		currentScrollbar = thisScrollPane;
		arrowPressTimeout = setTimeout("scroll(currentScrollbar, -scrollDistanceOnClick)", arrowTimeLag);
	}	
}

ScrollPanel.prototype.handleButtonDownPressed = function(event, ui) {
	// although this function was passed to the button as "this.handleButtonUpPressed it somehow
	// lost the connection to it's ScrollPanel object. "this" returns the window instead of the 
	// ScrollPanel object! We therefore need to find the id of the scrollBar and retreive the
	// object from there :-/
	var target
	if (event.target) {
		target = event.target;
	} else if (event.srcElement) {
		target = event.srcElement;
	}
	var helperElement = target;
	while (helperElement != null && (!$(helperElement).hasClass("scrollBar"))) {
		helperElement = helperElement.parentNode;
	}
	var thisScrollPane = scrollbars[helperElement.id];
	if (thisScrollPane) {
		currentScrollbar = thisScrollPane;
		arrowPressTimeout = setTimeout("scroll(currentScrollbar, scrollDistanceOnClick)", arrowTimeLag);
	}	
}

ScrollPanel.prototype.handleButtonUpReleased = function(event, ui) {
	clearTimeout(arrowPressTimeout);
}

ScrollPanel.prototype.handleButtonDownReleased = function(event, ui) {
	clearTimeout(arrowPressTimeout);
}

ScrollPanel.prototype.scroll = function(scrollDistance) {
//	alert("scrollPane: "+this);
	var scrollHead = $('#' + this.scrollBarID + ' .scrollHead');
	if (!scrollHead) {
		alert("ERROR: no scrollHead found!");
		return;
	}
	// 1. get current scroll position
	var scrollHeadHeight = scrollHead.height();
	var maxScrollPosition = scrollHead.parent().height() - scrollHeadHeight;
	var position = scrollHead.position();
//	alert("scroll head position: "+position.top);
	// 2. check if you can scroll that much
	var scrollY = 0;
	if (scrollDistance > 0) {
		if (position.top + scrollDistance <= maxScrollPosition) {
			scrollY = scrollDistance;
		} else {
			scrollY = maxScrollPosition - position.top;
		}
	} else {
		if (position.top >= scrollDistance * -1) {
			scrollY = scrollDistance;
		} else {
			scrollY = position.top * -1;
		}
	}
	// scroll by scrollY
	var newScrollPositionInPercent = (position.top + scrollY) / maxScrollPosition;
	
	// 3. scroll!
	var scrollDistance = this.getMaxScrollDistance() * newScrollPositionInPercent;
//	this.contentBox.css("top", "-"+scrollDistance+"px");
	this.contentBox.animate({ 
        top: "-"+scrollDistance+"px"
        }, arrowTimeLag);
//	scrollHead.css("top", (position.top + scrollY) + "px");
	scrollHead.animate({ 
        top: (position.top + scrollY)+"px"
        }, arrowTimeLag);
}

function scroll(scrollPane, scrollDistance) {
	if (scrollPane) {
		scrollPane.scroll(scrollDistance);
		currentScrollbar = scrollPane;
		if (scrollDistance > 0) {
			arrowPressTimeout = setTimeout("scroll(currentScrollbar, scrollDistanceOnClick)", arrowTimeLag);
		} else {
			arrowPressTimeout = setTimeout("scroll(currentScrollbar, -scrollDistanceOnClick)", arrowTimeLag);
		}
	} else {
		alert("no scroll bar to scroll!");
	}
}
