package com.guru.display 
{
	import com.guru.call.FunctionCall;
	import com.guru.call.ICall;
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.MouseEvent;
	
	/**
	 * ...
	 * @author Eddy Lee
	 */
	public class ToggleButton 
	{
		protected static const LABEL_ENABLE:String = "enable";
		protected static const LABEL_DISABLE:String = "disable";
		protected static const LABEL_ON_START:String = "onStart";
		protected static const LABEL_ON_END:String = "onEnd";
		protected static const LABEL_OFF_START:String = "offStart";
		protected static const LABEL_OFF_END:String = "offEnd";
		
		protected static const STATUS_ON:String = "on";
		protected static const STATUS_OFF:String = "off";
		
		protected var mTimeline:MovieClip;
		protected var mStatus:String;
		protected var mIsVisualDisable:Boolean;
		protected var mDisableControl:LabelMovieClip;
		protected var mContentControl:LabelMovieClip;
		
		protected var mPressCalls:Object;
		protected var mOverCalls:Object;
		protected var mOverDoneCalls:Object;
		protected var mOutCalls:Object;
		protected var mOutDoneCalls:Object;
		
		protected var mHitArea:MovieClip;
		protected var mHitDummy:MovieClip;
		
		public function ToggleButton(pTimeline:MovieClip) 
		{
			mTimeline = pTimeline;
			var mc:MovieClip = mTimeline.getChildByName("btn_mc") as MovieClip || mTimeline;
			
			if (mc != mTimeline) 
			{
				mDisableControl = new LabelMovieClip(mTimeline, LABEL_ENABLE);
			}
			
			mContentControl = new LabelMovieClip(mc, LABEL_ON_START);
			
			mHitArea = mc.getChildByName("hitArea_mc") as MovieClip || mTimeline.getChildByName("hitArea_mc") as MovieClip || mTimeline;
			mHitArea.addEventListener(MouseEvent.CLICK, onPress, false, 0, true);
			mHitArea.addEventListener(MouseEvent.ROLL_OVER, onOver, false, 0, true);
			mHitArea.addEventListener(MouseEvent.ROLL_OUT, onOut, false, 0, true);
			mHitArea.buttonMode = true;
			addHitDummy();
			
			mPressCalls = new Object();
			mOverCalls = new Object();
			mOverDoneCalls = new Object();
			mOutCalls = new Object();
			mOutDoneCalls = new Object();
			
			try 
			{
				enabled = (mDisableControl.getTimeline().currentLabel == LABEL_ENABLE);
			}
			catch (e:Error)
			{
				enabled = true;
			}
			visualDisable = true;
			this.setOn();
		}
		
		public function getTimeline():MovieClip 
		{
			return (mDisableControl)? mDisableControl.getTimeline() : getInnerTimeline();
		}
		
		public function getInnerTimeline():MovieClip 
		{
			return mContentControl.getTimeline();
		}
		
		public function get isOn():Boolean 
		{
			return mStatus == STATUS_ON;
		}
		
		public function get enabled():Boolean 
		{
			return mHitArea.mouseEnabled;
		}
		
		public function set enabled(pValue:Boolean):void 
		{
			mHitArea.mouseEnabled = pValue;
			mHitArea.mouseChildren = pValue;
			updateVisualDisable();
		}
		
		public function set visualDisable(pValue:Boolean):void 
		{
			mIsVisualDisable = pValue;
			updateVisualDisable();
		}
		
		public function set useHandCursor(pValue:Boolean):void 
		{
			mHitArea.useHandCursor = pValue;
		}
		
		public function setOnCall(pCall:ICall):void 
		{
			mPressCalls[STATUS_ON] = pCall;
		}
		
		public function setOnOverCall(pCall:ICall):void 
		{
			mOverCalls[STATUS_ON] = pCall;
		}
		
		public function setOnOverDoneCall(pCall:ICall):void 
		{
			mOverDoneCalls[STATUS_ON] = pCall;
		}
		
		public function setOnOutCall(pCall:ICall):void 
		{
			mOutCalls[STATUS_ON] = pCall;
		}
		
		public function setOnOutDoneCall(pCall:ICall):void 
		{
			mOutDoneCalls[STATUS_ON] = pCall;
		}
		
		public function setOffCall(pCall:ICall):void 
		{
			mPressCalls[STATUS_OFF] = pCall;
		}
		
		public function setOffOverCall(pCall:ICall):void 
		{
			mOverCalls[STATUS_OFF] = pCall;
		}
		
		public function setOffOverDoneCall(pCall:ICall):void 
		{
			mOverDoneCalls[STATUS_OFF] = pCall;
		}
		
		public function setOffOutCall(pCall:ICall):void 
		{
			mOutCalls[STATUS_OFF] = pCall;
		}
		
		public function setOffOutDoneCall(pCall:ICall):void 
		{
			mOutDoneCalls[STATUS_OFF] = pCall;
		}
		
		public function setOn():void 
		{
			mStatus = STATUS_ON;
			jumpToNormal();
		}
		
		public function setOff():void 
		{
			mStatus = STATUS_OFF;
			jumpToNormal();
		}
		
		public function switchOn():void 
		{
			mStatus = STATUS_ON;
			jumpToNormal(mPressCalls[mStatus]);
		}
		
		public function switchOff():void 
		{
			mStatus = STATUS_OFF;
			jumpToNormal(mPressCalls[mStatus]);
		}
		
		public function reset():void 
		{
			enabled = true;
			playToNormal();
		}
		
		public function onPress(pEvent:MouseEvent = null):void 
		{
			if (enabled) 
			{
				if (isOn) 
				{
					switchOff();
				}
				else 
				{
					switchOn();
				}
			}
		}
		
		public function onOver(pEvent:MouseEvent = null):void 
		{
			if (enabled) 
			{
				playToOver(mOverDoneCalls[mStatus]);
				try 
				{
					ICall(mOverCalls[mStatus]).execute();
				} catch (e:Error) { }
			}
		}
		
		public function onOut(pEvent:MouseEvent = null):void 
		{
			if (enabled) 
			{
				playToNormal(mOutDoneCalls[mStatus]);
				try 
				{
					ICall(mOutCalls[mStatus]).execute();
				} catch (e:Error) { }
			}
		}
		
		public function dispose():void 
		{
			removeHitDummy();
			mHitArea.buttonMode = false;
			mHitArea.removeEventListener(MouseEvent.MOUSE_DOWN, onPress);
			mHitArea.removeEventListener(MouseEvent.ROLL_OUT, onOut);
			mHitArea.removeEventListener(MouseEvent.ROLL_OVER, onOver);
			mHitArea = null;
			mTimeline = null;
			
			try 
			{
				mDisableControl.dispose();
			} catch (e:Error) { }
			mDisableControl = null;
			mContentControl.dispose();
			mContentControl = null;
			
			var statuses:Array = [STATUS_ON, STATUS_OFF];
			for each (var item:String in statuses) 
			{
				delete mPressCalls[item];
				delete mOverCalls[item];
				delete mOverDoneCalls[item];
				delete mOutCalls[item];
				delete mOutDoneCalls[item];
			}
			mPressCalls = null;
			mOverCalls = null;
			mOverDoneCalls = null;
			mOutCalls = null;
			mOutDoneCalls = null;
		}
		
		protected function updateVisualDisable():void 
		{
			try 
			{
				mDisableControl.playTo((mIsVisualDisable && !enabled)? LABEL_DISABLE : LABEL_ENABLE);
			} catch (e:Error) { }
		}
		
		protected function jumpToNormal(pCall:ICall = null):void 
		{
			mContentControl.jumpTo((isOn)? LABEL_ON_START : LABEL_OFF_START, pCall);
		}
		
		protected function playToNormal(pCall:ICall = null):void 
		{
			mContentControl.playTo((isOn)? LABEL_ON_START : LABEL_OFF_START, pCall);
		}
		
		protected function playToOver(pCall:ICall = null):void 
		{
			mContentControl.playTo((isOn)? LABEL_ON_END : LABEL_OFF_END, pCall);
		}
		
		protected function addHitDummy():void 
		{
			if (mHitArea.stage) 
			{
				mHitArea.addEventListener(Event.ENTER_FRAME, removeHitDummy, false, 0, true);
				mHitDummy = new mHitArea.constructor();
				mHitDummy.transform.matrix = mHitArea.transform.matrix;
				mHitDummy.alpha = 0;
				mHitArea.parent.addChild(mHitDummy);
			}
		}
		
		protected function removeHitDummy(pEvent:Event = null):void 
		{
			try 
			{
				mHitArea.removeEventListener(Event.ENTER_FRAME, removeHitDummy);
				mHitDummy.parent.removeChild(mHitDummy);
				mHitDummy = null;
			} catch (e:Error) { }
		}
	}
	
}