package 
{
	import adobe.utils.CustomActions;
	import flash.display.DisplayObject;
	import flash.display.MovieClip;
	import flash.display.Stage;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.filters.DropShadowFilter;
	import flash.filters.GlowFilter;
	import flash.geom.ColorTransform;
	import flash.geom.Rectangle;
	import flash.text.TextFormat;
	import flash.text.TextField;
	import flash.utils.Timer;
	import caurina.transitions.Tweener;
	import caurina.transitions.properties.ColorShortcuts;
	import flash.ui.Mouse;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormatAlign;
	
	/**
	 * ...
	 * @author Paul-André Belle-Isle : Flashbros
	 */
	public class ToolTip extends MovieClip 
	{
		//Not used
		static var allToolTip:Array = new Array();
		
		private var allOptions:Object;
		private var myText:String;
		private var myMC:Object;
		private var toolTip:MyToolTip;
		
		public function ToolTip(_myText:String, _allOptions:Object) {
			
			allOptions = new Object();
			allOptions = _allOptions;
			
			//Create options so it's open show
			allOptions.delay = 0;
			allOptions.removeDelay = 99999999;
			allOptions.alwaysShow = true;
			
			myText = _myText;
			
			
		}
		
		public function Show(_myMC:Object) {
			
			Tweener.removeTweens(toolTip);
			UnloadToolTip();
			
			myMC = _myMC;
			toolTip = AddToolTip(myMC, myText, allOptions);
		}

		private function UnloadToolTip() {
			
			//Try to remove the toolTip if it's here
			try {
				if (allOptions.addTo != undefined) {
					allOptions.addTo.stage.removeChild(toolTip);
				} else {
					myMC.stage.removeChild(toolTip);
				}
			}
			catch (error:*) { };
		}
		
		public function Hide() {	
			
			Tweener.removeTweens(toolTip);
			Tweener.addTween(toolTip,{time:allOptions.tweenTime/2,alpha:0,onComplete:UnloadToolTip});
		}
		
		
		public static function AddToolTip(myMC:Object,myText:String,allOptions:Object = null):MyToolTip {
			
			var useStage:Stage = allOptions.addTo != undefined ? allOptions.addTo.stage : myMC.stage;
			
			allOptions = CreateToolTipOptions(allOptions);
			
			//Creating the timer for the delay
			var myTimer:Timer = new Timer(allOptions.delay, 0);
			var myRemoveTimer:Timer = new Timer(allOptions.removeDelay, 0);
			
			//Positionning
			var correctPosition:String = allOptions.position;
			var currentPositionIndex:Number = 0;
			
			//Create toolTips
			var myToolTip:MyToolTip;
			
			var myTextFormat:TextFormat;
			
			var tweenIndex:Number;
			
			var maxRecursive:Number = 0;
			var currentRecursive:Number = 0;
			
			if (allOptions.position.indexOf("T", 0) != -1) {
				maxRecursive = 3;
			} else {
				maxRecursive = 2;
			}
			
			//Adding listener to timer
			myTimer.addEventListener(TimerEvent.TIMER, ShowToolTip);
			myRemoveTimer.addEventListener(TimerEvent.TIMER, RemoveToolTip);
			
			function ShowToolTip(e:TimerEvent = null):void {
				
				myToolTip = new MyToolTip();
				
				
				if (!allOptions.showTip) {
					myToolTip.back_mc.removeChild(myToolTip.back_mc.arrow_mc);
					//myToolTip.back_mc.arrow_mc.visible = false;
				}
				
				if (!allOptions.showMouse && allOptions.followMouse) {
					Mouse.hide();
				}
				
				//Always stop the timer
				myTimer.stop();
				
				//Set alpha to 0
				myToolTip.alpha = 0;
				
				//Code that create a new textField 
				//New hack to create 2 new TextField for glow and normal because defaultTextFormat isn't working with htmlText (known bug from flash)
				var myTextFormat:TextFormat = myToolTip.text_txt.getTextFormat();
				myTextFormat.color = allOptions.textColor;
				myTextFormat.align = allOptions.textAlign;

				
				var defaultText:TextField = new TextField();
				defaultText.width = 1;
				defaultText.height = myToolTip.text_txt.height;
				
				defaultText.embedFonts = myToolTip.text_txt.embedFonts;
				defaultText.multiline = true;
				
				defaultText.antiAliasType = "advanced";
				defaultText.gridFitType = "pixel";
				defaultText.defaultTextFormat = myTextFormat;
				
				defaultText.name = "text_txt";
				
				myToolTip.removeChild(myToolTip.text_txt);
				myToolTip.addChild(defaultText);
				myToolTip.text_txt = myToolTip.getChildByName("text_txt") as TextField;
				
				
				//Set autoSize
				myToolTip.text_txt.autoSize = TextFieldAutoSize[allOptions.textAlign.toUpperCase()];
				
				//Set the good Text
				//myToolTip.text_txt.setTextFormat(myTextFormat);
				myToolTip.text_txt.htmlText = myText;
				
				myToolTip.text_txt.multiline = true;
				myToolTip.text_txt.wordWrap = false;
				
				if(allOptions.width != 0) {
					myToolTip.text_txt.wordWrap = true;
					myToolTip.text_txt.width = allOptions.width;
				}
				
				myToolTip.text_txt.selectable = false;

				
				//text position
				myToolTip.text_txt.x = allOptions.horizontalMargin;
				myToolTip.text_txt.y = allOptions.verticalMargin;
				
				//Set the goodColor for the arrow
				var myColorTransform:ColorTransform = new ColorTransform();
				myColorTransform.color = allOptions.backColor;
				myToolTip.back_mc.arrow_mc.transform.colorTransform = myColorTransform;
				
				//Create the back for the toolTip
				var backTT:MovieClip = new MovieClip();
				backTT.name = "back_mc";
				backTT.graphics.beginFill(allOptions.backColor, 1);
				backTT.graphics.drawRoundRect(0,0,Math.round(myToolTip.text_txt.width + allOptions.horizontalMargin*2),Math.round(myToolTip.text_txt.height + allOptions.verticalMargin*2),allOptions.roundCorner);
				myToolTip.back_mc.addChild(backTT);
				
				//Create it back for the mask
				var backMask:MovieClip = new MovieClip();
				backMask.graphics.beginFill(allOptions.backColor, 1);
				backMask.graphics.drawRoundRect(0,0,Math.round(myToolTip.text_txt.width + allOptions.horizontalMargin*2),Math.round(myToolTip.text_txt.height + allOptions.verticalMargin*2),allOptions.roundCorner);
				myToolTip.mask_mc.addChild(backMask);
				
				//Set the mask
				myToolTip.mask_mc.x = 0;
				myToolTip.mask_mc.y = 0;
				myToolTip.over_mc.mask = myToolTip.mask_mc;
				
				//Set back alpha
				myToolTip.back_mc.alpha = allOptions.alpha;
				myToolTip.over_mc.alpha = allOptions.alpha;
				
				
				PlaceToolTip(null, null, true);
				
				
				
				//Create the Border and shadow
				var borderFilter:GlowFilter = new GlowFilter();
				borderFilter.color = allOptions.borderColor;
				borderFilter.blurX = allOptions.borderWidth;
				borderFilter.blurY = allOptions.borderWidth;
				borderFilter.strength = 2*allOptions.borderWidth;
				borderFilter.quality = 2;
				borderFilter.alpha = allOptions.borderAlpha;
				
				var shadowFilter:DropShadowFilter = new DropShadowFilter(0, 0, 0x000000, .8, 4, 4, .5, 1);
				
				myToolTip.back_mc.filters = new Array(borderFilter, shadowFilter);
				
				//Adding a fake Filter to toolTip so it work with not embed font
				var fakeFilter:GlowFilter = new GlowFilter(0,0,0,0,0,0);
				myToolTip.filters = new Array(fakeFilter);
				
				
				useStage.addChild(myToolTip);
				
				//Set the alpha animation
				Tweener.addTween(myToolTip, { time:allOptions.tweenTime, alpha:1 } );
				
				
				//If followMouse
				if (allOptions.followMouse) {
					if (allOptions.addTo != undefined) {
						allOptions.addTo.addEventListener(Event.ENTER_FRAME, PlaceToolTip);
					} else {
						myMC.addEventListener(Event.ENTER_FRAME, PlaceToolTip);
					}
				}
				
				
				//myToolTip.mouseChildren = false;
				//myToolTip.mouseEnabled = false;
			}
			
			
			function PlaceToolTip(e:Event = null, newPosition:String = null,firstTime:Boolean = false) {
				
				var xPos:Number = 0;
				var yPos:Number = 0;
				
				var useAutoFit:Boolean = allOptions.autoFit;
				
				//If it's the enterFrame, we reset to the default the position
				if (e != null) {
					correctPosition = allOptions.position;
					currentRecursive = 0;
				}
				
				currentRecursive++;
				
				//If it's recursive, overwrite it.
				if (newPosition != null) {
					correctPosition = newPosition;
				}
				
			

				
				
				var backTT:MovieClip = myToolTip.back_mc.getChildByName("back_mc") as MovieClip;
				var mcRect:Rectangle;
				
				//CHECK UP to see where the toolTip enter if followMouse
				if (allOptions.followMouse) {
					
					
					
					var useX:Number = useStage.mouseX;
					var useY:Number = useStage.mouseY;
					var useWidth:Number = 1;
					var useHeight:Number = 1;
					
					if (allOptions.followAxis.indexOf("x", 0) == -1) {
						useX = myMC.getBounds(useStage).x;
						useWidth = myMC.getBounds(useStage).width;
					}
					
					if (allOptions.followAxis.indexOf("y", 0) == -1) {
						useY = myMC.getBounds(useStage).y;
						useHeight = myMC.getBounds(useStage).height;
					}
					
					mcRect = new Rectangle(useX, useY, useWidth, useHeight);		
				} else {
					mcRect = myMC.getBounds(useStage);
				}
				
				//TOP
				if (correctPosition.indexOf("T", 0) != -1) {
					
					myToolTip.back_mc.arrow_mc.rotation = 0;
					myToolTip.back_mc.arrow_mc.x = Math.round(backTT.width / 2);
					myToolTip.back_mc.arrow_mc.y = Math.round(backTT.height + myToolTip.back_mc.arrow_mc.height / 2);
					
					xPos = Math.round(mcRect.x + mcRect.width / 2 - backTT.width / 2);
					yPos = Math.round(mcRect.y - myToolTip.back_mc.height) - allOptions.spacing;
				}
				
				//BOTTOM
				if (correctPosition.indexOf("B", 0) != -1) {
					
					myToolTip.back_mc.arrow_mc.rotation = 180;
					myToolTip.back_mc.arrow_mc.x = Math.round(backTT.width / 2);
					myToolTip.back_mc.arrow_mc.y = -Math.round((myToolTip.back_mc.arrow_mc.height / 2));
					
					xPos = Math.round(mcRect.x + mcRect.width/2 - backTT.width/2);
					yPos = Math.round(mcRect.y + mcRect.height + myToolTip.back_mc.arrow_mc.height) + allOptions.spacing;
				}
				
				//ONLY LEFT
				if (correctPosition.indexOf("L", 0) != -1 && correctPosition.indexOf("L", 1) == -1) {
					
					myToolTip.back_mc.arrow_mc.rotation = -90;
					myToolTip.back_mc.arrow_mc.x = Math.round(backTT.width + myToolTip.back_mc.arrow_mc.width / 2);
					myToolTip.back_mc.arrow_mc.y = Math.round(backTT.height / 2);
					
					xPos = Math.round(mcRect.x - myToolTip.back_mc.width) - allOptions.spacing;
					yPos = Math.round(mcRect.y + mcRect.height / 2 - myToolTip.back_mc.height/2);
					
				}
				
				//ONLY RIGHT
				if (correctPosition.indexOf("R", 0) != -1 && correctPosition.indexOf("R", 1) == -1) {
					
					myToolTip.back_mc.arrow_mc.rotation = 90;
					myToolTip.back_mc.arrow_mc.x = -(Math.round(myToolTip.back_mc.arrow_mc.width / 2));
					myToolTip.back_mc.arrow_mc.y = Math.round(backTT.height / 2);
					
					xPos = Math.round(mcRect.x + mcRect.width + myToolTip.back_mc.arrow_mc.width) + allOptions.spacing;
					yPos = Math.round(mcRect.y + mcRect.height / 2 - myToolTip.back_mc.height/2);
				}
				
				//LEFT BUT NOT ONLY LEFT
				if (correctPosition.indexOf("L", 1) != -1) {
					
					myToolTip.back_mc.arrow_mc.x = Math.round(backTT.width - myToolTip.back_mc.arrow_mc.width / 2 - allOptions.roundCorner / 2);
					
					xPos = Math.round(mcRect.x + mcRect.width/2 - backTT.width + (myToolTip.back_mc.width - myToolTip.back_mc.arrow_mc.x));
					
				}
				
		
				//RIGHT BUT NOT ONLY RIGHT
				if (correctPosition.indexOf("R", 1) != -1) {
					myToolTip.back_mc.arrow_mc.x = Math.round(allOptions.roundCorner / 2 + myToolTip.back_mc.arrow_mc.width / 2);
					
					xPos = Math.round(mcRect.x + mcRect.width/2 - (myToolTip.back_mc.arrow_mc.x));
				}
				
				//LITTLE FIX : ALWAYS PUT MORE DOWN WHEN IT BOTTOM AND FOLLOW MOUSE
				if (correctPosition.indexOf("B", 0) != -1 && allOptions.followMouse) {
					yPos += 15;
				}
				
				
				
				
				//Check up to be sure the toolTip stay in the Stage
				//TODO : CHECK IF WE CHANGE THE CORRECT POSITION
				var newPosition:String = "";
				var toolTipRect:Rectangle = myToolTip.getBounds(myToolTip.stage);
				
				if (currentRecursive < maxRecursive) {
					
					if (yPos < 0) {
						if(!useAutoFit) {
							yPos = 0;
						} else {
							
							if (correctPosition.indexOf("L", 0) != -1) {
								newPosition = "BL";
							} else {
								newPosition = "BR";
							}

						}
					}
					
					if (xPos < 0) {
						
						if(!useAutoFit) {
							xPos = 0;
						} else {
							
							if (correctPosition.indexOf("T", 0) != -1) {
								newPosition = "TR";
							} else {
								newPosition = "BR";
							}
							
						}
					}
					
					
					if (xPos + backTT.width > useStage.stageWidth) {
						if (!useAutoFit) {
							xPos = useStage.stageWidth - backTT.width;
						} else {
							
							if (correctPosition.indexOf("B", 0) != -1) {
								newPosition = "BL";

							} else {
								newPosition = "TL";
							}

							
						}
					}
					
					if (yPos + backTT.height > useStage.stageHeight) {
						
						if(!useAutoFit) {
							yPos = useStage.stageHeight - backTT.height;
						} else {
							
							if (xPos + backTT.width > useStage.stageWidth) {
							
								newPosition = "TL";
								
							} else {
								if (correctPosition.indexOf("L", 0) != -1) {
									newPosition = "TL";
								} else {
									newPosition = "TR";
								}
							}
							
						}
					}
				}
				////////////////////////////////////////////////////
				
				
				if (newPosition != "") {
					PlaceToolTip(null, newPosition,firstTime);
					return;
				}
				
				
				
				if(firstTime) {
					myToolTip.x = xPos;
					myToolTip.y = yPos;
				} else {
				
					Tweener.addTween(myToolTip, { time:.15, x:xPos, y:yPos,onUpdate:RoundValue,transition:"easeOutSine" } );
				}
				
				//Need to round the value if not, problem with the arrow
				function RoundValue() {
					myToolTip.x = Math.round(myToolTip.x);
					myToolTip.y = Math.round(myToolTip.y);
				}
				
				//Set the arrow in the mask same place
				myToolTip.mask_mc.arrow_mc.x = myToolTip.back_mc.arrow_mc.x;
				myToolTip.mask_mc.arrow_mc.y = myToolTip.back_mc.arrow_mc.y;
				myToolTip.mask_mc.arrow_mc.rotation = myToolTip.back_mc.arrow_mc.rotation;
				
				//Set the over (gradient and highlight) to go into the arrow
				var overRect:Rectangle = myToolTip.back_mc.getBounds(myToolTip);
				
				myToolTip.over_mc.x = overRect.x;
				myToolTip.over_mc.shadow_mc.width = overRect.width;
				myToolTip.over_mc.reflect_mc.width = overRect.width;
				myToolTip.over_mc.y = overRect.y;
				myToolTip.over_mc.shadow_mc.height = overRect.height;
				myToolTip.over_mc.reflect_mc.height = (backTT.height) / 2;
				
				if (correctPosition.indexOf("B",0) != -1) {
					myToolTip.over_mc.reflect_mc.height += myToolTip.back_mc.arrow_mc.height;
				}
				
				myToolTip.over_mc.reflect_mc.alpha = allOptions.highLight;
				myToolTip.over_mc.shadow_mc.alpha = allOptions.gradient;
				
				return;
					
			}
			
			function CheckRemoveToolTip(e:MouseEvent) {
					
				myRemoveTimer.start();
				//RemoveToolTip();
			}
			
			function RemoveToolTip(e:TimerEvent = null) {
				
				//Check if stay on mouseOver
				if (allOptions.stayOnMouseOver) {
					if (myToolTip.hitTestPoint(myToolTip.stage.mouseX, myToolTip.stage.mouseY, true)) {
						myRemoveTimer.stop();
						myRemoveTimer.start();
						return;
					}
				}
				
				//Check if it's still inside
				if (myMC.hitTestPoint(useStage.mouseX, useStage.mouseY, true)) {
					return;
				}
				
				//In case it was not fired up, we stop it
				myTimer.stop();
				myRemoveTimer.stop();
				
				Mouse.show();
				
				//Removing the ENTERFRAME listener in a try ;)
				try { myMC.removeEventListener(Event.ENTER_FRAME, PlaceToolTip); } catch (error:*) { };
				
				//Set the alpha animation
				function UnloadToolTip() {
					//Try to remove the toolTip if it's here
					try {
						useStage.removeChild(myToolTip);
					}
					catch (error:*) { };
				}
				
				Tweener.removeTweens(myToolTip);
				
				Tweener.addTween(myToolTip,{time:allOptions.tweenTime/2,alpha:0,onComplete:UnloadToolTip});
			}
			
			
			//When mouseOver, show toolTips
			function MouseOver(e:MouseEvent) {
				
			
				//If the removeTimer is running.. then just stop here
				if (myRemoveTimer.running) {
					myTimer.stop();
					myRemoveTimer.stop();
					return;
				}
				
				//Stop the timer.. in case off
				myTimer.stop();
				myRemoveTimer.stop();
				
				//Stopping the tweener
				Tweener.removeTweens(myToolTip);
				
				
				//Try to remove the toolTip in case it still here
				try { useStage.removeChild(myToolTip); } catch (error:*) { };
				
				//Start the timer
				myTimer.start();
				
			}
			
			
			if (allOptions.alwaysShow) {
				//Removing the ENTERFRAME listener in a try ;)
				try { myMC.removeEventListener(Event.ENTER_FRAME, PlaceToolTip); } catch (error:*) { };
				Tweener.removeTweens(myToolTip);
				ShowToolTip();
			
			} else {
			
				//Adding listener to MC
				myMC.addEventListener(MouseEvent.MOUSE_OVER, MouseOver);
				myMC.addEventListener(MouseEvent.MOUSE_OUT, CheckRemoveToolTip);
			}
			
			return myToolTip;
		}
		
		
		public static function CreateToolTipOptions(allOptions:Object = null):Object {
				
			if (allOptions.alreadyChecked) return allOptions;
				
			//Init options///
			if (allOptions == null) {
				allOptions = new Object();
			}
			
			allOptions.alreadyChecked = true;
			
			allOptions.delay = allOptions.delay == undefined ? 0 : allOptions.delay;
			allOptions.removeDelay = allOptions.removeDelay == undefined ? 0 : allOptions.removeDelay;
			allOptions.backColor = allOptions.backColor == undefined ? 0x7F090D : allOptions.backColor;
			allOptions.position = allOptions.position == undefined ? "TL" : allOptions.position;
			allOptions.followMouse = allOptions.followMouse == undefined ? false : allOptions.followMouse;
			allOptions.followAxis = allOptions.followAxis == undefined ? "xy" : allOptions.followAxis;
			allOptions.roundCorner = allOptions.roundCorner == undefined ? 10 : allOptions.roundCorner;
			allOptions.highLight = allOptions.highLight == undefined ? 1 : allOptions.highLight;
			allOptions.gradient = allOptions.gradient == undefined ? 1 : allOptions.gradient;
			allOptions.alpha = allOptions.alpha == undefined ? 1 : allOptions.alpha;
			
			allOptions.stayOnMouseOver = allOptions.stayOnMouseOver == undefined ? false : allOptions.stayOnMouseOver;
			
			//Text options
			allOptions.textColor = allOptions.textColor == undefined ? 0xffffff : allOptions.textColor;
			allOptions.textAlign = allOptions.textAlign == undefined ? "left" : allOptions.textAlign;
			
			//Timing
			allOptions.tweenTime = allOptions.tweenTime == undefined ? 1 : allOptions.tweenTime;
			
			//border options
			allOptions.borderColor = allOptions.borderColor == undefined ? 0x666666 : allOptions.borderColor;
			allOptions.borderWidth = allOptions.borderWidth == undefined ? 2 : Number(allOptions.borderWidth) + 1;
			allOptions.borderAlpha = allOptions.borderAlpha == undefined ? 1 : Number(allOptions.borderAlpha);
			
			//Sizing options
			allOptions.width = allOptions.width == undefined ? 0 : allOptions.width;
			
			//spacing
			allOptions.verticalMargin = allOptions.verticalMargin == undefined ? 5 : allOptions.verticalMargin;
			allOptions.horizontalMargin = allOptions.horizontalMargin == undefined ? 10 : allOptions.horizontalMargin;
			allOptions.spacing = allOptions.spacing == undefined ? 3 : allOptions.spacing;
			
			//mouse
			allOptions.showMouse = allOptions.showMouse == undefined ? false : allOptions.showMouse;
			
			//Tip options
			allOptions.showTip = allOptions.showTip == undefined ? true : allOptions.showTip;
			
			allOptions.autoFit = allOptions.autoFit == undefined ? true : allOptions.autoFit;
			
			if (allOptions.stayOnMouseOver && allOptions.removeDelay == 0) {
				allOptions.removeDelay = 200;
			}
			
			return allOptions;
		}
	}
}