/****************************************************************************************/
/*  Copyright (C) 2004 Rob Johnson <robjohnson@black-hole.com>                          */
/*                                                                                      */
/*  This program IS NOT free software; you may not use, redistribute or modify          */
/*  without the permission of the author.  For licensing and purchasing information     */
/*  please visit http://www.script-source.net/jshelp/ .                                 */
/*                                                                                      */
/*  JSHelp.js 1.1 - JSHelp is a configurable pop-up help script which is useful for     */
/*  presenting formatted messages to users.  JSHelp works in all recent browsers        */
/*  including IE 5+, Netscape 6+, Mozilla 1+, Opera 7+                                  */
/*                                                                                      */
/*  For more information and a demo please visit http://www.script-source.net/jshelp/ . */
/****************************************************************************************/

window.JSHelpLib = new JSHelpLibClass(); window.JSHelpLib.init();


function JSHelpLibClass() {
	this.init = function() {
		this.curPos = new mouseCoords(false);
		if(this.isIE()) document.onmousemove = window.JSHelpLib.eTrackCoords;
		else {
			window.captureEvents(Event.MOUSEMOVE);
			window.onmousemove = window.JSHelpLib.eTrackCoords;
		}
	}
	this.isIE = function() {
		return navigator.appName.indexOf('Microsoft') >= 0;
	}
	this.getLeft = function(obj) {
		return (obj.offsetParent==null ? obj.offsetLeft : obj.offsetLeft + this.getLeft(obj.offsetParent));
	}
	this.getTop = function(obj) {
		return (obj.offsetParent==null ? obj.offsetTop : obj.offsetTop + this.getTop(obj.offsetParent));
	}
	this.in_array = function(needle, haystack) {
		for(var i in haystack) {
			if(haystack[i] == needle) return true;
		}
		return false;
	}

	this.getElementByClassName = function(that, name) {
		for(var i=0; i<that.childNodes.length; ++i) {
			if(that.childNodes[i].className == name) return that.childNodes[i];
			else {
				var f = this.getElementByClassName(that.childNodes[i], name);
				if(f) return f;
			}
		}
		return false;
	}

	this.copyObjectByVal = function(obj, recursive) {
		var ret = new Object;
		for(var i in obj) {
	        if (recursive && typeof obj[i] == 'object') {
	            ret[i] = window.JSHelpLib.copyObjectByVal(obj[i], recursive);
	        }
	        else ret[i] = obj[i];
		}
	}

	this.eTrackCoords = function(e) {
		window.JSHelpLib.curPos.x = (window.JSHelpLib.isIE()) ? event.clientX : e.pageX;
		window.JSHelpLib.curPos.y = (window.JSHelpLib.isIE()) ? event.clientY : e.pageY;
		if(window.JSHelpLib.curPos.display) self.status = window.JSHelpLib.curPos.x + ' x ' + window.JSHelpLib.curPos.y;
	}

	function mouseCoords(display) {
		this.x = this.y = 0;
		this.display = display;
	
		this.isOver = function(that) {
			if(typeof(that) == 'undefined') return;
			if(that.style.visibilty == 'hidden') return;
			var left = window.JSHelpLib.getLeft(that);
			var top = window.JSHelpLib.getTop(that);
			if(window.JSHelpLib.isIE()) {
				left -= document.body.scrollLeft;
				top -= document.body.scrollTop;
			}
			var right = left + that.offsetWidth;
			var bot = top + that.offsetHeight;
			return (this.x > left) && (this.x < right) && (this.y > top) && (this.y < bot);
		}
	}
}
function JSHelpOffset(x, y) {
	this.x = x;
	this.y = y;
}

function Offset(x, y) {
	return new JSHelpOffset(x, y);
}



