/*

	Mouse Tracking Into Box

	version 1.0
	
	19 - Apr - 07
	
	G. Stevens
	
	Implements a tool tips type info box at the mouse cursor and tracks its movement
	
	Required Libraries: event.js

*/


InfoBoxTrackObj = function() {
	
	
	var PREFIX = "gs1907_";
	
	var infoBox = document.getElementById(PREFIX + "infBox");
	var infoBoxShadow = document.getElementById(PREFIX + "infBoxShadow");
	var body = document.getElementsByTagName("body")[0];
	var infoWidth, infoHeight;
	var xOffset, yOffset;
	
	var evnt;//ref to event object
	
	var hasShadow = true;
	var isHidden = true;
	
	var DEF_CLASS = "gsInfoBox";
	var DEF_SHADOW_CLASS = "gsInfoBoxShadow";
	var DEF_Z_INDEX = 2;//default z-index
	var DEF_WIDTH = 50;
	var UNITS = "px";
	var SHADOW_OFFSET = 3;
	var MOUSE_OFFSET = 20;
	var MAX_WIDTH = 300;
	
	//create elements if they dont already exist
	if(!infoBox) {
		infoBox = document.createElement("div");
		infoBox.id = PREFIX + "infoBox";
		document.getElementsByTagName("body")[0].appendChild(infoBox);
		var cInfoBox = "{position: absolute !important; color: #333333; background: rgb(255,255,245); border: 1px solid #333333; ";
		cInfoBox +=	"z-index: " + DEF_Z_INDEX + "; display: none; padding: 0 4px;}";
		createRule("." + DEF_CLASS, cInfoBox);
		infoBox.className = DEF_CLASS;
	}//if
	if(!infoBoxShadow) {
		infoBoxShadow = document.createElement("div");
		document.getElementsByTagName("body")[0].appendChild(infoBoxShadow);
		var cInfoBoxShadow = "{position: absolute !important; background: black !important; opacity: .3; border-color: black !important; ";
		cInfoBoxShadow += "filter:Alpha(Opacity=30); -khtml-opacity: 0.3; -moz-opacity: 0.3; color: black !important; padding: 0 4px;";
		cInfoBoxShadow +=	"z-index: " + (DEF_Z_INDEX - 1) + "; display: none; border-width: 1px; border-style: solid !important;}";
		createRule("." + DEF_SHADOW_CLASS, cInfoBoxShadow);
		infoBoxShadow.className = DEF_SHADOW_CLASS;
	}//if
	
	try {
		evnt = new EventObj();
	} catch(e) {
		alert("Error creating EventObj instance: " + e)
	}//try



	//
	//###### public methods ######
	//
	
	this.setZIndex = function(zIndex) {

		if(infoBox) infoBox.style.zIndex = (zIndex > DEF_Z_INDEX) ? zIndex : DEF_Z_INDEX;
		if(infoBoxShadow) infoBoxShadow.style.zIndex = (zIndex > DEF_Z_INDEX) ? zIndex - 1 : DEF_Z_INDEX - 1;
	}//setZIndex
	
	this.setClass = function(aClass){
	//sets class to use
	//aClass = string containing a class name. If null or empty, class used will be default
		if(infoBox && infoBoxShadow && typeof aClass == "string") {
			if(aClass != "" && aClass != null) {
				infoBox.className = DEF_CLASS + " " + aClass;
				infoBoxShadow.className = aClass + " " + DEF_SHADOW_CLASS;
							
			} else {//use default class
				infoBox.className = DEF_CLASS;
				infoBoxShadow.className = DEF_SHADOW_CLASS;					
			}//if

		}//if
	}//setClass
	
	this.setContent = function(content){
		
		if(infoBox && typeof content == "string") {
			infoBox.style.width = "auto";
			infoBox.innerHTML = content;
			infoBoxShadow.style.width = "auto";
			infoBoxShadow.innerHTML = content;
			infoWidth = getOffsetProperty(infoBox, infoBox, "offsetWidth");
			if(infoWidth > MAX_WIDTH) infoBox.style.width = MAX_WIDTH + UNITS;//limit width to max width
			infoBoxShadow.style.width = infoBox.style.width;
			infoWidth =  getOffsetProperty(infoBox, infoBox, "offsetWidth");
			infoHeight = getOffsetProperty(infoBox, infoBox, "offsetHeight");
		}//if
	}//setContent
	
	this.setWidth = function(width){
		if(typeof width != "number" || width < 1) return;
		MAX_WIDTH = width;
	}//setWidth
	
	this.setShadow = function(state){
		if(infoBoxShadow && typeof state == "boolean" && !isHidden) infoBoxShadow.style.display = (state) ? "block" : "none";
		hasShadow = state;
	}//setShadow
	
	this.isHidden = function(){
		return isHidden;
	}//isHidden
	
	this.show = function(text, direction){
	//show infobox
	//text = any text to display
	//direction = string containing infobox compass direction relative to mouse pointer
	//		allowed values = NE, NW, SE, SW - default is SE
		if(text != null && text != "") this.setContent(text);

		if(infoBox) infoBox.style.display = "block";
		if(infoBoxShadow && hasShadow) infoBoxShadow.style.display = "block";
		
		//calc infobox position offset from mouse pointer
		if(direction) direction = direction.toUpperCase();

		
		if(direction == "NE") {//top right
			xOffset = MOUSE_OFFSET - InfoBoxTrackObj.prototype.OFFSET_ADJUST;
			yOffset = -MOUSE_OFFSET - infoHeight + InfoBoxTrackObj.prototype.OFFSET_ADJUST;
			
		} else if(direction == "NW") {//top left
			xOffset = -MOUSE_OFFSET - infoWidth + InfoBoxTrackObj.prototype.OFFSET_ADJUST;
			yOffset = -MOUSE_OFFSET - infoHeight + InfoBoxTrackObj.prototype.OFFSET_ADJUST;
			
		} else if(direction == "SW") {//bottom left
			xOffset = -MOUSE_OFFSET - infoWidth + InfoBoxTrackObj.prototype.OFFSET_ADJUST;
			yOffset = MOUSE_OFFSET - InfoBoxTrackObj.prototype.OFFSET_ADJUST;
			
		} else {//default - botton right
	
			xOffset = MOUSE_OFFSET;
			yOffset = MOUSE_OFFSET;		
		}//if
		
		evnt.addEvent("mouseover", body, updatePosition, false);				
		evnt.addEvent("mousemove", body, updatePosition, false);		
		
	}//show
	
	this.hide = function(){
	//hides infobox
		if(infoBox) infoBox.style.display = "none";
		if(infoBoxShadow) infoBoxShadow.style.display = "none";
		isHidden = true;
		evnt.removeEvent("mousemove", body, updatePosition, false);
	}//hide
	
	//
	//###### private methods ######
	//
	
	function createRule(selctor, rule) {
	//creates a css rule
	//selector = string containing css selector ie "body" or ".someClass p"
	//rule = string containing css rule eg "{color: red; font-size: 120%;}"
		with(document.styleSheets[0]){
			if(typeof insertRule == "function") {
				insertRule(selctor + " " + rule, cssRules.length);//CSS2 browsers
	
			} else if(typeof addRule != "undefined") {//IE
				addRule(selctor, rule);
			}
		}//with
	}//createRule
	
	function getOffsetProperty(elem1, elem2, prop){
	//retrives an offset property that is only visible if element or its accedents is exposed ie has style.display != "none"
	//elem1: ref to HTML element to expose; elem2: ref to HTML to find offset property of; prop: string containing offset property name
		if(typeof elem1 != "object" || typeof elem2 != "object" || typeof prop != "string") return null;
		var result;
		var vis = elem1.style.visibility;//store settings
		var display = elem1.style.display;
		elem1.style.visibility = "hidden";//expose element
		elem1.style.display = "block";
		result = eval("elem2." + prop);//get the offset property
		elem1.style.display = display;//restore original settings
		elem1.style.visibility = vis;		
		return result;
	}//getOffsetProperty
	

	//
	//###### event handler function ######
	//	
	function updatePosition(e) {
	//mouse movement event handler
	
		var x = evnt.getX(e);
		var y = evnt.getY(e);
		
	var IS_IE = document.all && document.getElementById && !document.defaultView;//test for IE
	

	if(IS_IE) {//IE
		if(infoBoxShadow && hasShadow){
			infoBoxShadow.style.top = (y + yOffset + SHADOW_OFFSET + document.documentElement.scrollTop) + UNITS;
			infoBoxShadow.style.left = (x + xOffset + SHADOW_OFFSET + document.documentElement.scrollLeft) + UNITS;			
		}//if
		
		if(infoBox){
			infoBox.style.top = (y + yOffset + document.documentElement.scrollTop) + UNITS;
			infoBox.style.left = (x + xOffset + document.documentElement.scrollLeft) + UNITS;				
		}//if	
	
	} else {//non-IE
		if(infoBoxShadow && hasShadow){
			infoBoxShadow.style.top = (y + yOffset + SHADOW_OFFSET) + UNITS;
			infoBoxShadow.style.left = (x + xOffset + SHADOW_OFFSET) + UNITS;			
		}//if
		
		if(infoBox){
			infoBox.style.top = (y + yOffset) + UNITS;
			infoBox.style.left = (x + xOffset) + UNITS;				
		}//if
		
	}//if

	
	}//updatePosition	
	
	
}//InfoBoxTrackObj

//OFFSET_ADJUST allows fine control over gap between mouse cursor and info box.
//increasing this value moves info box closer to mouse cursor for NW, SW and NE positions
InfoBoxTrackObj.prototype.OFFSET_ADJUST = 10;

