/*
My top JS tips that I've leaned in the past year:

1. Be mindful of scope. Stay away from the global scope of the window and create js objects.
   (if you don't fully understand scope, let me know and I'll dig some good articles out for you)

2. Avoid (like the plague!) anonymous functions. Ensure that they're all assigned a name - it makes debugging possible.

3. Don't worry about the size of your js files, worry about the number of them! We routine send 100k+ of js code
		in our system, but we send it in one file. (We build file individually and then have a tool that bundles them together)
   I used to worry about the size of things, and then I was educated that the total request/response is 99% of the work.
   So really, don't worry about manual minification.

4. Use http://www.jslint.com/. Although the browser can interpret and run poorly formatted js, it doesn't make it right ;-)
	jsLint will point you in the right direction, and has saved my ass several times when I couldn't get my script to run in IE

5. If you use other people's code from the internet, reformat it to match your style. 

6. Code you get off of the internet is probably wrong, ill concieved and buggy. At least if it's in your formatting style
	you'll be able to see why!
	
7. Write your code planning that it will be object oriented:

	var object = function() { return { 
		someFunction : function() 
		{
			...
		}
	}}

8. Make everything an object! (which ties to point 1) Makes life much easier to debug, and the browser really doesn't care.

	var objinstance = new object();
	
   It makes it much simpler to build on in the future, and much simpler to debug (even if you're only creating one copy of the object)
*/

/*
Notes on these two functions:

  These are stripped from the base code library that we use to do lots of cool stuff in our system (extjs.com).
  If you include the block, these functions are applied to every function in the session.

CREATE DELEGATE

  createDelegate is probably the most powerful and useful function that I've ever used in js. This one function
  as saved me hundreds of lines of js code, and you'll see it throughout the code below.
  It allows you to attach function event handlers, using a defined scope and custom or extended arguments.

  e.g. - when you were calling $tooltip.hoverIntent( with your two functions, you needed to use inline anonymous 
  functions, that were scoped to (either the window, or the element that was being hovered, can't remember). This
  means that you loose access to variables and you need to start doing bad things like var t = this;

  Using createDelegate, you can call named, object level functions in the scope that you choose, such as the 
  object that you've created that is initiating the call. No matter what scope the event handler tries to call
  your function using, the scope that you define takes over.

  The second great advantage that createDelegate provides is the ability to replace or extend the arguments that
  are passed to your function. In the same example below, when I register the hoverIntent for imgX, I pass the 
  corresponding $tooltip and $target variables in as well so that they are readily available to me 
  (ie - no lookups required). These are variables can either be appended to the end of caller's agrument list,
  or they can replace the caller's arguments all together.

  Usage:
  
  	myFunction.createDelegate(scope, [arg1, arg2, ..., argX], appendArgs);
  	
  	scope {object} the scope that you want to use. in 90% of cases, you use the this object
  	args  {array}  an array of arguments to pass
  	appendArgs {boolean/number} true -> your arguments will be appended to the original call arguments
  								false -> your arguments will replace the original call arguments
  								number -> you can choose how many arguments or the original call to use first, 
  										but I wouldn't recommend using this method. if your unsure, use true
  										
DEFER

	defer acts much the same as createDelegate, but the first argument is the number of milliseconds to defer
	the call. This can be useful to call a function after an animation has been performed, or to get around
	event execution order. (e.g. elementA.outhover happens before elementB.inhover, but I want to know if
	elementB will receive the hover before I do anything in outhover...)
	
	My best advice for you when using this function is to be weary, and use it sparingly. It's really powerful,
	but if you can find a way arond needing to use it, do. The biggest problem with it is that you're not
	guaranteed to get the defer time that you want, because in js overdue timers don't fire if the browser is 
	busy running another piece of js.
	
	Take the following code for example:
	
	
	jQuery(document).ready(function()
	{	
		// after clicking ok, the alert box probably won't disappear right away...
	    alert('Click ok to start this foul experiment!\n\nThe next box should appear in 1ms.');
	    	
		(function() { alert('Much more than 1ms!!!') }).defer(1);
		
		// and now we freeze the browser...
		var bigString = '';
		for (var x = 0; x < 10000; x++)
		{
			for (var y = 0; y < 1000; y++)
			{
				bigString += 'X';
			}
		}
	});
  
*/

jQuery(document).ready(function()
{	
	Function.prototype.createDelegate = function(obj, args, appendArgs)
	{
        var method = this;
        return function() 
        {
            var callArgs = args || arguments;
            if(appendArgs === true){
                callArgs = Array.prototype.slice.call(arguments, 0);
                callArgs = callArgs.concat(args);
            }else if(typeof appendArgs == "number"){
                callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
                var applyArgs = [appendArgs, 0].concat(args); // create method call params
                Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
            }
            return method.apply(obj || window, callArgs);
        };
    };
    
    Function.prototype.defer = function(millis, obj, args, appendArgs)
    {
        var fn = this.createDelegate(obj, args, appendArgs);
        if(millis)
        {
            return setTimeout(fn, millis);
        }
        fn();
        return 0;
    };	
});

jQuery(document).ready(function(){ (new tooltipHandler).initialize(); })


//Ajax Tooltip script: By JavaScript Kit: http://www.javascriptkit.com
//Last update (July 10th, 08'): Modified tooltip to follow mouse, added Ajax "loading" message.

