// JavaScript Document
/**
 * This file contains the JavaScript Class for creating a custom scroll bar for content within a DOM tag
 *
 * This file contains a single JavaScript Class that provides the said 
 * functionality. ProjeectMiso scroller was modified to develop this component.
 *
 * Language: JavaScript
 * Depenedancies: MooTools 1.11
 *
 * @package    	pmScroller
 * @author     	ProjectMiso.net <email@projectmiso.net>
 * @version    	2.0
 * @since      	Original: September 2007, Current: August 7, 2009
 * @deprecated 	N/A
 * @license		PhotoBiz's internal use only
*/
/**
 * Features:
 	1. Create a custom scroll bar for HTML content
	2. Scroll vertically or horizontally
	3. For vertical scrolling mouse-wheel is enabled

 * Sample HTML Code:
 
 <div id="scroll_container" class="scrollingImageContainer misoScroller">
	<div class="misoScrollerContent">
		.... HTML contnet ...
	</div>
	<div class="trackBG">
		<div class="up_arrow"></div> <!-- optional -->
		<div class="misoScrollerTrack">
			<div class="misoScrollerBar"></div>
		</div>
		<div class="down_arrow"></div> <!-- optional -->
	</div>
 </div>
 
 * What you need -
 	-- HTML code structure like above - apply your custom styles
	-- apply a CSS class name to the scrolling content container (i.e. misoScrollerContent)
	-- apply a CSS class name to the scrollbar track (i.e. misoScrollerTrack)
	-- apply a CSS class name to the scrollbar (i.e. misoScrollerBar)
	-- now invoke the Class and supply the ID of the main container and the CSS class names you used. The above example used default class names
 
 * Invokation:
	* Short form - 
	
		var Scroller = new pmScroller({ container: "container_ID" });
	* Long form - 
	
		var Scroller = new pmScroller({ 
			container: 			"scroll_container",		//the container ID - REQUIRED
			contentCSS: 		"misoScrollerContent",	//content CSS name  - REQUIRED
			trackContainerCSS:	"misoScrollerTrackContainer",	//The track, scroll bar, arrow container  - REQUIRED
			trackCSS: 			"misoScrollerTrack",	//Track CSS name  - OPTIONAL (required if there is a scroll track and bar)
			barCSS: 			"misoScrollerBar",		//Track Bar CSS name  - OPTIONAL (required if there is a scroll track and bar)
			upArrowCSS: 		"misoScrollerUpArrow",	//Up Arrow CSS name  - OPTIONAL (required if there are scroll arrows)
			downArrowCSS: 		"misoScrollerDownArrow",	//Down Arrow  CSS name  - OPTIONAL (required if there are scroll arrows)
			speed:				5,		//1 to 10. 1 is slow and 10 is the fastest  - OPTIONAL 
			iPhone:				isIphone  //- OPTIONAL 
		});

 * Public Methods:
 *		Class.unload();			//no arguments. this method is for garbage collection - will clear DOM and other objects from 
 *									the memory if called on window.unload
		
**/
	
