/**
* Wrapper for forumsMenu.register
*
* @param	string	Control ID
* @param	boolean	No image (true)
* @param	boolean	Does nothing any more
*/
function menuRegister(controlid, noimage, datefield) {
	if (typeof forumsMenu == 'object')
	{
		return forumsMenu.register(controlid, noimage);
	}
}


/**
* popup menu registry
*/
function popupHandler() {
	/**
	* Options:
	* @var	integer	Number of steps to use in sliding menus open
	* @var	boolean	Use opacity face in menu open?
	*/
	this.open_steps = 10;
	this.open_fade = false;

	this.active = false;

	this.menus = new Array();
	this.activemenu = null;

	this.hidden_selects = new Array();
};

// =============================================================================
// popupHandler methods

/**
* Activate / Deactivate the menu system
* @param	boolean	Active state for menus
*/
popupHandler.prototype.activate = function(active) {
	this.active = active;
};

/**
* Register a control object as a menu control
* @param	string	ID of the control object
* @param	boolean	Do not add an image (true)
* @return	popupMenu
*/
popupHandler.prototype.register = function(controlkey, noimage) {
	this.menus[controlkey] = new popupMenu(controlkey, noimage);
	return this.menus[controlkey];
};

/**
* Hide active menu
*/
popupHandler.prototype.hide = function() {
	if (this.activemenu != null)
	{
		//this.activemenu.hide();
		this.menus[this.activemenu].hide();
	}
};


// #############################################################################
// initialize menu registry

var forumsMenu = new popupHandler();

/**
* Function to allow anything to hide all menus
* @param	event	Event object
* @return	mixed
*/
function menuHide(e) {
	if (e && e.button && e.button != 1 && e.type == 'click') {
		return true;
	} else {
		forumsMenu.hide();
	}
};

/**
* popup menu class constructor
* Manages a single menu and control object
* Initializes control object
* @param	string	ID of the control object
*/
function popupMenu(controlkey, noimage) {
	this.controlkey = controlkey;
	this.menuname = this.controlkey.split('.')[0] + '_menu';

	this.initControl(noimage);

	if (GetE(this.menuname)) {
		this.initMenu();
	}

	this.slide_open = (is_opera ? false : true);
	this.open_steps = forumsMenu.open_steps;
};

// =============================================================================
// popupMenu methods

/**
* Initialize the control object
*/
popupMenu.prototype.initControl = function(noimage) {
	this.controlobj = GetE(this.controlkey);
	this.controlobj.state = false;

	if (this.controlobj.firstChild && (this.controlobj.firstChild.tagName == 'TEXTAREA' || this.controlobj.firstChild.tagName == 'INPUT')) {
		// do nothing
	} else {
		if (!noimage && !(is_mac && is_ie))	{
			var space = document.createTextNode(' ');
			this.controlobj.appendChild(space);

			var img = document.createElement('img');
			img.src = IMGDIR_MISC + '/menu_open.gif';
			img.border = 0;
			img.title = '';
			img.alt = '';
			this.controlobj.appendChild(img);
		}

		this.controlobj.unselectable = true;
		if (!noimage) {
			this.controlobj.style.cursor = 'pointer';
		}
		this.controlobj.onclick = popupEvents.prototype.controlobjOnclick;
		this.controlobj.onmouseover = popupEvents.prototype.controlobjOnmouseover;
	}
};

/**
* Init the popup menu object
*/
popupMenu.prototype.initMenu = function() {
	this.menuobj = GetE(this.menuname);
	if (this.menuobj && !this.menuobj.initialized) {
		this.menuobj.initialized = true;
		this.menuobj.onclick = eventWay;
		this.menuobj.style.position = 'absolute';
		this.menuobj.style.zIndex = 50;

		// init popup filters (ie only)
		if (is_ie && !is_mac) {
			this.menuobj.style.filter += "progid:DXImageTransform.Microsoft.alpha(enabled=1,opacity=100)";
			this.menuobj.style.filter += "progid:DXImageTransform.Microsoft.shadow(direction=135,color=#8E8E8E,strength=3)";
		}
		//this.initMenuContents();
	}
};

