(function($){
	$.fn.ImageSwitch = function(Arguements, FuntionHandle) {
		var defaults = {
			Type: "FadeIn", // Type of effect to run the function
			NewImage: "", //The new image will be loaded in
			EffectOriginal: true,
			Speed: 1000, //Speed of the effect
			StartLeft: 50, //Which position the effect start from compare to the final position could be (-)
			StartTop: 0,
			StartOpacity: 0, //Which start opacity it would be
			EndLeft: -50, //Which position the effect start from compare to the final position could be (-)
			EndTop: 0,
			Direction: "RightLeft" //Which Way the image will be sroll
		}
		
		var Args = $.extend(defaults, Arguements);
		var Obj = this; // Just a way to reference to this obj in case we need to pass in another event handle
		var EndFunction = FuntionHandle;
		//-----------------------------------------------------------------------------------------------------------
		//The original image will be fade out when the new image will fade in
		var FadeImage = function(){
			//Generate the effect map, move the effect map overlay the original map
			$("body").append("<img class='GrpEffectImg'/>");
			$(".GrpEffectImg").attr("src", Obj.attr("src"));
			$(".GrpEffectImg").css("position", "absolute");
			$(".GrpEffectImg").css("top", Obj.offset().top);
			$(".GrpEffectImg").css("left", Obj.offset().left);
			$(".GrpEffectImg").css("opacity", 1);
			
			//Change image of the original map
			Obj.attr("src", Args.NewImage);
			
			//Need something special when user want to keep no effect for the orignal
			if(Args.EffectOriginal)
			{
				//Set the start opacity, as the effect will fade out we set in start at 1, vice versa for the original
				Obj.css("opacity", Args.StartOpacity);		
				
				//Fade in the original image
				Obj.animate({"opacity":1}, Args.Speed);			
			}
			
			//Start effect animation
			$(".GrpEffectImg").animate({"opacity":0}, Args.Speed, function(){
					//Remove the effect image when finish the effect
					$(".GrpEffectImg").remove();
					EndFunction();
			});			
		}
		//-----------------------------------------------------------------------------------------------------------
		//The new image will fly from the startPosition with the StartOpacity
		var FlyIn = function(){
			//Generate the effect map, move the effect map overlay the original map
			$("body").append("<img class='GrpEffectImg'/>");
			$(".GrpEffectImg").attr("src", Args.NewImage);
			$(".GrpEffectImg").css("position", "absolute");
			$(".GrpEffectImg").css("top", Obj.offset().top + Args.StartTop);
			$(".GrpEffectImg").css("left", Obj.offset().left + Args.StartLeft);
			$(".GrpEffectImg").css("opacity", Args.StartOpacity);
			
			//Let the effect start fly in
			$(".GrpEffectImg").animate({"opacity":1, "top":Obj.offset().top, 
										"left": Obj.offset().left}, Args.Speed,
				function(){
					Obj.attr("src", Args.NewImage);
					$(".GrpEffectImg").remove();
					EndFunction();
			});
		}
		//-----------------------------------------------------------------------------------------------------------
		//The old image will fly out from the current position to the end position
		var FlyOut = function(){
			//Generate the effect map, move the effect map overlay the original map
			$("body").append("<img class='GrpEffectImg'/>");
			$(".GrpEffectImg").attr("src", Obj.attr("src"));
			$(".GrpEffectImg").css("position", "absolute");
			$(".GrpEffectImg").css("top", Obj.offset().top);
			$(".GrpEffectImg").css("left", Obj.offset().left);
			$(".GrpEffectImg").css("opacity", 1);
			Obj.attr("src", Args.NewImage);
			//Let the effect start fly out
			$(".GrpEffectImg").animate({"opacity":0, "top":Obj.offset().top + Args.EndTop, 
										"left": Obj.offset().left + Args.EndLeft}, Args.Speed,
				function(){
					$(".GrpEffectImg").remove();
					EndFunction();
			});
		}		
		//-----------------------------------------------------------------------------------------------------------
		//The new image will scoll in and kick the old image out
		var Scroll = function(){
			//Save the original status so we could set it in the end
			var orgPosition = Obj.css("position");
			var orgLeft = Obj.css("left");
			var orgTop = Obj.css("top");
			//Create a viewport for it
			Obj.wrap("<div id='GrpViewport'></div>");
			$("#GrpViewport").css("overflow","hidden");
			$("#GrpViewport").width(Obj.width());
			$("#GrpViewport").height(Obj.height());								
			//Generate the effect map, move the effect map overlay the original map				
			$("#GrpViewport").append("<img class='GrpEffectImg'/>");
			$(".GrpEffectImg").attr("src", Args.NewImage);
			$(".GrpEffectImg").css("position", "absolute");
			//Find where the Effect Image start
			var StartTop = 0;
			var StartLeft = 0;				
			switch(Args.Direction){
				case "RightLeft":	StartLeft = -Obj.width();	break;
				case "LeftRight":	StartLeft = Obj.width();	break;
				case "TopDown":		StartTop = -Obj.height();	break;
				case "DownTop":		StartTop = Obj.height();	break;
			}
			
			$(".GrpEffectImg").css("top", StartTop);
			$(".GrpEffectImg").css("left", StartLeft);				
			//We need to treat absolute position different					
			if(Obj.css("position")!="absolute")
			{
				$("#GrpViewport").css("position","relative");					
				Obj.css("position","absolute");			
			}
			else
			{
				$("#GrpViewport").css("position","absolute");
				$("#GrpViewport").css("left",orgLeft);
				$("#GrpViewport").css("top",orgTop);
				Obj.css("position","absolute");			
				Obj.css("top",0);
				Obj.css("left",0);
			}
			$(".GrpEffectImg").animate({"top":0,"left":0}, Args.Speed, 
					function(){
						//Finish the effect, and replace the viewport with this area
						Obj.attr("src", Args.NewImage);
						Obj.css("position", orgPosition);
						Obj.css("top", orgTop);
						Obj.css("left", orgLeft);
						$("#GrpViewport").replaceWith(Obj);
						EndFunction();
				});	
			if(Args.EffectOriginal)
			{			
				//Move the original image along
				Obj.animate({"top": - StartTop,
							"left": - StartLeft}, Args.Speed);									
			}
		}
		//-----------------------------------------------------------------------------------------------------------
		//A door come out create an effect door close.then open the new image
		var SingleDoor = function(){
			//Save the original status so we could set it in the end
			var orgPosition = Obj.css("position");
			var orgLeft = Obj.css("left");
			var orgTop = Obj.css("top");
			//Create a viewport for it
			Obj.wrap("<div id='GrpViewport'></div>");
			$("#GrpViewport").css("overflow","hidden");
			$("#GrpViewport").width(Obj.width());
			$("#GrpViewport").height(Obj.height());								
			//Generate the effect map, move the effect map overlay the original map				
			$("#GrpViewport").append("<div class='GrpEffectDiv'/>");
			$(".GrpEffectDiv").attr("src", Args.NewImage);
			$(".GrpEffectDiv").css("position", "absolute");
			$(".GrpEffectDiv").css("background-color", "#FFF");
			$(".GrpEffectDiv").width(Obj.width());
			$(".GrpEffectDiv").height(Obj.height());								
			//Find where the Effect Image start
			var StartTop = 0;
			var StartLeft = 0;				
			switch(Args.Direction){
				case "RightLeft":	StartLeft = -Obj.width();	break;
				case "LeftRight":	StartLeft = Obj.width();	break;
				case "TopDown":		StartTop = -Obj.height();	break;
				case "DownTop":		StartTop = Obj.height();	break;
			}				
			$(".GrpEffectDiv").css("top", StartTop);
			$(".GrpEffectDiv").css("left", StartLeft);	
			
			//We need to treat absolute position different					
			if(Obj.css("position")!="absolute")
			{
				$("#GrpViewport").css("position","relative");					
				Obj.css("position","absolute");			
			}
			else
			{
				$("#GrpViewport").css("position","absolute");
				$("#GrpViewport").css("left",orgLeft);
				$("#GrpViewport").css("top",orgTop);
				Obj.css("position","absolute");			
				Obj.css("top",0);
				Obj.css("left",0);
			}
			//Start Close the Door
			$(".GrpEffectDiv").animate({"top":0,"left":0}, Args.Speed, function(){
				//Finish the first effect change the image and open the door
				Obj.attr("src", Args.NewImage);
				//Start open the door
				$(".GrpEffectDiv").animate({"top":StartTop,"left":StartLeft}, Args.Speed, function(){
					//Reset style
					Obj.css("position", orgPosition);
					Obj.css("top", orgTop);
					Obj.css("left", orgLeft);
					$("#GrpViewport").replaceWith(Obj);
					EndFunction();
				})
			});	
		}
		//-----------------------------------------------------------------------------------------------------------
		//Same with single door but with this effect, there will be 2 door
		var DoubleDoor = function(){
			//Save the original status so we could set it in the end
			var orgPosition = Obj.css("position");
			var orgLeft = Obj.css("left");
			var orgTop = Obj.css("top");
			//Create a viewport for it
			Obj.wrap("<div id='GrpViewport'></div>");
			$("#GrpViewport").css("overflow","hidden");
			$("#GrpViewport").width(Obj.width());
			$("#GrpViewport").height(Obj.height());								
			//Generate the effect map, move the effect map overlay the original map				
			$("#GrpViewport").append("<div class='GrpEffectDiv'/>");
			$(".GrpEffectDiv").css("position", "absolute");
			$(".GrpEffectDiv").css("background-color", "#FFF");
			$(".GrpEffectDiv").width(Obj.width());
			$(".GrpEffectDiv").height(Obj.height());								
			//We need the second door
			$("#GrpViewport").append("<div class='GrpEffectDiv1'/>");
			$(".GrpEffectDiv1").css("position", "absolute");
			$(".GrpEffectDiv1").css("background-color", "#FFF");
			$(".GrpEffectDiv1").width(Obj.width());
			$(".GrpEffectDiv1").height(Obj.height());								
			
			//Find where the Effect Image start
			var StartTop = 0;
			var StartLeft = 0;				
			switch(Args.Direction){
				case "RightLeft":	StartLeft = -Obj.width();	break;
				case "LeftRight":	StartLeft = Obj.width();	break;
				case "TopDown":		StartTop = -Obj.height();	break;
				case "DownTop":		StartTop = Obj.height();	break;
			}				
			$(".GrpEffectDiv").css("top", StartTop);
			$(".GrpEffectDiv").css("left", StartLeft);	
			$(".GrpEffectDiv1").css("top", -StartTop);
			$(".GrpEffectDiv1").css("left", -StartLeft);	
			
			//set the background for the door effect so it look different
			if(!Args.EffectOriginal){
				$(".GrpEffectDiv").css("background","#FFF url("+Args.NewImage+") no-repeat "+ -StartLeft/2 +"px "+ -StartTop/2+"px");
				$(".GrpEffectDiv1").css("background","#FFF url("+Args.NewImage+") no-repeat "+ StartLeft/2+"px "+ StartTop/2 +"px");
			}			
			
			//We need to treat absolute position different					
			if(Obj.css("position")!="absolute")
			{
				$("#GrpViewport").css("position","relative");					
				Obj.css("position","absolute");			
			}
			else
			{
				$("#GrpViewport").css("position","absolute");
				$("#GrpViewport").css("left",orgLeft);
				$("#GrpViewport").css("top",orgTop);
				Obj.css("position","absolute");			
				Obj.css("top",0);
				Obj.css("left",0);
			}
			//Start Close the Door
			$(".GrpEffectDiv").animate({"top":StartTop/2,"left":StartLeft/2}, Args.Speed, function(){
				//Finish the first effect change the image and open the door
				Obj.attr("src", Args.NewImage);
				//If EffectOriginal isn't on mean two door stick into the new image, then stop here. Else carry on
				if(!Args.EffectOriginal){
					Obj.css("position", orgPosition);
					Obj.css("top", orgTop);
					Obj.css("left", orgLeft);				
					$("#GrpViewport").replaceWith(Obj);
				}else{
					//Start open the door
					$(".GrpEffectDiv").animate({"top":StartTop,"left":StartLeft}, Args.Speed, function(){
						//Reset style
						Obj.css("position", orgPosition);
						Obj.css("top", orgTop);
						Obj.css("left", orgLeft);
						$("#GrpViewport").replaceWith(Obj);
					});
				}
			});	
			$(".GrpEffectDiv1").animate({"top":-StartTop/2,"left":-StartLeft/2}, Args.Speed, function(){
				//Finish the first effect change the image and open the door
				Obj.attr("src", Args.NewImage);
				//If EffectOriginal isn't on mean two door stick into the new image, then stop here. Else carry on
				if(!Args.EffectOriginal){
					EndFunction();
				}else{
					//Start open the door
					$(".GrpEffectDiv1").animate({"top":-StartTop,"left":-StartLeft}, Args.Speed, function(){
						//Run the end effect
						EndFunction();
					});
				}
			});					
		}
		
		return this.each(function(){
			switch(Args.Type){
				case "FadeIn":
					FadeImage();
					break;
				case "FlyIn":
					FlyIn();
					break;
				case "FlyOut":
					FlyOut();
					break;					
				case "Scroll":
					Scroll();
					break;
				case "SingleDoor":
					SingleDoor();
					break;
				case "DoubleDoor":
					DoubleDoor();
					break;						
			}
		})
	}
})(jQuery);
