//
// Copyright (c) 2007-2008 Stardock Systems, Inc.
// Author: Andrew Powell, 10.30.07
// Version 1.0
// Version 1.1 - AAP 06.27.08
// Version 1.2 - AAP 09.03.08
//

Sd.Menus = Class.create();
Sd.Menus.prototype =
{

}

Sd.Menus.Registry = [];
Sd.Menus.slideLength = 200;
Sd.Menus.hideDelay = 500;
Sd.Menus.activityDelay = 2000;
Sd.Menus.minCPUResolution = 10;
Sd.Menus.items = [];

Sd.MenusScript = true;
Sd.MenusTimeout = null;

Sd.Menus.Menu = Class.create();
Sd.Menus.Menu.prototype =
{
	initialize: function (triggerid, id, dir, immediate)
	{
		if(!$id('StardockMenuCss')) Sd.Menus.initCss();

		this.ie = document.all ? 1 : 0;
		this.ns4 = document.layers ? 1 : 0;
		this.dom = document.getElementById ? 1 : 0;
		
		//if true, the menu will render immediately after the target element.
		this.immediate = (immediate == null) ? false : immediate;
		
		this.animate = true;
		
		this.onMenuShow = function(){ };
		this.onMenuVisible = function(){ };
		this.onMenuHide = function(){ };
		this.onMenuHidden = function(){ };
		
		if (this.ie || this.ns4 || this.dom)
		{
			this.triggerid = triggerid;
			this.trigger = $id(this.triggerid);
			this.triggerpos = this.trigger._bounds();
			this.id = id;
			this.dir = dir;
			this.orientation = dir == "left" || dir == "right" ? "h" : "v";
			this.dirType = dir == "right" || dir == "down" ? "-" : "+";
			this.hideTimer = false;
			this.aniTimer = false;
			this.open = false;
			this.over = false;
			this.startTime = 0;
			this.height = 10;
			this.width = 1;
			this.dim = 0; //this.orientation == "h" ? this.width : this.height;
			this.outPos = 0;
			this.gRef = "Sd.Menus_" + id;
			eval(this.gRef+"=this");
			Sd.Menus.Registry[id] = this;

			this.load();
		}
	},

	addItem: function(link, label, onclick, type)
	{
		var menu = this.menu;
		if(menu == null || !menu) return;

		var type = (type == null) ? 'a' : type;
		var item = $new(type);

		if(type == 'a') item.href = link;

		item.innerHTML = label;
		item.onmouseover = new Function("Sd.Menus.clearTimeout('" + this.id + "')");
		item.onmouseout = new Function("Sd.Menus.hideMenu('" + this.id + "')");

		if(onclick && onclick != null && onclick != '')
		{
			if(typeof(onclick) == 'function')
				item.onclick = onclick;
			else
				item.onclick = function(){ eval(onclick); }
		}

		this.items.appendChild(item);

		//var width = this.getElementWidth(item);
		//var height = this.getElementHeight(item);

		//if(width > this.width) this.width = width + 13;

		//this.height += height;

		//this.recalcSize(menu, width, height);
		this.recalcSize();

		return item;

	},

	addHeader: function(text, addToTop)
	{
		var addToTop = (addToTop == null) ? true : addToTop;
		var menu = this.menu; 
		if(menu == null) return;

		var header = $new('div', null, 'header');
		header.innerHTML = text;
		header.onmouseover = new Function("Sd.Menus.clearTimeout('" + this.id + "')");
		header.onmouseout = new Function("Sd.Menus.hideMenu('" + this.id + "')");

		if(this.items.firstChild && addToTop == true)
			this.items.insertBefore(header, this.items.firstChild);
		else
			this.items.appendChild(header);

		var width = this.getElementWidth(header);
		var height = this.getElementHeight(header);

		if(width > this.width) this.width = width + 13;

		this.height += height;

		this.recalcSize(); //menu, width, height);

		return header;

	},

	addSeparator: function()
	{

	},

	recalcSize: function()
	{
		//container.style.height = this.height + 'px';
		//container.style.width = this.width + 'px';
		//container.style.clip = 'rect(0px ' + (this.width) + 'px ' + (this.height) + 'px 0px)';
		this.menu.clip = 'rect(0px ' + (this.menu._bounds().width) + 'px ' + (this.menu._bounds().height) + 'px 0px)';

//		var docRect = this.getDocumentRect();
//
//		if(this.triggerpos.left > docRect.width || (this.triggerpos.left + this.width) > docRect.width)
//		{
//			this.triggerpos.left = docRect.width - this.width - 10;
//			this.menu.style.left = (this.triggerpos.left) + 'px';
//		}

		this.reposition();
		this.resetSlide();

		//set the correct initial state, again, since we're changing it's dimensions.
		//this.endSlide();
	},

	resetSlide: function()
	{
		this.dim = this.orientation == "h" ? this.menu._bounds().width : this.menu._bounds().height;
		this.homePos = eval("0" + this.dirType + this.dim);

		this.accelConst = (this.outPos - this.homePos) / Sd.Menus.slideLength / Sd.Menus.slideLength;
		
		//set the correct initial state, again, since we're changing it's dimensions.
		this.endSlide();
	},

	reposition: function()
	{
		if(!this.trigger) return;
		
		this.triggerpos = this.trigger._bounds();
		this.menu.style.left = (this.triggerpos.left) + 'px';
		this.menu.style.top = (this.triggerpos.top + this.triggerpos.height) + 'px';

		var docRect = this.getDocumentRect();

		if(this.triggerpos.left > docRect.width || (this.triggerpos.left + this.width) > docRect.width)
		{
			this.triggerpos.left = docRect.width - this.width - 10;
			this.menu.style.left = (this.triggerpos.left) + 'px';
		}

		//this.menu.style.zIndex = 99999999;

	},

	load: function()
	{
		var menu = $new('div', this.id, 'StardockMenu');
		var content = $new('div', this.id + '_Content', 'content');
		var items = $new('div', this.id + '_Items', 'items');

		//menu.style.position = 'absolute';
		//menu.style.zIndex = 9999;
		menu.style.left = (this.triggerpos.left) + 'px';
		menu.style.top = (this.triggerpos.top + this.triggerpos.height) + 'px';
		//menu.style.overflow = 'hidden';
		//menu.style.whiteSpace = 'nowrap';

		content.appendChild(items);
		menu.appendChild(content);

		if(!this.immediate)
			document.body.appendChild(menu);
		else
			document.body.insertBefore(menu, document.body.firstChild);

		this.menu = menu;
		this.content = content;
		this.items = items;
		this.style = this.ns4 ? this.content : this.content.style;
//		this.homePos = eval("0" + this.dirType + this.dim);
//		
//		this.accelConst = (this.outPos - this.homePos) / Sd.Menus.slideLength / Sd.Menus.slideLength;

		// set event handlers.
		if (this.ns4) this.content.captureEvents(Event.MOUSEOVER | Event.MOUSEOUT);
		this.content.onmouseover = new Function("Sd.Menus.clearTimeout('" + this.id + "')");
		this.content.onmouseout = new Function("Sd.Menus.hideMenu('" + this.id + "')");

		//set initial state
		//this.endSlide();
		
		this.resetSlide();

	},

	startSlide: function(open)
	{
		this[open ? "onactivate" : "ondeactivate"]();
		this.open = open;
		if (open) this.setVisibility(true);
		
		if(this.animate == true)
		{
			this.startTime = (new Date()).getTime();
			this.aniTimer = window.setInterval(this.gRef + ".slide()", Sd.Menus.minCPUResolution);
		}
		else
		{
			this.endSlide();
		}
	},

	slide: function()
	{
		var elapsed = (new Date()).getTime() - this.startTime;
		if (elapsed > Sd.Menus.slideLength)
			this.endSlide();
		else
		{
			var d = Math.round(Math.pow(Sd.Menus.slideLength-elapsed, 2) * this.accelConst);
			if (this.open && this.dirType == "-") d = -d;
			else if (this.open && this.dirType == "+") d = -d;
			else if (!this.open && this.dirType == "-") d = -this.dim + d;
			else d = this.dim + d;
			this.moveTo(d);
		}
	},

	endSlide: function()
	{
		this.aniTimer = window.clearTimeout(this.aniTimer);
		this.moveTo(this.open ? this.outPos : this.homePos);
		if (!this.open) 
		{
			this.setVisibility(false);
			this.onMenuHidden(this);
		}

		if ((this.open && !this.over) || (!this.open && this.over))
			this.startSlide(this.over);
		else
			this.onMenuVisible(this);
	},

	setVisibility: function(bShow)
	{
		var s = this.ns4 ? this.menu : this.menu.style;

		s.visibility = bShow ? "visible" : "hidden";

	},

	moveTo: function(p)
	{
		this.style[this.orientation == "h" ? "left" : "top"] = this.ns4 ? p : p + "px";
	},

	getPos: function(c)
	{
		return parseInt(this.style[c]);
	},

	onactivate: function() { },
	ondeactivate: function() { },

	getElementHeight: function(elem)
	{
		xPos = elem.offsetHeight;
		return xPos;
	},

	getElementWidth: function(elem)
	{
		xPos = elem.offsetWidth;
		return xPos;
	},

	getDocumentRect: function()
	{
		var w = window;
		var d = w.document, m = d.compatMode == 'CSS1Compat', b = d.body, de = d.documentElement;

		return {
			left : w.pageXOffset || (m ? de.scrollLeft : b.scrollLeft),
			top : w.pageYOffset || (m ? de.scrollTop : b.scrollTop),
			width : w.innerWidth || (m ? de.clientWidth : b.clientWidth),
			height : w.innerHeight || (m ? de.clientHeight : b.clientHeight)
		};
	}
}

	// Makes a Stardock.Menu's items not be cut off in Firefox.
	Sd.Menus.recalcMenuSize = function( menu, item ) 
	{
	   var width = menu.getElementWidth(item)
	   var height = menu.getElementHeight(item);
	
	   if(width > menu.width) menu.width = width + 13;
	
	   menu.height += height;
	
	   menu.recalcSize(menu.menu, width, height);		
	};

	// *** Function : showMenu
	Sd.Menus.showMenu = function(id)
	{
		var reg = Sd.Menus.Registry;
		var obj = Sd.Menus.Registry[id];
		if(!obj || typeof(obj) == 'undefined' || obj == null) return;
		if (obj.menu)
		{
			obj.reposition();
			obj.over = true
			for (menu in reg) if (id != menu)
			{
				Sd.Menus.hide(menu);
				var menuObj = Sd.Menus.Registry[menu];
				if(menuObj && menuObj.onMenuHide) menuObj.onMenuHide(menu);
			}
			
			if (obj.hideTimer) { reg[id].hideTimer = window.clearTimeout(reg[id].hideTimer); }
			if (!obj.open && !obj.aniTimer) 
				reg[id].startSlide(true);

			obj.onMenuShow(obj);

			Sd.MenusTimeout = window.setTimeout("Sd.Menus.hideMenu('" + id + "')", Sd.Menus.activityDelay);
		}
	}

	Sd.Menus.clearTimeout = function(id)
	{
		var reg = Sd.Menus.Registry;
		var obj = Sd.Menus.Registry[id];
		if (obj.hideTimer) { reg[id].hideTimer = window.clearTimeout(reg[id].hideTimer); }
		if(Sd.MenusTimeout) window.clearTimeout(Sd.MenusTimeout);
	}

	Sd.Menus.hideMenu = function(id)
	{
		var obj = Sd.Menus.Registry[id];
		if (obj.menu)
		{
			obj.onMenuHide(obj);
			if (obj.hideTimer) window.clearTimeout(obj.hideTimer);
			obj.hideTimer = window.setTimeout("Sd.Menus.hide('" + id + "')", Sd.Menus.hideDelay);
		}
	}

	Sd.Menus.hideAll = function()
	{
		var reg = Sd.Menus.Registry;
		for (menu in reg)
		{
			Sd.Menus.hide(menu);
			if (menu.hideTimer) window.clearTimeout(menu.hideTimer);
		}
	}

	Sd.Menus.hide = function(id)
	{
		var obj = Sd.Menus.Registry[id];
		obj.over = false;
		if (obj.hideTimer) window.clearTimeout(obj.hideTimer);
		obj.hideTimer = 0;
		if (obj.open && !obj.aniTimer) obj.startSlide(false);
	}

	Sd.Menus.initCss = function(id)
	{
		//initialize the default css for the menu. These shouldn't be overriden. Instead the customCssClassPrefix parameter
		//should be used in the menu constructor.
		var css =
			'.StardockMenu { margin-top: 2px; white-space: nowrap; position: absolute; z-index: 9999; overflow: hidden; }' +
			'.StardockMenu .content { background:transparent; padding: 1px; position: relative; }' +
			'.StardockMenu .content .items { border:1px solid #333; background: white; }' +
			'.StardockMenu .content .items a { color:#333; display:block; padding:2px 10px; text-decoration:none; background:transparent; }' +
			'.StardockMenu .content .items a:hover { background-color:#666; color:#fff; }' +
			'.StardockMenu .content .items .header { color:#fff; background-color:#333; padding:2px 10px; font-size: 11px; }';

		var head = document.getElementsByTagName('head')[0];
		var styleTag = document.createElement('style');
		styleTag.id = 'StardockMenuCss';

		styleTag.setAttribute("type", "text/css");

		if(styleTag.styleSheet)	// IE
		{
			styleTag.styleSheet.cssText = css;
			head.insertBefore(styleTag, head.childNodes(0));
		}
		else	// w3c
		{
			var cssText = document.createTextNode(css);
			styleTag.appendChild(cssText);
			head.insertBefore(styleTag, head.childNodes[0]);
		}
		
	}



