/**
 * ScrollBars.js 
 * Copyright (C) 2006 nightlabs
 * author : khaled at nightlabs dot de
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; 
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 *@param _cssClass A string referencing the desired stylesheet class. If missing, this will default to "defaultScroll".
 *	refObject & refDiv is deprecated.Only the parent Object and Class are beeing tansmitted.
 * @param _string defines the orientation. It can be either vertical or horizontal
 * Note: currently all Events are using a global function (crossBrowserAddEventListener)
 * TODO: call for prototypes to transmit the Object references.
 */
function Scrollbar (_parentObject, _string, _cssClass)
{
	util = Util.getInstance();
	this.parent = _parentObject;
	this.orientationStr = _string;
	this.cssClass = _cssClass;
	if (this.cssClass == null) this.cssClass = "defaultScroll";
	this.scrollListeners = new Array();
	this.isDragingX = false;
	this.isDragingY = false;
	this.isPressed = true;
	
	/* Privat Method that is called for every new Scrollbar object to define the starting layout/params */
	this.initScrollbar = function (){
		this.scrollDiv = document.createElement("div");
		this.scrollDiv.style.position = "absolute";
		//this.scrollDiv.style.overflow = "hidden";
		this.parent.appendChild(this.scrollDiv);
		if (this.orientationStr == "vertical") {
				this.scrollDiv.setAttribute("id", this.cssClass + "_verticalScroll");
		}
		if (this.orientationStr == "horizontal"){
		this.scrollDiv.setAttribute("id", this.cssClass + "_horizontalScroll");
		}
	}
	this.createFirstImage = function (){
		this.image1 = new Image;
		this.image1.style.position = "absolute";
		this.image1.onmouseup = util.createMethodReference(this, "buttonReleased");
		this.image1.onmouseout = util.createMethodReference(this, "buttonReleased");
		if (this.orientationStr == "horizontal"){
			this.image1.src = util.imageUrlToString(util.getStyleRule( "#" + this.cssClass +"_horizontalButtonLeft","backgroundImage"));
			util.crossBrowserAddEventListener(this.image1,"mousedown",util.createMethodReference(this, "startButtonLeftDrag"));
		}
		if (this.orientationStr == "vertical"){
			this.image1.src = util.imageUrlToString(util.getStyleRule( "#" + this.cssClass +"_verticalButtonUp","backgroundImage"));
			util.crossBrowserAddEventListener(this.image1,"mousedown",util.createMethodReference(this, "startButtonUpDrag"));
		}
			this.scrollDiv.appendChild(this.image1);
	}
	this.createSecondImage = function () {
		this.image2 = new Image;
		this.image2.style.position= "absolute";
		this.image2.onmouseup = util.createMethodReference(this, "buttonReleased");
		this.image2.onmouseout = util.createMethodReference(this, "buttonReleased");
		if (this.orientationStr == "horizontal"){
			this.image2.src = util.imageUrlToString(util.getStyleRule( "#" + this.cssClass +"_horizontalButtonRight","backgroundImage"));
			util.crossBrowserAddEventListener(this.image2,"mousedown",util.createMethodReference(this, "startButtonRightDrag"));
		}
		if (this.orientationStr == "vertical"){
			this.image2.src = util.imageUrlToString(util.getStyleRule( "#" + this.cssClass +"_verticalButtonDown","backgroundImage"));
			util.crossBrowserAddEventListener(this.image2,"mousedown",util.createMethodReference(this, "startButtonDownDrag"));
		}
			this.scrollDiv.appendChild(this.image2);
	}
	/* TODO : @params for the Slider to define other Layouts */ 
	this.createSlider = function (){
		this.slider = document.createElement("div");
		this.scrollDiv.appendChild(this.slider);
		this.slider.style.position = "absolute";
		
		util.crossBrowserAddEventListener(this.slider,"mousemove",util.createMethodReference(this, "dragSlider"));
		if (this.orientationStr == "horizontal"){
			this.slider.setAttribute("id", this.cssClass + "_horizontalSlider");
			/* during initialisation slider is moved to a fixed starting position*/
			//this.slider.style.left = this.image1.width +"px"; 
			util.crossBrowserAddEventListener(this.slider,"mousedown",util.createMethodReference(this, "dragStartHorizontalSlider"));
		}	
		if (this.orientationStr == "vertical"){
			this.slider.setAttribute("id", this.cssClass + "_verticalSlider");
			/* during initialisation slider is moved to a fixed starting position*/
			//this.slider.style.top = this.image1.height +"px"; 
			util.crossBrowserAddEventListener(this.slider,"mousedown",util.createMethodReference(this, "dragStartVerticalSlider"));
		}
	this.scrollDiv.appendChild(this.slider);
		
	}
	/* calling all the private init methods . InitScrollbar must be called first*/
	this.initScrollbar();
	this.createFirstImage();
	this.createSecondImage();
	/* params for the Slider would be nice */
	this.createSlider();
	/**
	 * Dirty Workaround to negate the IE behaviour of selecting things with mousedown && mousemove.
	 * it will create an hopefully invisible (!hidden) InputField that will be selected while dragging 
	 * the Scrollbar.  TODO: find an other solution!
	 */ 
	if(navigator.appName == "Microsoft Internet Explorer"){
		this.createInvisibleDiv();
	}
}
/* Ie workaround creating the non visible Input Field .. */  
Scrollbar.prototype.createInvisibleDiv = function (){
	this.form = document.createElement("form")
	this.invisibleDiv = document.createElement("div");
  	this.invisibleDiv.style.overflow ="hidden";
  	this.invisibleDiv.style.position ="absolute";
  	this.invisibleDiv.style.height ="0px";
  	this.invisibleDiv.style.width ="0px";
  	this.inputField = document.createElement("input");
	this.inputField.setAttribute("type","text");
	this.inputField.setAttribute("size","0");
	this.form.appendChild(this.inputField);
	this.invisibleDiv.appendChild(this.form);
	this.parent.appendChild(this.invisibleDiv);
}
/** Note that the document.mousemove && document.mouseup will be overwritten at that stage
 *  Although itīs very likely not to hapen as itīs hard to figure out a case for the
 *  need of a persistent mousemove or mouseup on the entire document.
 */ 
