/**
* A scrollable layer with a custom scrollbar - with all the bells and whistles of the standard browser scrollbar. 
* 
* Scrollable Div class as shown here: http://www.blueshoes.org/en/javascript/scrollablediv/
* 
* 
* dependencies: 
* <code>
* 	<script type="text/javascript" src="/_bsJavascript/lib/LibCrossBrowser.js"></script>
* 	<script type="text/javascript" src="/_bsJavascript/lib/EventHandler.js"></script>
* 	<script type="text/javascript" src="/_bsJavascript/core/form/Bs_FormUtil.lib.js"></script>
* 	<script type="text/javascript" src="/_bsJavascript/components/slider/Bs_Slider.class.js"></script>
* </code>
* 
* @status    experimental
* @since     bs-4.6
* @author    andrej arn
* @copyright blueshoes.org
*/
function Bs_ScrollableDiv() {
	this.sliderObj;
	this.bwCheckObj;
	this.lastScrollTo = 0;
	this.containerObj;
	this.contentObj;
	this.containerElm;
	this.contentElm;
	this.sliderDivId;
	
	/**
	* @access ?
	* @var    bool isActive
	*/
	this.isActive = false;
	
	
	/**
	* @access public
	* @param  string containerDivId
	* @param  string contentDivId
	* @return void
	*/
	this.init = function(containerDivId, contentDivId) {
		this.bwCheckObj = lib_bwcheck();
		
		this.containerObj = new makeObj(this.bwCheckObj, containerDivId);
		this.contentObj   = new makeObj(this.bwCheckObj, contentDivId, containerDivId);
		this.contentObj.moveIt(0, 0);
		this.containerObj.css.visibility = "visible";
		this.containerElm = document.getElementById(containerDivId);
		this.contentElm   = document.getElementById(contentDivId);
		if (this.contentElm.attachEvent) { //ie only
			this.contentElm.Bs_ScrollableDiv = this;
			this.contentElm.attachEvent('onmousewheel', Bs_ScrollableDiv_onMouseWheel);
		}
	}
	
	/**
	* uses the given slider component as scrollbar.
	* 
	* in your slider object, set 'height' to 'auto'. the slider will then have the height 
	* of your div.
	* 
	* also it is a good idea to set 'maxVal' to 'auto'. it will then have the height of 
	* the scrollable (hidden) space. this automatically adjusts the speed of sliding.
	* 
	* @access public
	* @param  object sliderObj (an instance of Bs_Slider.)
	* @param  string sliderDivId (the id of the div tag to use as container for the slider.)
	* @return void
	*/
	this.setSliderObject = function(sliderObj, sliderDivId) {
		sliderObj.useInputField = 0;
		sliderObj.attachOnChange(Bs_ScrollableDiv_sliderChange);
		this.sliderObj = sliderObj;
		if (this.sliderObj.height == 'auto') {
			this.sliderObj.height = this.containerElm.offsetHeight - (this.sliderObj._arrowIconLeftHeight + this.sliderObj._arrowIconRightHeight);
		}
		if (this.sliderObj.width == 'auto') {
			this.sliderObj.width = this.containerElm.offsetWidth - (this.sliderObj._arrowIconLeftWidth + this.sliderObj._arrowIconRightWidth);
		}
		this.sliderObj.Bs_ScrollableDiv = this;
		this.sliderDivId = sliderDivId;
		this.updateScrollableSpace();
	}
	
	/**
	* @access public
	* @param int amount
	* @param string unit (currently only 'pixel' supported.)
	* @return void
	*/
	this.setSlideSpeed = function(amount, unit) {
		this.sliderObj.valueInterval  = 0.1;
		this.sliderObj.arrowAmount    = amount * this.sliderObj.arrowKeepFiringTimeout /1000;
		this.sliderObj.minVal         = 0;
		
		if (this.sliderObj.direction == 0) {
			this.sliderObj.maxVal         = this.contentElm.scrollWidth - this.containerElm.offsetWidth;
		} else {
			this.sliderObj.maxVal         = this.contentElm.scrollHeight - this.containerElm.offsetHeight;
		}
		
		if (this.sliderObj.valueDefault > 0) {
			this.sliderObj.valueDefault = this.sliderObj.maxVal / 100 * this.sliderObj.valueDefault;
		}
		this.updateScrollableSpace(); //cheap hack.
	}
	
	/**
	* @access public
	* @param int amount
	* @param string unit (currently only 'pixel' supported.)
	* @return void
	*/
	this.setWheelSpeed = function(amount, unit) {
		this.sliderObj.wheelAmount    = amount;
	}
	
	/**
	* when the content div changes its content, this method needs to be called 
	* so we can update the slider object. because the height (width) of the content 
	* in the div may have changed. 
	* @access public
	* @return void
	*/
	this.updateScrollableSpace = function() {
		if (this.sliderObj.direction == 0) {
			var scrollableSpace = this.contentElm.offsetWidth - this.containerElm.offsetWidth;
		} else {
			var scrollableSpace = this.contentElm.offsetHeight - this.containerElm.offsetHeight;
		}
		
		if (this.sliderObj.maxVal == 'auto') {
			this.sliderObj.maxVal = scrollableSpace;
		}
		
		if (scrollableSpace > 0) {
			this.isActive = true;
			this.sliderObj.drawInto(this.sliderDivId);
			if (this.sliderObj.valueDefault != this.sliderObj.minVal) {
				this.bsSliderChange(this.sliderObj.valueDefault);
			}
		} else {
			this.isActive = false;
			//this.sliderObj.hide(); //todo
		}
	}
	
	
	/**
	* @access private (used internally)
	* @return void
	*/
	this.onMouseWheel = function() {
		this.sliderObj.onMouseWheel();
	}
	
	
	/**
	* registered callback function. you don't need it.
	* fires when the slider value changes, to slide the div.
	* 
	* @access public (you don't need it)
	* @param  int val (could be string, at least it's numeric)
	* @param  int newPos (could be string, at least it's numeric)
	* @return void
	*/
	this.bsSliderChange = function(val, newPos) {
		var percent = val * 100 / (this.sliderObj.maxVal - this.sliderObj.minVal);
		/*
		if (moz) {
			var scrollableSpace = this.contentElm.offsetHeight;
		} else { //ie and opera work the same way
			var scrollableSpace = Math.abs(parseInt(this.contentElm.style.top)) + this.containerElm.scrollHeight;
		}
		*/
		if (this.sliderObj.direction == 0) {
			var scrollableSpace = this.contentElm.offsetWidth  - this.containerElm.offsetWidth;
		} else {
			var scrollableSpace = this.contentElm.offsetHeight - this.containerElm.offsetHeight;
		}
		
		//alert(this.containerElm.scrollHeight); //342  130    190
		//alert(this.containerElm.offsetHeight); //131  130
		//alert(scrollableSpace);
		
		var scrollTo = parseInt(scrollableSpace * percent  / 100);
		
		if (scrollTo != this.lastScrollTo) {
			if (this.sliderObj.direction == 0) {
				this.contentObj.moveIt(-scrollTo, 0);
			} else {
				this.contentObj.moveIt(0, -scrollTo);
			}
			this.lastScrollTo = scrollTo;
		}
	}
	
}



