/*
Camjax Hover 3.0
Author: Cameron Duff, Black & Hayden Consulting
Date: 27/05/2010
Release Notes: Complete rewrite: enhanced hover logic and usability
Dependencies: jQuery, Camjax 2.82
Backward compatible: No

Version History:
	2.0,	20/10/2009,		Refactor for multiple hover zones
	1.0,	1/08/2009,		Initial release
*/

//Internal variables - do not change
var HOVER_STATE_HIDDEN = 0;
var HOVER_STATE_LOADING = 1;
var HOVER_STATE_SHOWING = 2;
var DEFAULT_SLIDE_SPEED = 400; //slide animation time in milliseconds
var DEFAULT_AJAX_SHOW_DELAY = 350;
var DEFAULT_AJAX_HIDE_DELAY = 800;
var DEFAULT_STATIC_SHOW_DELAY = 150;
var DEFAULT_STATIC_HIDE_DELAY = 300;
var HOVER_MOUSE_OFFSET_LEFT = 5;
var HOVER_MOUSE_OFFSET_TOP = 10;
var AN_IMPORTANT_NUMBER = 8; // XD self-documenting code
var camjaxHovers = new Array();

function CamjaxHover(hookObject, hoverWindow, camjaxUpdateUrl, loadingDisplay)
{
	this.hookObject = hookObject;
	this.hoverWindow = hoverWindow;
	this.camjaxUpdateUrl = camjaxUpdateUrl;
	this.loadingDisplay = loadingDisplay;
	this.slideSpeed = DEFAULT_SLIDE_SPEED;
	this.hoverState = HOVER_STATE_HIDDEN;
	this.showTimeout = null;
	this.hideTimeout = null;
	this.onHook = false;
	
	if(this.camjaxUpdateUrl != null)
	{
		this.showDelay = DEFAULT_AJAX_SHOW_DELAY;
		this.hideDelay = DEFAULT_AJAX_HIDE_DELAY;
	}
	else
	{
		this.showDelay = DEFAULT_STATIC_SHOW_DELAY;
		this.hideDelay = DEFAULT_STATIC_HIDE_DELAY;
	}
	
	camjaxHovers.push(this);
	hookObject.click(function(event)
	{
		var camjaxHover = getCamjaxHoverForHook(this);
		
		if(camjaxHover.hoverState == HOVER_STATE_HIDDEN)
		{
			if(camjaxHover.showTimeout != null)
			{
					clearTimeout(camjaxHover.showTimeout);
			}
			camjaxHover.showHoverWindow(event);
		}
	});

	hookObject.mouseover(function(event)
	{
		var camjaxHover = getCamjaxHoverForHook(this);
		camjaxHover.onHook = true;
		
		if(camjaxHover.hoverState == HOVER_STATE_HIDDEN)
		{
			if(camjaxHover.showTimeout != null)
			{
				clearTimeout(camjaxHover.showTimeout);
			}

			camjaxHover.showTimeout = setTimeout(function() { camjaxHover.checkShowHoverWindow(event); }, camjaxHover.showDelay);
		}
	});

	hookObject.mouseout(function()
	{
		var camjaxHover = getCamjaxHoverForHook(this);
		camjaxHover.onHook = false;
		
		if(camjaxHover.hoverState == HOVER_STATE_SHOWING)
		{
			if(camjaxHover.hideTimeout != null)
			{
				clearTimeout(camjaxHover.hideTimeout);
			}

			camjaxHover.hideTimeout = setTimeout(function() { camjaxHover.checkHideHoverWindow(); }, camjaxHover.hideDelay);
		}
	});
	
	hoverWindow.mouseover(function()
	{
		var camjaxHover = getCamjaxHoverForHoverWindow(this);
		camjaxHover.onHook = true;
		if(camjaxHover.hideTimeout != null)
		{
			clearTimeout(camjaxHover.hideTimeout);
		}
	});

	hoverWindow.mouseout(function()
	{
		var camjaxHover = getCamjaxHoverForHoverWindow(this);
		camjaxHover.onHook = false;
		if(camjaxHover.hideTimeout != null)
		{
			clearTimeout(camjaxHover.hideTimeout);
		}

		if(camjaxHover.hoverState == HOVER_STATE_SHOWING)
		{
			camjaxHover.hideTimeout = setTimeout(function() { camjaxHover.checkHideHoverWindow(); }, camjaxHover.hideDelay);
		}
	});
}

CamjaxHover.prototype.checkHideHoverWindow = function()
{
	if(!this.onHook)
	{
		this.hideHoverWindow();
	}
}

CamjaxHover.prototype.checkShowHoverWindow = function(mouseEvent)
{
	if(this.onHook)
	{
		this.showHoverWindow(mouseEvent);
	}
}

CamjaxHover.prototype.hideHoverWindow = function()
{
	this.hoverState = HOVER_STATE_HIDDEN;
	this.hoverWindow.slideUp(this.slideSpeed);
}