Scrollbar.prototype.dragStartVerticalSlider = function (event) {
   util.crossBrowserAddEventListener(document,"mousemove",util.createMethodReference(this, "dragSlider"));
   util.crossBrowserAddEventListener(document,"mouseup",util.createMethodReference(this, "dragStopSlider"));
   this.isDragingY = true;
   this.mouseStartPositionY = event.clientY;
   this.sliderStartPositionTop= this.slider.offsetTop ;
}
Scrollbar.prototype.dragStartHorizontalSlider = function (event) {
   util.crossBrowserAddEventListener(document,"mousemove",util.createMethodReference(this, "dragSlider"));
   util.crossBrowserAddEventListener(document,"mouseup",util.createMethodReference(this, "dragStopSlider"));
   this.isDragingX = true;
   this.mouseStartPositionX = event.clientX;
   this.sliderStartPositionLeft= this.slider.offsetLeft ;
}
Scrollbar.prototype.dragStopSlider = function (event){
	this.isDragingY = false;
	this.isDragingX = false;
}
Scrollbar.prototype.dragOutSlider = function (event){
	this.mouseStartPositionY = event.clientY;
	this.sliderStartPositionTop = this.slider.offsetTop ;
	this.mouseStartPositionX = event.clientX;
	this.sliderStartPositionLeft = this.slider.offsetLeft ;
}	