function Bs_ScrollableDiv_onMouseWheel() {
	var obj   = window.event.srcElement;
	
	var gotIt = false;
	while (true) {
		if (typeof(obj.Bs_ScrollableDiv) != 'undefined') {
			gotIt = true;
			break;
		}
		if (typeof(obj.parentNode) == 'undefined') break;
		obj = obj.parentNode;
	}
	if (gotIt && obj.Bs_ScrollableDiv.isActive) {
		obj.Bs_ScrollableDiv.onMouseWheel();
		return false;
	} else {
		return true;
	}
}


function lib_bwcheck() { //Browsercheck (needed)
	//it's ok to not chedk for ie7 etc here. it does not matter, as long as long as dom is available.
	this.ver=navigator.appVersion;
	this.agent=navigator.userAgent;
	this.dom=(document.getElementById) ? 1 : 0;
	this.opera5=(navigator.userAgent.indexOf("Opera")>-1 && document.getElementById)?1:0;
	this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0; 
	this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0;
	this.ie4=(document.all && !this.dom && !this.opera5)?1:0;
	this.ie=this.ie4||this.ie5||this.ie6;
	this.mac=this.agent.indexOf("Mac")>-1;
	this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0; 
	this.ns4=(document.layers && !this.dom)?1:0;
	this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5);
	bs_px_char = (this.ns4 || window.opera) ? "" : "px"; // A unit of measure that will be added when setting the position of a layer.
	return this;
}

function Bs_ScrollableDiv_moveIt(x,y) {
	this.x = x;
	this.y = y;
	this.css.left = this.x + bs_px_char;
	this.css.top  = this.y + bs_px_char;
}


/**
* registered callback function for the slider.
* @param object sliderObj
* @param int val (the value)
*/
function Bs_ScrollableDiv_sliderChange(sliderObj, val, newPos){ 
	sliderObj.Bs_ScrollableDiv.bsSliderChange(val, newPos);
}


function makeObj(bwCheckObj, obj, nest){
	nest=(!nest) ? "":'document.'+nest+'.';
	this.el=bwCheckObj.dom?document.getElementById(obj):bwCheckObj.ie4?document.all[obj]:bwCheckObj.ns4?eval(nest+'document.'+obj):0;
	this.css= (bwCheckObj.dom) ? document.getElementById(obj).style : (bwCheckObj.ie4) ? document.all[obj].style : (bwCheckObj.ns4) ? eval(nest+'document.'+obj) : 0;
	this.scrollHeight=bwCheckObj.ns4?this.css.document.height:this.el.offsetHeight;
	this.clipHeight=bwCheckObj.ns4?this.css.clip.height:this.el.offsetHeight;
	this.moveIt=Bs_ScrollableDiv_moveIt;
	this.x=0;
	this.y=0;
	this.obj = obj + "Object";
	eval(this.obj + "=this");
	return this;
}
