/*
###################################
#	CRIADO POR: ANDRÉ PONCE		  #
#	http://www.andreponce.com     #
###################################


Modo de uso:

	var scroll 	:ScrollBar = new ScrollBar( bg, drag, bt_c, bt_b );
	
	scroll.startScroll( obj, 400, 400, NaN, "y" );
	
	scroll.easingScroll = .2; //opcional
	scroll.mouseWheel = true; //opcional
	
	addChild(scroll);
	
	scroll.update(); //se você atualizar o tamanho do objeto é so chamar este metodo para atualizar o scroll
	
*/
	
package classes.matuto.ui.scroll 
{
	
	//import br.com.ninja.event.NinjaScrollBarEvent;
	
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.display.Stage;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;
	
	/**
	 * ...
	 * @author André Ponce
	 */
	public class MtScrollBar extends Sprite
	{
		
		private static var rootStage	:Stage;
		
		public var bg			:*;
		public var drag			:*;
		public var arrow_top	:*;
		public var arrow_bottom	:*;
		
		private var bg_container			:Sprite;
		private var drag_container			:Sprite;
		private var arrow_top_container		:Sprite;
		private var arrow_bottom_container	:Sprite;
		
		private var container		:Sprite;
		private var target			:DisplayObject;
		public var rect				:Rectangle;
		
		private var axis			:String;
		private var mouse_axis		:String;
		private var size_axis		:String;
		private var full_size		:Number;
		private var size			:Number;
		private var pos_drag_min	:Number;
		private var pos_drag_max	:Number;
		private var pct				:Number;
		private var drag_size		:Number;
		private var drag_size_m		:Number;
		
		public var delta			:Number = 8;
		public var easingScroll		:Number = .5;
		public var mouseWheel		:Boolean = false;
		public var speed			:Number = 10;
		private var fixed			:Number;
		private var value			:Number;
		
		private var isArrowDown		:Boolean = false;
		private var isDragMove		:Boolean = false;
		private var isDragDown		:Boolean = false;
		private var isUpdatingDrag	:Boolean = false;
		
		public function MtScrollBar( _bg :DisplayObject = null, _drag :DisplayObject = null, _arrow_top :DisplayObject = null, _arrow_bottom :DisplayObject = null ) 
		{
			
			this.bg 			= _bg;
			this.drag			= _drag;
			
			
			
			this.arrow_top		= _arrow_top;
			this.arrow_bottom	= _arrow_bottom;
			
			bg_container 			= new Sprite();
			drag_container 			= new Sprite();
			arrow_top_container		= new Sprite();
			arrow_bottom_container	= new Sprite();
			
			var arr_temp :Array = [bg_container, drag_container, arrow_top_container, arrow_bottom_container];
			
			for (var i :int = 0; i < arr_temp.length; i++ ) {
				
				var part :DisplayObject = arguments[i];
				
				if (part) {
					
					var container :Sprite = arr_temp[i];
					
					container.x = Math.round(part.x);
					container.y = Math.round(part.y);
					
					part.x = part.y = 0;
					
					container.addChild(part);
					
					addChild(container);
					
				}
				
			}
			
			addEventListener(Event.ADDED_TO_STAGE, added_handle);
			
		}
		
		private function startEvents() :void
		{
			bg_container.addEventListener( MouseEvent.MOUSE_DOWN, bg_down_handle );
			drag_container.addEventListener( MouseEvent.MOUSE_DOWN, drag_down_handle );
			arrow_top_container.addEventListener( MouseEvent.MOUSE_DOWN, top_down_handle );
			arrow_bottom_container.addEventListener( MouseEvent.MOUSE_DOWN, bottom_down_handle );
			arrow_top_container.addEventListener( MouseEvent.MOUSE_UP, drag_up_handle );
			arrow_bottom_container.addEventListener( MouseEvent.MOUSE_UP, drag_up_handle );
		}
		
		private function added_handle(e :Event) :void
		{
			
			if (!rootStage) rootStage = stage;
				
			rootStage.addEventListener( MouseEvent.MOUSE_WHEEL, mouse_wheel_handle );
			
			rootStage.addEventListener(Event.RESIZE, onResize);
		}
		
		private function onResize(e:Event):void 
		{
			dispatchEvent(new Event("resize"));
		}
		
		
		public function stopScroll() :void
		{
			
			
			
		}
		
		
		public function startScroll( target :DisplayObject, width :Number = 200, height :Number = 200, fixed :Number = NaN, axis :String = "y" ) :void
		{
			
			if(!container)
			{
				startEvents();
				
				this.target = target;
				
				if (!target[axis]) axis = "y";
				
				this.axis 		= axis;
				this.mouse_axis	= "mouse" + axis.toUpperCase();
				
				if (axis == "y") size_axis = "height";
				else size_axis = "width";
				
				pos_drag_min	= drag_container[axis];
				
				pct			= 0;
				value 		= 0;
				this.fixed	= fixed;
				
				rect = new Rectangle(0, 0, width, height);
				
				var container_name :String = "container_scroll_" + target.name;
				
				var current_container :Sprite = target.parent as Sprite;
				
				if(current_container.name!=container_name)
				{
					
					container = new Sprite();				
					container.name = container_name;
					
					container.x = target.x;
					container.y = target.y;
					
					target.x = target.y = 0;
					
					target.parent.addChildAt(container, target.parent.getChildIndex(target));
					container.addChild(target);
					
					if(container.scrollRect) rect = container.scrollRect;
			
					container.scrollRect = rect;
					
				}else container = current_container;
				
				update();
			}
		}
		
		
		private function mouse_wheel_handle(e :MouseEvent) :void
		{
			
			if(mouseWheel && stage && target) scrollTo(value+((e.delta*delta)*-1));
			
		}
		
		
		private function bg_down_handle(e :MouseEvent) :void
		{
			
			var pct	:Number = ( ( this[mouse_axis] - drag_size ) - ( bg_container[axis]-drag_size_m ) ) / ( bg_container[size_axis] - drag_size);
			
			isDragMove 	= true;
			
			scrollTo( pct*size );
			
		}
		
		
		private function drag_down_handle(e :MouseEvent) :void
		{
			
			isDragDown = true;
			isDragMove = false;
			
			var rect :Rectangle = new Rectangle();
			
			rect.x = drag_container.x;
			rect.y = drag_container.y;
			
			rect[axis] = pos_drag_min;
			
			rect[size_axis] = Math.round( bg_container[size_axis] - drag_size );
			
			drag_container.startDrag( false, rect );
			
			rootStage.addEventListener( MouseEvent.MOUSE_UP, drag_up_handle );
			rootStage.addEventListener( MouseEvent.MOUSE_MOVE, move_handle );
			
		}
		
		
		private function drag_up_handle(e :MouseEvent) :void
		{
			
			isDragDown 	= false;
			isArrowDown	= false;
			
			drag_container.stopDrag();
			
			rootStage.removeEventListener( MouseEvent.MOUSE_UP, drag_up_handle );
			rootStage.removeEventListener( MouseEvent.MOUSE_MOVE, move_handle );
			
		}
		
		
		private function move_handle(e :MouseEvent) :void
		{
			
			scrollTo( (drag_container[axis] - pos_drag_min) / (pos_drag_max - pos_drag_min)*size );
			
			
		}
		
		
		private function top_down_handle(e :MouseEvent) :void
		{
			
			rootStage.addEventListener( MouseEvent.MOUSE_UP, drag_up_handle );
			
			isArrowDown = true;
			
			if(speed>0) speed*=-1;
			
			startRender();
			
		}
		
		
		private function bottom_down_handle(e :MouseEvent) :void
		{
			
			rootStage.addEventListener( MouseEvent.MOUSE_UP, drag_up_handle );
			
			isArrowDown = true;
			
			if(speed<0) speed*=-1;
			
			startRender();
			
		}
		
		
		private function startRender() :void
		{
			
			if(!hasEventListener(Event.ENTER_FRAME)) addEventListener( Event.ENTER_FRAME, render_handle );
			
		}
		
		
		private function stopRender() :void
		{
			
			removeEventListener( Event.ENTER_FRAME, render_handle );
			
		}
		
		
		
		private function render_handle(e :Event) :void
		{
			if(isUpdatingDrag)
			{
				var temp_drag_size :Number = drag[size_axis];
				
				drag[size_axis] += ( drag_size - drag[size_axis] )*easingScroll;
				
				if(drag[size_axis]==temp_drag_size) isUpdatingDrag = false;
				
			}
			
			if( isArrowDown ) scrollTo(value+speed);
			if( isDragMove ) {
				
				var temp_drag_pos	:Number = drag_container[axis];
				
				var pos_drag	:Number = (pos_drag_min+( (bg_container[size_axis] - drag_size) *pct));
				
				//if(pos_drag<pos_drag_min) pos_drag = pos_drag_min;
				//if(pos_drag>pos_drag_max) pos_drag = pos_drag_max;
				
				drag_container[axis] += ( pos_drag - drag_container[axis] ) * easingScroll;
				
				if(drag_container[axis]==temp_drag_pos) isDragMove = false;
				
			}
			
			var current_rect :Number = rect[axis]; 
			
			rect = container.scrollRect;
			
			var _value :Number = ( value - rect[axis] ) * easingScroll;
			
			//if(hasEventListener(NinjaScrollBarEvent.ON_UPDATE_POSITION)) dispatchEvent(new NinjaScrollBarEvent(NinjaScrollBarEvent.ON_UPDATE_POSITION, {axis:axis, value:_value, active:(size>0)}));
			
			rect[axis] += _value;
			
			if( (rect[axis]==current_rect || rect[axis]<.000000001) && !isUpdatingDrag && !isDragMove ) stopRender();
			
			container.scrollRect = rect;
			
		}
		
		
		public function scrollTo( value :Number = 0 ) :void
		{
			
			if (value > size) 	value = size;
			if (value < 0)		value = 0;
			
			pct = value/size;
			
			this.value = value;
			
			if(!isDragDown) isDragMove = true;
			
			startRender();
			
		}
		
		
		public function update(value :Number = NaN, width :Number = NaN, height :Number = NaN) :void
		{
			
			if(rect)
			{
			
				if( !isNaN(width) ) 	rect.width  = width;
				if( !isNaN(height) ) 	rect.height = height;
				
				container.scrollRect = rect;
				
				var bounds :Rectangle =  target.getBounds(target);
				
				full_size 	= bounds[size_axis] + bounds[axis];
				size 		= full_size - rect[size_axis];
				
				if ( !isNaN(fixed) ) drag_size = fixed;
				else{
					
					var _pct :Number = rect[size_axis] / full_size;
					
					drag_size = bg_container[size_axis]*(_pct * .75);
					drag_size = drag_size>bg_container.height ? bg_container.height : drag_size;
					
				}
				
				if(drag_size<10) drag_size = 10;
				
				//if(drag[size_axis]>bg[size_axis]) drag[size_axis] = bg[size_axis]*.75;
				//if(drag[size_axis]<10) drag[size_axis] = 10;
				//drag_size 	= drag[size_axis];
				
				drag_size_m = drag_size*.5;	
				
				pos_drag_max = pos_drag_min + (bg_container[size_axis] - drag_size);
				
				isUpdatingDrag = true;
				
				startRender();
				
				if(isNaN(value)) value = this.value;
				
				scrollTo(value);
				
				if (full_size <= rect[size_axis]) drag_container.mouseEnabled = drag_container.mouseChildren = false;
				else drag_container.mouseEnabled = drag_container.mouseChildren = true;
				
				//if(hasEventListener(NinjaScrollBarEvent.ON_UPDATE)) dispatchEvent(new NinjaScrollBarEvent(NinjaScrollBarEvent.ON_UPDATE, {axis:this.axis, value:value, active:(size>0)}));
				
			}
			
		}
		
	}
	
}