var pmScroller = new Class({
   	options:{
		//================= Editable Properties/Options
		//-------- WIDGET
		container: 			"",				//the container ID
		type: 				"vertical",		//the main Widget 
		contentCSS: 		null,			//content properties
		trackContainerCSS:	null,			//The track, scroll bar, arrow container
		trackCSS: 			null,			//Track properties
		barCSS: 			null,			//Track Bar properties
		upArrowCSS: 		null,			//Track Bar properties
		downArrowCSS: 		null,			//Track Bar properties
		customBarSize: 		false,
		steps: 				100,			//Steps in bar scrolling
		speed:				5,				//1 to 10. 1 is slow and 10 is fast
		iPhone:				false,			//is the agent iPhone - mousedown, up, over, out, etc. doesn't work
		
		//------ METHODS
		onChange: 			function(){},
		onComplete: 		function(){}
	},
    initialize: function(options){
		var clss = this;
		
		//STEP 1: load the default or supplied options
		this.setOptions(options);				//set options if custom options are being supplied
		this.parseOptions(this.options);		//parse optionsand convert them into class properties
		
		if (this.speed < 1){
			this.speed = 1;	
		} else if (this.speed > 10){
			this.speed = 10;	
		}
		this.speed = 500/this.speed;
		
		//STEP 2: collect the elements and convert them into MooTools DOM objects
		this.container = $(this.container);								//The main widget container
		this.content = this.container.getElement('div[class=' + this.contentCSS + ']');
		if (this.trackContainerCSS) { this.trackContainer = this.container.getElement('div[class=' + this.trackContainerCSS + ']'); }
		if (this.trackCSS) { this.track = this.container.getElement('div[class=' + this.trackCSS + ']'); }
		if (this.barCSS) { this.bar = this.track.getElement('div[class=' + this.barCSS + ']'); }
		if (this.upArrowCSS) { this.upArrow = this.container.getElement('div[class=' + this.upArrowCSS + ']'); }
		if (this.downArrowCSS) { this.downArrow = this.container.getElement('div[class=' + this.downArrowCSS + ']'); }
		
		this.complete = true;
		
		//STEP 3: Call the rendering + initialization functions
		this.render();
		
		//create the timer component
		this.timer = {};
		this.timer.start = function(direction){
			this.active = true;
			//clss.play();
			this.timerID = clss.scroll.periodical(clss.speed, clss, direction);
		};
		this.timer.stop = function(){
			$clear(this.timerID)
			this.active = false;
		};
		
		
		//STEP 4: Handle mouse wheel and keyboard events
		this.container.addEvent('mousewheel', function(event) {
			event = new Event(event); event.stop(); event.stopPropagation()
			//App.roar.alert("Wheel", event.wheel );
			if (event.wheel > 0) { clss.scroll('up'); } 		/* Mousewheel UP */
			else if (event.wheel < 0) { clss.scroll('down'); }	/* Mousewheel DOWN*/
		});
		this.container.addEvent('onkeydown', function(event) {
			event = new Event(event); event.stop(); event.stopPropagation()
			if (key == "up" || (key == "space" && event.shift) || key == "$" || key == "!") { clss.scroll('up'); } 		/* Mousewheel UP */
			else if (key == "down" || key == "space" || key == '"' || key == "#") { clss.scroll('down'); }			/* Mousewheel DOWN*/
		});
		
		//create the arrow event handler
		if (this.upArrow){
			this.upArrow.addEvent('mousedown', function(event) {
				var e = new Event(event); e.stop();
				clss.scroll("up");
				clss.scroll("up");
				clss.timer.start("up");
			});
			if (this.iPhone){
				this.upArrow.addEvent('click', function(event) {
					var e = new Event(event); e.stop();
					clss.scroll("up");
					clss.scroll("up");
				});
			}
			this.upArrow.addEvents({
				'mouseup': function(event) {
					var e  = new Event(event); e.stop();
					//alert(clss.barHoverColor)
					clss.timer.stop();
				},
				'mouseleave': function(event) {
					var e  = new Event(event); e.stop();
					//alert(clss.barHoverColor)
					clss.timer.stop();
				}
			});
		}
		if (this.downArrow){
			this.downArrow.addEvent('mousedown', function(event) {
				var e  = new Event(event); e.stop();
				//alert("sds")
				clss.scroll("down");
				clss.scroll("down");
				clss.timer.start("down");
			});
			if (this.iPhone){
				this.downArrow.addEvent('click', function(event) {
					var e = new Event(event); e.stop();
					clss.scroll("down");
					clss.scroll("down");
				});
			}
			this.downArrow.addEvents({
				'mouseup': function(event) {
					var e  = new Event(event); e.stop();
					//alert(clss.barHoverColor)
					clss.timer.stop();
				},
				'mouseleave': function(event) {
					var e  = new Event(event); e.stop();
					//alert(clss.barHoverColor)
					clss.timer.stop();
				}
			});
		}
		
    },
	parseOptions: function(optionsObj, ignoreUndefinedProps){
		if (!optionsObj){ return; } else {
			for (var optionName in optionsObj){
				if (ignoreUndefinedProps && optionsObj[optionName] == undefined){ continue; } else { this[optionName] = optionsObj[optionName]; }
			}
		}
	},
	render: function(){
		var clss = this;
		
		if (this.bar && this.track){
			//STEP 1: set the height of the track bar
			this.track.height = this.track.getStyle("height").toInt();
			this.track.width = this.track.getStyle("width").toInt();
			this.content.height = this.content.getStyle("height").toInt();
			this.content.width = this.content.getStyle("width").toInt();
			
			//make the track disappear if not enough content
			if (this.content.height >= this.content.scrollHeight){
				this.trackContainer.remove();
			}
			
			//if track 'bar' dimension is not custom - apply default
			//alert(this.container.id + " :: track height :: " + this.track.height + ", customize: " + this.bar.getStyle("height").toInt());
			if (this.track.height > 0 && this.customBarSize == false){
			
				if (this.type == "vertical" && this.bar.getStyle("height").toInt() < 10){ //if height was not specified by CSS
					this.bar.height = this.track.height * (this.content.height / this.content.scrollHeight);
					if (this.bar.height < 10) { this.bar.height == 10; }
					this.bar.setStyle("height", this.bar.height);
					
					if (this.bar.height == 0){
						this.bar.setStyle("display", "none");
					} 
				} else if (this.type =="horizontal"){ //if height was not specified by CSS
					if (this.contentWidth){
						this.bar.width = this.track.width * (this.contentWidth / this.content.scrollWidth);
						if (this.content.scrollWidth < this.contentWidth + 5){ this.bar.width = 0; }
					} else {
						this.bar.width = this.track.width * (this.content.width / this.content.scrollWidth);
						if (this.content.scrollWidth < this.content.width + 5){ this.bar.width = 0; }
						//alert(this.track.width + " * " + this.content.width + " / " + this.content.scrollWidth);
					}
					//alert(this.content.scrollWidth)
					if (this.bar.width == 0){
						this.bar.setStyle("display", "none");
					} 
					
				}
			} 
			if (this.customBarSize) {
				this.bar.height = this.customBarSize;
				this.bar.setStyle("height", this.bar.height);
			}
			
			//STEP 2: create slider - track and bar
			//cerate about content slider - for scrolling
			this.bar.addEvent("mousedown", function(event){
				this.complete = false;
			});
			
			this.slider = new Slider(this.track, this.bar, {	
				steps: this.steps,	
				mode: this.type,	
				wheel: true,
				onChange: function(step){
					clss.onChange();
					clss.complete = false;
					//clss.bar.setStyle("background-color", clss.barHoverColor);
					clss.scroll(undefined, step);
				},
				onComplete: function(){
					//clss.bar.setStyle("background-color", clss.barColor);
					clss.onComplete();
					clss.complete = true;
				}
			}).set(0);
			
			this.track.addEvent("mousedown", function(event){
				new Event(event).stop();
			});
		}
	},
	scroll: function(direction, step){
		var scrollable_height = this.content.scrollHeight - this.content.height;
		var scrollable_width = this.content.scrollWidth - this.content.width;
		
		//alert(this.content.scrollWidth + " " +  this.content.width);
		
		//scrolling with scoll bar
		if (step != undefined){
			if (this.type == "vertical"){
				var srollTo = (scrollable_height / this.steps) * step;
				this.content.scrollTop = srollTo;
			} else {
				var srollTo = (scrollable_width / this.steps) * step;
				this.content.scrollLeft = srollTo;
			}
		} 
		//scolling with mouse wheel and keyboard
		if (direction != undefined){
			if (direction == "up"){
				if (this.type == "vertical"){
					this.content.scrollTop = this.content.scrollTop - 40;
				} else {
					this.content.scrollLeft = this.content.scrollLeft - 40;
				}
			} else {
				if (this.type == "vertical"){
					this.content.scrollTop = this.content.scrollTop + 40;
				} else {
					this.content.scrollLeft = this.content.scrollLeft + 40;
				}
			}
			if (this.type == "vertical"){
				step = this.content.scrollTop / (scrollable_height / this.steps);
			} else {
				step = this.content.scrollLeft / (scrollable_width / this.steps);
			}
			
			if (this.bar && this.track){
				this.slider.set(step);
			}
		}
	}
});
pmScroller.implement(new Options);