var ajaxtooltip = function() { return {
	//enable Fade? [true/false, duration_milliseconds]
	fadeeffect : [true, 300], 
	loadingHTML : '<div style="font-style:italic"><img src="ajaxload.gif" /> Fetching profile....</div>',

	positiontip : function($tooltip, e)
	{
		var dims = this.getViewPortDimension();		
		var twidth=$tooltip.get(0).offsetWidth;
		var theight=$tooltip.get(0).offsetHeight;
		$tooltip.css({left: ((dims.width - twidth) / 2) + dims.left, top : ((dims.height - twidth) / 2) + dims.top } );
	},
	
	getViewPortDimension : function()
	{
		// Browser Window Size and Position
		// copyright Stephen Chapman, 3rd Jan 2005, 8th Dec 2005
		// you may copy these functions but please keep the copyright notice as well
		function pageWidth() 
		{
			return window.innerWidth != null? window.innerWidth : document.documentElement && document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body != null ? document.body.clientWidth : null;
		} 
			
		function pageHeight() 
		{
			return  window.innerHeight != null? window.innerHeight : document.documentElement && document.documentElement.clientHeight ?  document.documentElement.clientHeight : document.body != null? document.body.clientHeight : null;
		} 

		function posLeft() 
		{
			return typeof window.pageXOffset != 'undefined' ? window.pageXOffset :document.documentElement && document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ? document.body.scrollLeft : 0;
		} 

		function posTop() 
		{
			return typeof window.pageYOffset != 'undefined' ?  window.pageYOffset : document.documentElement && document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ? document.body.scrollTop : 0;
		} 

		function posRight() 
		{
			return posLeft()+pageWidth();
		} 
		
		function posBottom() 
		{
			return posTop()+pageHeight();
		}
		
		return {
			width : pageWidth(),
			height : pageHeight(),
			top : posTop(),
			bottom : posBottom(),
			left : posLeft(),
			right : posRight()
		};
	},
	
	showtip : function($tooltip, e)
	{
		$tooltip.show();
		this.positiontip($tooltip, e);
		
		if (this.fadeeffect[0])
		{
			$tooltip.hide().fadeIn(this.fadeeffect[1]);
		}
		else
		{
			$tooltip.show();
		}
	},

	hidetip : function($tooltip, skipFadeEffect)
	{
		if (this.fadeeffect[0] && skipFadeEffect !== true)
		{
			$tooltip.fadeOut(this.fadeeffect[1]);
		}
		else
		{
			$tooltip.hide();
		}
	}

}}

var tooltipHandler = function() { return { 
	
	//array to contain references to all tooltip DIVs on the page
	tooltips:[],
	currentlyVisibleTooltip : null,
	
	initialize : function()
	{	
		this.ajaxtooltip = new ajaxtooltip();
		this.ajaxtooltip.iebody=(document.compatMode && document.compatMode!="BackCompat")? document.documentElement : document.body;
		
		//find all links with "title=ajax:" declaration
		var elements = $('*[@title^="ajax:"]');
		
		elements.each(this.prepareElement.createDelegate(this));//.createDelegate(this, [elements], true));
	},	
	prepareElement : function(index, element)
	{ 
		// Create the tooltip element
		this.tooltips.push($('<div class="ajaxtooltip"></div>').appendTo('body'))
		var $tooltip = this.tooltips[this.tooltips.length - 1];
		
		var $target = $(element);
		//get URL of external file
		$target.titleurl=jQuery.trim(element.getAttribute('title').split(':')[1]); 
		//remember this tooltip DIV's position relative to its peers
		$target.titleposition=index+' pos' ;
		$target.removeAttr('title')
		
		$tooltip.hoverIntent(
			this.onTooltipHoverStart.createDelegate(this, [$tooltip, $target], true), 
			this.onTooltipHoverEnd.createDelegate(this, [$tooltip, $target], true)
		);
		
		$target.hoverIntent(
			this.onTargetHoverStart.createDelegate(this, [$tooltip, $target], true), 
			this.onTargetHoverEnd.createDelegate(this, [$tooltip, $target], true)
		);
		
		// Not good to bind to mouse move for positioning -> your actually calling the function several hundred times in a few seconds
		/*$target.bind("mousemove", function(e){
			var $tooltip=tooltips[parseInt(this.titleposition)]
			ajaxtooltip.positiontip($tooltip, e)
		})*/
	},
	
	onTargetHoverStart : function(e, $tooltip, $target) 
	{
		$tooltip.targetHover = true;
		
		if (this.currentlyVisibleTooltip)
		{
			this.currentlyVisibleTooltip.targetHover = false;
			this.currentlyVisibleTooltip.tooltipHover = false;
			this.hideTooltip(this.currentlyVisibleTooltip, true);
		}
		
		this.currentlyVisibleTooltip = $tooltip;
		
		if (!$tooltip.get(0).loadsuccess)
		{ //first time fetching Ajax content for this tooltip?
			$tooltip.html(this.ajaxtooltip.loadingHTML).show();
			$tooltip.load($target.titleurl, '', (function()
			{
				this.ajaxtooltip.showtip($tooltip, e);
				$tooltip.post(0).loadsuccess=true;
			}).createDelegate(this));
		}
		else
		{
			this.ajaxtooltip.showtip($tooltip, e);
		}
	},
	
	onTargetHoverEnd : function(e, $tooltip, $target) 
	{
		(function() {
			$tooltip.targetHover = false;
			this.hideTooltip($tooltip);
		}).defer(800, this);
	},
	
	onTooltipHoverStart : function(e, $tooltip, $target) 
	{
		$tooltip.tooltipHover = true;
	},
	
	onTooltipHoverEnd : function(e, $tooltip, $target) 
	{
		$tooltip.tooltipHover = false;
		this.hideTooltip($tooltip);
	},
	
	hideTooltip : function($tooltip, skipFadeEffect)
	{
		if (!$tooltip.targetHover && !$tooltip.tooltipHover)
		{
			this.currentlyVisibleTooltip = null;
			this.ajaxtooltip.hidetip($tooltip, skipFadeEffect);
		}
	}
}};