CamjaxHover.prototype.showHoverWindow = function(mouseEvent)
{
	if(this.hideTimeout != null)
	{
		clearTimeout(this.hideTimeout);
	}

	updateCamjaxHoverWindowPosition(this.hoverWindow.get(0), getMouseX(mouseEvent), getMouseY(mouseEvent));
	
	if(this.hoverState == HOVER_STATE_HIDDEN)
	{
		this.hoverWindow.slideDown(this.slideSpeed);
	}



	if(this.camjaxUpdateUrl != null)
	{
		if(this.loadingDisplay != null)
		{
			this.hoverWindow.get(0).innerHTML = this.loadingDisplay.get(0).innerHTML;
		}
		else
		{
			this.hoverWindow.get(0).innerHTML = "Loading ...";
		}
		
		this.hoverState = HOVER_STATE_LOADING;
		
		camjaxController.sendAjax(this.camjaxUpdateUrl, null, function(responseText, camjaxHover)
		{		
			camjaxHover.hoverWindow.get(0).innerHTML = responseText;
			camjaxHover.hoverState = HOVER_STATE_SHOWING;
	
			if(!camjaxHover.onHook)
			{
				if(camjaxHover.hideTimeout != null)
				{
					clearTimeout(camjaxHover.hideTimeout);
				}
	
				camjaxHover.hideTimeout = setTimeout(function() { camjaxHover.checkHideHoverWindow(); }, camjaxHover.hideDelay);
			}
		}, [ this ]);
	}
	else
	{
		this.hoverState = HOVER_STATE_SHOWING;
		if(!this.onHook)
		{
			if(this.hideTimeout != null)
			{
				clearTimeout(this.hideTimeout);
			}

			this.hideTimeout = setTimeout(function() { this.checkHideHoverWindow(); }, this.hideDelay);
		}
	}
}

function getCamjaxHoverForHook(hook)
{
	for(var i = 0; i < camjaxHovers.length; i ++)
	{
		if(camjaxHovers[i].hookObject.get(0).id == hook.id)
		{
			return camjaxHovers[i];
		}
	}
	
	return null;
}

function getCamjaxHoverForHoverWindow(hoverWindow)
{
	for(var i = 0; i < camjaxHovers.length; i ++)
	{
		if(camjaxHovers[i].hoverWindow.get(0).id == hoverWindow.id)
		{
			return camjaxHovers[i];
		}
	}
	
	return null;
}

function updateCamjaxHoverWindowPosition(hoverWindow, currentMouseX, currentMouseY)
{
	var elementWidth = hoverWindow.offsetWidth;		
	var adjustedMouseX = currentMouseX - getPosLeft();
	
	hoverWindow.style.left = (currentMouseX + HOVER_MOUSE_OFFSET_LEFT) + "px";
	hoverWindow.style.top = (currentMouseY + HOVER_MOUSE_OFFSET_TOP) + "px";

	if(adjustedMouseX + elementWidth > getPageWidth())
	{
		hoverWindow.style.left = (currentMouseX - elementWidth - AN_IMPORTANT_NUMBER) + "px";
	}
	
	var elementHeight = hoverWindow.offsetHeight;
	var adjustedMouseY = currentMouseY - getPosTop();
	
	if(adjustedMouseY + elementHeight > getPageHeight())
	{
		hoverWindow.style.top = (currentMouseY - elementHeight - AN_IMPORTANT_NUMBER) + "px";
	}
}

// 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 getPageWidth() { return window.innerWidth != null? window.innerWidth : document.documentElement && document.documentElement.clientWidth ?       document.documentElement.clientWidth : document.body != null ? document.body.clientWidth : null;} 
function getPageHeight() { return  window.innerHeight != null? window.innerHeight : document.documentElement && document.documentElement.clientHeight ?  document.documentElement.clientHeight : document.body != null? document.body.clientHeight : null;} 
function getPosLeft() { return typeof window.pageXOffset != 'undefined' ? window.pageXOffset :document.documentElement && document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ? document.body.scrollLeft : 0;} 
function getPosTop() { return typeof window.pageYOffset != 'undefined' ?  window.pageYOffset : document.documentElement && document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ? document.body.scrollTop : 0;} 
function getPosRight() { return getPosLeft() + getPageWidth(); } 
function getPosBottom() { return getPosTop() + getPageHeight(); }

function getMouseX(evt) { if (evt.pageX) return evt.pageX; else if (evt.clientX)   return evt.clientX + (document.documentElement.scrollLeft ?   document.documentElement.scrollLeft :   document.body.scrollLeft); else return null; }
function getMouseY(evt) { if (evt.pageY) return evt.pageY; else if (evt.clientY)   return evt.clientY + (document.documentElement.scrollTop ?   document.documentElement.scrollTop :   document.body.scrollTop); else return null; }