Scrollbar.prototype.dragSlider = function (event) {
if(navigator.appName == "Microsoft Internet Explorer"){
/* this is what the IE workaround is ment to do */
	this.inputField.select();
/* blur is just to ensure that no cursor blink will ever apear */
	this.inputField.blur();
}
	if (this.isDragingX == true){
		position = this.sliderStartPositionLeft +(event.clientX - this.mouseStartPositionX); 	
		if (position < this.sliderMaxOffsetLeft ) position  = this.sliderMaxOffsetLeft ;
	 	if (position + this.slider.offsetWidth > this.sliderMaxOffsetRight) position  = this.sliderMaxOffsetRight - this.slider.offsetWidth ;
		this.slider.style.left = position + "px";
		this.fireScrollEvent();		
	}
	if (this.isDragingY == true){
		position = this.sliderStartPositionTop +(event.clientY - this.mouseStartPositionY); 	
		if (position < this.sliderMaxOffsetTop ) position  = this.sliderMaxOffsetTop ;
	 	if (position + this.slider.offsetHeight > this.sliderMaxOffsetBottom) position  = this.sliderMaxOffsetBottom - this.slider.offsetHeight ;
		this.slider.style.top = position + "px";
		this.fireScrollEvent();		
	}
}
/* check methods to keep the slider within its range*/
Scrollbar.prototype.checkHorizontalSliderPositions = function (){
	position = this.slider.offsetLeft; 	
	if (position < this.sliderMaxOffsetLeft ) position  = this.sliderMaxOffsetLeft;
	if (position + this.slider.offsetWidth > this.sliderMaxOffsetRight) position  = this.sliderMaxOffsetRight - this.slider.offsetWidth ;
	this.slider.style.left = position + "px";
}
Scrollbar.prototype.checkVerticalSliderPositions = function (){
	position = this.slider.offsetTop; 	
	if (position < this.sliderMaxOffsetTop ) position  = this.sliderMaxOffsetTop;
	if (position + this.slider.offsetHeight > this.sliderMaxOffsetBottom) position  = this.sliderMaxOffsetBottom - this.slider.offsetHeight ;
	this.slider.style.top = position + "px";
}
/* TODO : call for prototypes to transmit the Object references, that way params can be passed over
 * and the next 6 Methods will become 2
 */
Scrollbar.prototype.startButtonLeftDrag = function (){
	this.isPressed = true;		
	this.scrollJumpAmmount = -3;
	this.buttonDragHorizontalSlider();	
}
Scrollbar.prototype.startButtonRightDrag = function (){
	this.isPressed = true;		
	this.scrollJumpAmmount = 3;
	this.buttonDragHorizontalSlider();	
}
Scrollbar.prototype.startButtonUpDrag = function (){
	this.isPressed = true;		
	this.scrollJumpAmmount = -3;
	this.buttonDragVerticalSlider();	
}
Scrollbar.prototype.startButtonDownDrag = function (){
	this.isPressed = true;		
	this.scrollJumpAmmount = 3;
	this.buttonDragVerticalSlider();	
}
Scrollbar.prototype.buttonDragHorizontalSlider = function (){
 	if (this.isPressed == true){		
		this.slider.style.left = this.slider.offsetLeft + this.scrollJumpAmmount +"px";
		this.checkHorizontalSliderPositions();
		window.setTimeout(util.createMethodReference(this, 'buttonDragHorizontalSlider'),0);
		this.fireScrollEvent();	
	}
}
Scrollbar.prototype.buttonDragVerticalSlider = function (){
 	if (this.isPressed == true){
		this.slider.style.top = this.slider.offsetTop + this.scrollJumpAmmount +"px";
		this.checkVerticalSliderPositions();
		window.setTimeout(util.createMethodReference(this, 'buttonDragVerticalSlider'),0);
		this.fireScrollEvent();	
	}
}
Scrollbar.prototype.buttonReleased = function (){
	this.isPressed = false;
}
 /**
 * This method adds a ScrollListener which needs to be a function
 * with one parameter of type ScrollEvent. This method will be called,
 * whenever the scrolled value has changed.
 * @see #removeScrollListener(scrollListener)
 */