function JSHelp(objname) {
	this.objname = objname;
	this.helpalignopts = new Array('topleft', 'topcenter', 'topright', 'midleft', 'midcenter', 'midright', 'botleft', 'botcenter', 'botright');
	this.initflag = false;
	this.helpboxes = new Array();
	this.triggers = new Array();
	this.triggerswap = new Array();
	this.divoffset = new Array();
	this.alignoffset = new Array();
	this.timer;
	this.hide_timeout = 1000;
	this.div_classname = 'divhelp';
	this.offset = new JSHelpOffset(0, 0);
	this.curHelp = '';
	this.triggercount = 0;
	this.lib = window.JSHelpLib;

	this.create = function() {

	}
	this.init = function() {
		// load help messages
		var tmplist = document.getElementsByTagName('div');
		for(var i=0; i<tmplist.length; ++i) {
			if(tmplist[i].className == this.div_classname && tmplist[i].id) this.helpboxes[tmplist[i].id] = tmplist[i];
		}

		// set init flag
		this.initflag = true;
	}

	this.click = function(that, key, align, swapdata) {
		if(typeof(this.helpboxes[key]) == 'undefined') return;
		var thisdiv = this.helpboxes[key];
		if(thisdiv.style.visibility == 'visible') this.doHide(key);
		else this.show(that, key, align, swapdata);
	}
	this.over = function(that) {
		var key = this.getKeyByObj(that);
		if(!key || typeof(this.helpboxes[key]) == 'undefined') return;
		var thisdiv = this.helpboxes[key];
		if(thisdiv.style.visibility == 'visible') {
			clearTimeout(this.timer);
		}
	}
	this.show = function(that, key, align, swapdata) {
		if(!this.initflag) return;
		clearTimeout(this.timer);
		this.doHideAll();

		if(typeof(this.helpboxes[key]) == 'undefined') return;
		var thisdiv = this.helpboxes[key];

		if(!that.id) that.id = 'helptrigger_' + key + ++this.triggercount;
		if(swapdata) {
			this.triggerswap[key] = new Object();
			if(this.isImage(that)) {
				this.triggerswap[key].upImg = new Image(); this.triggerswap[key].upImg.src = that.src;
				this.triggerswap[key].overImg = new Image(); this.triggerswap[key].overImg.src = swapdata;
			}
			else {
				this.triggerswap[key].upClass = that.className;
				this.triggerswap[key].overClass = swapdata;
			}
		}

		this.triggers[key] = that;

		if(typeof(this.triggerswap[key]) != 'undefined') {
			if(this.isImage(that) && this.triggerswap[key].upImg) {
				that.src = this.triggerswap[key].overImg.src;
			}
			else if(this.triggerswap[key].overClass) {
				that.className = this.triggerswap[key].overClass;
			}
		}

		// helpboxalign
		// topleft, topcenter, topright, midleft, midcenter, midright, botleft, botcenter, botright
		if(!align) align = this.helpboxalign;
		align = align.toLowerCase();
		if(!this.lib.in_array(align, this.helpalignopts)) align = this.helpboxalign;
		var alignkey = align;
		var valign = align.substr(0, 3);
		align = align.substr(3);

		var offsetx = this.offset.x;
		var offsety = this.offset.y;
		if(typeof(this.alignoffset[alignkey]) != 'undefined') {
			offsetx = this.alignoffset[alignkey].x;
			offsety = this.alignoffset[alignkey].y;
		}
		if(typeof(this.divoffset[key]) != 'undefined') {
			offsetx = this.divoffset[key].x;
			offsety = this.divoffset[key].y;
		}

		// figure out position
		var postop = posleft = 0;
		var thisdivheight = thisdiv.offsetHeight;
		var thisdivwidth = thisdiv.offsetWidth;

		switch(align) {
			case 'left':
				posleft = this.lib.getLeft(that) - offsetx;
				break;

			case 'center':
				posleft = this.lib.getLeft(that) + (that.offsetWidth / 2);
				posleft -= thisdivwidth / 2;
				break;

			case 'right':
				posleft = this.lib.getLeft(that) + that.offsetWidth;
				posleft -= thisdivwidth - offsetx;
				break;
		}

		switch(valign) {
			case 'top':
				postop = this.lib.getTop(that) - offsety;
				postop -= thisdivheight;
				break;

			case 'mid':
				postop = this.lib.getTop(that) + (that.offsetHeight / 2)
				postop -= thisdivheight / 2;
				if(align == 'left') posleft = this.lib.getLeft(that) - thisdivwidth - offsetx;
				else if(align == 'right') posleft = this.lib.getLeft(that) + that.offsetWidth + offsetx;
				break;

			case 'bot':
				postop = this.lib.getTop(that) + offsety;
				postop += that.offsetHeight;
				break;
		}

		// make sure the help box fits on the screen vertically

		var divbot = postop + thisdivheight;
		var screenbot = document.body.clientHeight + document.body.scrollTop;
		var screentop = screenbot - document.body.clientHeight;
		if(screenbot < divbot) postop = screenbot - thisdivheight - 1;
		else if(postop < screentop) postop = screentop;

		// now make sure it fit's horizontally

		var divright = posleft + thisdivwidth;
		var screenright = document.body.clientWidth + document.body.scrollLeft;
		var screenleft = screenright - document.body.clientWidth;
		if(screenright < divright) posleft = screenright - thisdivwidth - 1;
		else if(posleft < screenleft) posleft = screenleft;

		// position & display
		thisdiv.style.left = posleft;
		thisdiv.style.top = postop;
		thisdiv.left = posleft;
		thisdiv.right = posleft + thisdivwidth;
		thisdiv.top = postop;
		thisdiv.bot = postop + thisdivheight;
		thisdiv.style.visibility = 'visible';
	}
	this.hide = function(that) {
		if(!this.initflag) return;
		var key = this.getKeyByObj(that);
		clearTimeout(this.timer);
		if(this.hide_timeout > 0) this.timer = setTimeout("window."+this.objname+".startDoHide('"+key+"')", this.hide_timeout);
	}

	this.startDoHide = function(key) {
		if(this.lib.curPos.isOver(this.helpboxes[key])) this.hide(this.triggers[key]);
		else this.doHide(key);
	}
	this.doHide = function(key) {
		if(typeof(this.triggers[key]) != 'undefined' && typeof(this.triggerswap[key]) != 'undefined') {
			if(this.isImage(this.triggers[key]) && this.triggerswap[key].upImg) {
				this.triggers[key].src = this.triggerswap[key].upImg.src;
			}
			else if(this.triggerswap[key].upClass) {
				this.triggers[key].className = this.triggerswap[key].upClass;
			}
		}
		if(typeof(this.helpboxes[key]) != 'undefined') this.helpboxes[key].style.visibility = 'hidden';
		else this.doHideAll();
	}
	this.doHideAll = function() {
		for(var k in this.helpboxes) this.doHide(k);
	}

	this.getKeyByObj = function(obj) {
		for(var key in this.triggers) {
			if(obj.id == this.triggers[key].id) return key;
		}
		return '';
	}
	this.isImage = function(that) {
		return(that.tagName == 'IMG' || that.tagName == 'IMAGE');
	}


	this.create();
}