/**
* Init the popup menu contents
*/
popupMenu.prototype.initMenuContents = function() {
	var tds = GetTags(this.menuobj, 'td');
	for (var i = 0; i < tds.length; i++) {
		if (tds[i].className == 'forums_menu_option')
		{
			if (tds[i].title && tds[i].title == 'nohilite')
			{
				// not an active cell
				tds[i].title = '';
			}
			else
			{
				// create a reference back to the menu class
				tds[i].controlkey = this.controlkey;

				// handle mouseover / mouseout highlighting events
				tds[i].onmouseover = popupEvents.prototype.menuoptionOnmouseover;
				tds[i].onmouseout = popupEvents.prototype.menuoptionOnmouseout;

				var links = GetTags(tds[i], 'a');
				if (links.length == 1)
				{
					tds[i].className = tds[i].className + ' forums_menu_option_alink';
					tds[i].islink = true;

					var linkobj = links[0];

					if (typeof linkobj.onclick == 'function')
					{
						tds[i].ofunc = linkobj.onclick;
						tds[i].onclick = popupEvents.prototype.menuoptionOnclickFunction;
					}
					else if (typeof tds[i].onclick == 'function')
					{
						tds[i].ofunc = tds[i].onclick;
						tds[i].onclick = popupEvents.prototype.menuoptionOnclickFunction;
					}
					// this use to be an else statement but Gecko and Opera have a better event system
					// else if (is_saf)
					else
					{
						tds[i].href = linkobj.href;
						tds[i].onclick = popupEvents.prototype.menuoptionOnclickLink;
					}

					if (tds[i].onclick)
					{
						var myspan = document.createElement('span');
						myspan.innerHTML = linkobj.innerHTML;
						tds[i].insertBefore(myspan, linkobj);
						tds[i].removeChild(linkobj);
					}
				}
			}
		}
	}
};

/**
* Show the menu
*
* @param	object	The control object calling the menu
* @param	boolean	Use slide (false) or open instantly? (true)
*/
popupMenu.prototype.show = function(obj, instant) {
	if (!forumsMenu.active)	{
		return false;
	} else if (!this.menuobj) {
		this.initMenu();
	}
	if (!this.menuobj) {
		return false;
	}
	if (forumsMenu.activemenu != null) {
		forumsMenu.menus[forumsMenu.activemenu].hide();
	}
	forumsMenu.activemenu = this.controlkey;
	this.menuobj.style.display = '';
	if (this.slide_open) {
		this.menuobj.style.clip = 'rect(auto, 0px, 0px, auto)';
	}
	this.pos = this.fetchOffset(obj);
	this.leftpx = this.pos['left'];
	this.toppx = this.pos['top'] + obj.offsetHeight;
	if ((this.leftpx + this.menuobj.offsetWidth) >= document.body.clientWidth && (this.leftpx + obj.offsetWidth - this.menuobj.offsetWidth) > 0)
	{
		this.leftpx = this.leftpx + obj.offsetWidth - this.menuobj.offsetWidth;
		this.direction = 'right';
	}
	else
	{
		this.direction = 'left'
	}

	this.menuobj.style.left = this.leftpx + 'px';
	this.menuobj.style.top  = this.toppx + 'px';

	if (!instant && this.slide_open)
	{
		this.intervalX = Math.ceil(this.menuobj.offsetWidth / this.open_steps);
		this.intervalY = Math.ceil(this.menuobj.offsetHeight / this.open_steps);
		this.slide((this.direction == 'left' ? 0 : this.menuobj.offsetWidth), 0, 0);
	}
	else if (this.menuobj.style.clip && this.slide_open)
	{
		this.menuobj.style.clip = 'rect(auto, auto, auto, auto)';
	}

	// deal with IE putting <select> elements on top of everything
	this.handleOverlaps(true);

	if (this.controlobj.editorid)
	{
		this.controlobj.state = true;
		//this.controlobj.editor.menu_context(this.controlobj, 'mousedown');
		forumsEditor[this.controlobj.editorid].menu_context(this.controlobj, 'mousedown');
	}
};