Scrollbar.prototype.addScrollListener = function (scrollListener) {
	this.scrollListeners.push(scrollListener);
}
/**
 * This method removes a ScrollListener that has been added before.
 * If the given ScrollListener has not been previously added, this method
 * is an expensive noop (it will recreate the listener array in any case).
 */
Scrollbar.prototype.removeScrollListener = function (scrollListener) {
	tmpListeners = this.scrollListeners;
	this.scrollListeners = new Array();
	for (i = 0; i < this.scrollListeners.length; ++i) {
		listener = this.scrollListeners[i];
		if (listener != scrollListener){
			this.scrollListeners.push(scrollListener);
		}	
	}
}
/**
 * This method is called internally, when the scrolled value has changed.
 * TODO: Stop calling it from outside (ex:ScrollPane.layout).
 */
Scrollbar.prototype.fireScrollEvent = function () {
	scrollEvent = new ScrollEvent(this);
	for (i = 0; i < this.scrollListeners.length; ++i) {
		listener = this.scrollListeners[i];
			listener(scrollEvent);
	}
}
Scrollbar.prototype.setVisibility =  function (_boolean){
	if(_boolean == true) this.scrollDiv.style.visibility = "visible";
	if(_boolean == false) this.scrollDiv.style.visibility = "hidden";			
}	
Scrollbar.prototype.getVisibility = function (){
	return this.scrollDiv.style.visibility;			
} 
Scrollbar.prototype.getHeight = function (){
	return this.scrollDiv.offsetHeight;
}
Scrollbar.prototype.getWidth = function (){
	return this.scrollDiv.offsetWidth; 	
}
Scrollbar.prototype.setHeight = function (_height){
	this.scrollDiv.style.height= _height;
	this.sliderPxRange = _height - this.image1.height - this.image2.height ;
}	
Scrollbar.prototype.setWidth = function (_width){
	this.scrollDiv.style.width= _width;
	this.sliderPxRange = _width - this.image1.width - this.image2.width ;
}
Scrollbar.prototype.setTop = function (y){
	this.scrollDiv.style.top= y;
}
Scrollbar.prototype.setLeft = function (x){
	this.scrollDiv.style.left= x;
}
Scrollbar.prototype.getSliderPxRange = function (){
	return this.sliderPxRange;
}
Scrollbar.prototype.getSliderOffsetTop = function (){
	return this.slider.offsetTop;
}
Scrollbar.prototype.getSliderOffsetLeft = function (){
	return this.slider.offsetLeft;
}
Scrollbar.prototype.getImageHeight = function (){
	return this.image1.offsetHeight;
}
Scrollbar.prototype.getImageWidth = function (){
	return this.image1.offsetWidth;
}
Scrollbar.prototype.getScrollDiv = function (){
	return this.scrollDiv;
}
/* this method has to be called externly */
Scrollbar.prototype.resizeSlider = function (elementRange){
	if (this.orientationStr == "vertical"){
		var factor = elementRange / this.scrollDiv.offsetHeight;
		this.slider.style.height = this.sliderPxRange / factor +"px" ;
	} 
	if (this.orientationStr == "horizontal"){
		var factor = elementRange / this.scrollDiv.offsetWidth;
		this.slider.style.width = this.sliderPxRange / factor + "px";
	} 
}
// has to be called after each resize.
Scrollbar.prototype.layout = function (_string){
	if (_string == "vertical") {
		this.image2.style.top = this.scrollDiv.offsetHeight - this.image2.height;
		this.sliderMaxOffsetTop = this.image1.height;
		this.sliderMaxOffsetBottom = this.scrollDiv.offsetHeight - this.image2.height;
	}
	if (_string == "horizontal"){
		this.image2.style.left = this.scrollDiv.offsetWidth - this.image2.width;
		this.sliderMaxOffsetLeft = this.image1.width;
		this.sliderMaxOffsetRight = this.scrollDiv.offsetWidth - this.image2.width;
	}
}