/**
* Hide the menu
*/
popupMenu.prototype.hide = function(e)
{

	if (e && e.button && e.button != 1)
	{
		// get around some context menu issues etc.
		return true;
	}

	this.stopSlide();

	this.menuobj.style.display = 'none';

	this.handleOverlaps(false);

	if (this.controlobj.editorid)
	{
		this.controlobj.state = false;
		//this.controlobj.editor.menu_context(this.controlobj, 'mouseout');
		forumsEditor[this.controlobj.editorid].menu_context(this.controlobj, 'mouseout');
	}

	forumsMenu.activemenu = null;
};

/**
* Hover behaviour for control object
*/
popupMenu.prototype.hover = function(obj)
{
	if (forumsMenu.activemenu != null)
	{
		if (forumsMenu.menus[forumsMenu.activemenu].controlkey != this.id)
		{
			this.show(obj, true);
		}
	}
};

/**
* Slides menu open
*
* @param	integer	Clip X
* @param	integer	Clip Y
* @param	integer	Opacity (0-100)
*/
popupMenu.prototype.slide = function(clipX, clipY, opacity)
{
	if (this.direction == 'left' && (clipX < this.menuobj.offsetWidth || clipY < this.menuobj.offsetHeight))
	{
		if (forumsMenu.open_fade && is_ie)
		{
			opacity += 10;
			this.menuobj.filters.item('DXImageTransform.Microsoft.alpha').opacity = opacity;
		}

		clipX += this.intervalX;
		clipY += this.intervalY;

		this.menuobj.style.clip = "rect(auto, " + clipX + "px, " + clipY + "px, auto)";
		this.slidetimer = setTimeout("forumsMenu.menus[forumsMenu.activemenu].slide(" + clipX + ", " + clipY + ", " + opacity + ");", 0);
	}
	else if (this.direction == 'right' && (clipX > 0 || clipY < this.menuobj.offsetHeight))
	{
		if (forumsMenu.open_fade && is_ie)
		{
			opacity += 10;
			menuobj.filters.item('DXImageTransform.Microsoft.alpha').opacity = opacity;
		}

		clipX -= this.intervalX;
		clipY += this.intervalY;

		this.menuobj.style.clip = "rect(auto, " + this.menuobj.offsetWidth + "px, " + clipY + "px, " + clipX + "px)";
		this.slidetimer = setTimeout("forumsMenu.menus[forumsMenu.activemenu].slide(" + clipX + ", " + clipY + ", " + opacity + ");", 0);
	}
	else
	{
		this.stopSlide();
	}
};

/**
* Abort menu slider
*/
popupMenu.prototype.stopSlide = function()
{
	clearTimeout(this.slidetimer);

	this.menuobj.style.clip = 'rect(auto, auto, auto, auto)';

	if (forumsMenu.open_fade && is_ie)
	{
		this.menuobj.filters.item('DXImageTransform.Microsoft.alpha').opacity = 100;
	}
};

/**
* Fetch offset of an object
*
* @param	object	The object to be measured
*
* @return	array	The measured offsets left/top
*/
popupMenu.prototype.fetchOffset = function(obj)
{
	var left_offset = obj.offsetLeft;
	var top_offset = obj.offsetTop;

	while ((obj = obj.offsetParent) != null)
	{
		left_offset += obj.offsetLeft;
		top_offset += obj.offsetTop;
	}

	return { 'left' : left_offset, 'top' : top_offset };
};

/**
* Detect an overlap of an object and a menu
*
* @param	object	Object to be tested for overlap
* @param	array	Array of dimensions for menu object
*
* @return	boolean	True if overlap
*/
popupMenu.prototype.overlaps = function(obj, m)
{
	var s = new Array();
	var pos = this.fetchOffset(obj);
	s['L'] = pos['left'];
	s['T'] = pos['top'];
	s['R'] = s['L'] + obj.offsetWidth;
	s['B'] = s['T'] + obj.offsetHeight;


	if (s['L'] > m['R'] || s['R'] < m['L'] || s['T'] > m['B'] || s['B'] < m['T'])
	{
		return false;
	}
	return true;
};

/**
* Handle IE overlapping <select> elements
*
* @param	boolean	Hide (true) or show (false) overlapping <select> elements
*/
popupMenu.prototype.handleOverlaps = function(dohide)
{
	if (is_ie)
	{
		var selects = GetTags(document, 'select');

		if (dohide)
		{
			var menuarea = new Array(); menuarea = {
				'L' : this.leftpx,
				'R' : this.leftpx + this.menuobj.offsetWidth,
				'T' : this.toppx,
				'B' : this.toppx + this.menuobj.offsetHeight
			};

			for (var i = 0; i < selects.length; i++)
			{
				if (this.overlaps(selects[i], menuarea))
				{
					var hide = true;
					var s = selects[i];
					while (s = s.parentNode)
					{
						if (s.className == 'forums_menu_popup')
						{
							hide = false;
							break;
						}
					}

					if (hide)
					{
						selects[i].style.visibility = 'hidden';
						arrayPush(forumsMenu.hidden_selects, i);
					}
				}
			}
		}
		else
		{
			while (true)
			{
				var i = arrayPop(forumsMenu.hidden_selects);
				if (typeof i == 'undefined' || i == null)
				{
					break;
				}
				else
				{
					selects[i].style.visibility = 'visible';
				}
			}
		}
	}
};

// #############################################################################
// Menu event handler functions

/**
* Class containing menu popup event handlers
*/
function popupEvents()
{
};

/**
* Handles control object click events
*/
popupEvents.prototype.controlobjOnclick = function(e)
{
	if (typeof doAnEvent == 'function')
	{
		doAnEvent(e);
		if (forumsMenu.activemenu == null || forumsMenu.menus[forumsMenu.activemenu].controlkey != this.id)
		{
			forumsMenu.menus[this.id].show(this);
		}
		else
		{
			forumsMenu.menus[this.id].hide();
		}
	}
};

/**
* Handles control object mouseover events
*/
popupEvents.prototype.controlobjOnmouseover = function(e)
{
	if (typeof doAnEvent == 'function')
	{
		doAnEvent(e);
		forumsMenu.menus[this.id].hover(this);
	}
};

/**
* Handles menu option click events for options with onclick events
*/
popupEvents.prototype.menuoptionOnclickFunction = function(e)
{
	this.ofunc(e);
	forumsMenu.menus[this.controlkey].hide();
};

/**
* Handles menu option click events for options containing links
*/
popupEvents.prototype.menuoptionOnclickLink = function(e)
{
	e = e ? e : window.event;

	if (e.shiftKey)
	{
		window.open(this.href);
	}
	else
	{
		window.location = this.href;
	}

	forumsMenu.menus[this.controlkey].hide();
};

/**
* Handles menu option mouseover events
*/
popupEvents.prototype.menuoptionOnmouseover = function(e)
{
	this.className = 'forums_menu_hilite' + (this.islink ? ' forums_menu_hilite_alink' : '');
	this.style.cursor = pointer_cursor;
};

/**
* Handles menu option mouseout events
*/
popupEvents.prototype.menuoptionOnmouseout = function(e)
{
	this.className = 'forums_menu_option' + (this.islink ? ' forums_menu_option_alink' : '');
	this.style.cursor = 'default';
};
