/*!======================================================================*\
|| #################################################################### ||
|| # vBulletin [#]version[#]
|| # ---------------------------------------------------------------- # ||
|| # Copyright ©2000-[#]year[#] vBulletin Solutions Inc. All Rights Reserved. ||
|| # This file may not be redistributed in whole or significant part. # ||
|| # ---------------- VBULLETIN IS NOT FREE SOFTWARE ---------------- # ||
|| # http://www.vbulletin.com | http://www.vbulletin.com/license.html # ||
|| #################################################################### ||
\*======================================================================*/

//disable suggesting for old versions of safari -- bug #11471
var webkit_version = userAgent.match(/applewebkit\/([0-9]+)/);
var use_suggest = AJAX_Compatible && !(is_saf && !(webkit_version[1] >= 412));

// #############################################################################
// vB_AJAX_Suggest
// #############################################################################

/**
* Base class to handle suggestion lists, refactored from the original
* tag suggest class in vbulletin_ajax_tagsugg.js
*
* @package	vBulletin
* @version	$Revision: 24798 $
* @date		$Date: 2007-11-22 13:59:49 +0000 (Thu, 22 Nov 2007) $
* @author	Mike Sullivan, Kier Darby, Kevin Sours
* @copyright	vBulletin Solutions Inc.
*
* @param	string	Name of variable instantiating this class
* @param	string	ID of the text input element to monitor
* @param	string	Unique key of the popup menu in which to show suggestions
*/
function vB_AJAX_Suggest(varname, textobjid, menukey)
{
	//only do "static" inits here, call base_init from derived classes to handle object init.
	this.xmltag = 'item';
	this.rooturl = '';
}


// =============================================================================
// vB_AJAX_TagSuggest methods

if (use_suggest)
{
	vB_AJAX_Suggest.prototype.base_init = function(varname, textobjid, menukey)
	{
		this.menuobj = YAHOO.util.Dom.get(menukey + "_body");

		//TODO -- temporary remove when style converted.
		if (!this.menuobj)
		{
			this.menuobj = YAHOO.util.Dom.get(menukey + "_menu");
		}

		//if the menu container element isn't there, create it as the last
		//child of the of the parent
		if (!this.menuobj)
		{
			this.menuobj = document.createElement('div');
			this.menuobj.id = menukey + "_body";
			YAHOO.util.Dom.addClass(this.menuobj, 'popupbody'); 
			YAHOO.util.Dom.get(menukey).appendChild(this.menuobj);
		}

		this.textobj = YAHOO.util.Dom.get(textobjid);
		this.textobj.setAttribute("autocomplete", "off");
		this.textobj.onfocus = function(e) { this.obj.active = true; };
		this.textobj.onblur  = function(e) { this.obj.active = false; };
		this.textobj.obj = this;

		/**
		* Varaiables used by this class
		*
		* @var	string	The name given to the instance of this class
		* @var	string	The menu key for the vbmenu name suggestion popup
		* @var	string	The current tag fragment text
		* @var	string	The current string of completed items (Foo ; Bar etc.)
		* @var	string  The primary delimiter
		* @var	array	A list of delimiters for items
		* @var	integer	The currently selected tag index in the menu
		* @var	boolean	Is the suggestion menu open or not
		* @var	object	A javascript timeout marker
		* @var	array	The list of suggested items
		* @var	boolean	True when text box is focussed - only show menu when true
		* @var	object	YUI AJAX Transaction
		*/
		this.set_primary_delimiter(',');
		this.varname = varname;
		this.menukey = menukey;
		this.fragment = '';
		this.doneitems = '';
		this.selected = 0;
		this.menuopen = false;
		this.timeout = null;
		this.items = new Array();
		this.active = false;
		this.ajax_req = null;

		/**
		* Options used by this class
		*
		* @var	boolean	Allow multiple items (Foo, Bar etc.) or just single (Foo)
		* @var	integer	The minimum length of the text fragment before requesting a search
		*/
		this.allow_multiple = false;
		this.min_chars = 3;

		this.textobj.onkeyup = function(e) { return this.obj.key_event_handler(e); };
		this.textobj.onkeypress = function(e)
		{
			e = e ? e : window.event;
			if (e.keyCode == 13)
			{
				return (this.obj.menuopen ? false : true);
			}
		};
	};

	/*** Set base url, so we can run from somewhere other than the root. Like admincp.
	*
	* @param string  the location of the documentroot.
	**/
   vB_AJAX_Suggest.prototype.setrooturl = function(newurl)
	{
		this.rooturl = newurl;
	}

	/**
	* Sets additional delimiters for separating multiple items. A comma will always be used.
	*
	*	For the time being this should be considered a "private" method.  It does not take into 
	* account what happens if additional delimiters have already been set and will, in fact,
	* reset the delimiter list to the primary.
	*
	* @param	string	Primary delimiter
	* @private
	*/
	vB_AJAX_Suggest.prototype.set_primary_delimiter = function(delim)
	{
		this.delim = delim;
		this.delimiters = new Array(this.delim);
	}
	

	/**
	* Sets additional delimiters for separating multiple items. A comma will always be used.
	*
	* @param	string	List of delimiters
	*/
	vB_AJAX_Suggest.prototype.set_delimiters = function(delimiters)
	{
		this.delimiters = new Array(this.delim);

		if (delimiters)
		{
			var delim_matches, i;

			// find all {...} parts first. Parse them and then remove.
			if (delim_matches = PHP.match_all(delimiters, '\{([^}]*)\}'))
			{
				for (i = 0; i < delim_matches.length; i++)
				{
					if (delim_matches[i][1] !== '')
					{
						this.delimiters.push(delim_matches[i][1]);
					}

					delimiters = delimiters.replace(delim_matches[i][0], '');
				}
			}

			// remaining text is just space delimited
			delim_matches = delimiters.split(' ');
			for (i = 0; i < delim_matches.length; i++)
			{
				if (delim_matches[i] !== '')
				{
					this.delimiters.push(delim_matches[i]);
				}
			}
		}
	};

	/**
	* Reads the contents of the text input box
	*/
	vB_AJAX_Suggest.prototype.get_text = function()
	{
		if (this.allow_multiple)
		{
			// search for a delimiter (meaning we have more than one tag in the box)
			var delimpos = -1, delimlen;
			for (var delimid = 0; delimid < this.delimiters.length; delimid++)
			{
				if (this.textobj.value.lastIndexOf(this.delimiters[delimid]) > delimpos)
				{
					delimpos = this.textobj.value.lastIndexOf(this.delimiters[delimid]);
					delimlen = this.delimiters[delimid].length;
				}
			}

			if (delimpos == -1)
			{
				// the current tag is the only one in the text box
				this.doneitems = new String('');
				this.fragment = new String(this.textobj.value);
			}
			else
			{
				// also need to store completed items in the text box
				this.doneitems = new String(this.textobj.value.substring(0, delimpos + delimlen));
				this.fragment = new String(this.textobj.value.substring(delimpos + delimlen));
			}
		}
		else
		{
			this.fragment = new String(this.textobj.value);
		}

		// trim away leading and trailing spaces from the fragment
		this.fragment = PHP.trim(this.fragment);
	};

	/**
	* Sets the contents of the text input box
	*
	* @param	integer	The index of the desired tag in this.items to insert
	*/
	vB_AJAX_Suggest.prototype.set_text = function(i)
	{
		if (this.allow_multiple)
		{
			var extra_space = (this.doneitems.substr(this.doneitems.length - 1) == " " ? "" : " ");
			this.textobj.value = PHP.ltrim(this.doneitems + extra_space + PHP.unhtmlspecialchars(this.items[i]) + this.delim + " ");
		}
		else
		{
			this.textobj.value = PHP.unhtmlspecialchars(this.items[i]);
		}

		this.textobj.focus();
		this.menu_hide();

		return false;
	};

	/**
	* Moves the 'selected' row in the menu
	*
	* @param	integer	Increment (1, -1 etc.)
	*/
	vB_AJAX_Suggest.prototype.move_row_selection = function(increment)
	{
		var newval = parseInt(this.selected, 10) + parseInt(increment, 10);

		if (newval < 0)
		{
			newval = this.items.length - 1;
		}
		else if (newval >= this.items.length)
		{
			newval = 0;
		}

		this.set_row_selection(newval);

		return false;
	};

	/**
	* Sets the 'selected' row in the menu
	*
	* @param	integer	The index of the desired selection (0 - n)
	*/
	vB_AJAX_Suggest.prototype.set_row_selection = function(i)
	{
		var lis = fetch_tags(this.menuobj, 'li');
		if (lis.length)
		{
			lis[this.selected].className = 'vbmenu_option';
			this.selected = i;
			lis[this.selected].className = 'vbmenu_hilite';
		}
	};

	/**
	* Event handler for the text input box key-up event
	*
	* @param	event	The event object
	*/
	vB_AJAX_Suggest.prototype.key_event_handler = function(evt)
	{
		evt = evt ? evt : window.event;

		if (this.menuopen)
		{
			// 38 = up
			// 40 = down
			// 13 = return
			// 27 = escape

			switch (evt.keyCode)
			{
				case 38: // arrow up
				{
					this.move_row_selection(-1);
					return false;
				}
				case 40: // arrow down
				{
					this.move_row_selection(1);
					return false;
				}
				case 27: // escape
				{
					this.menu_hide();
					return false;
				}
				case 13: // return / enter
				{
					this.set_text(this.selected);
					return false;
				}
			}
		}

		// create the fragment
		this.get_text();

		if (this.fragment.length >= this.min_chars)
		{
			clearTimeout(this.timeout);
			this.timeout = setTimeout(this.varname + '.item_search();', 500);
		}
		else
		{
			this.menu_hide();
		}
	};

	/**
	* Sends the fragment to search the database
	*/
	vB_AJAX_Suggest.prototype.item_search = function()
	{
		if (this.active)
		{
			this.items = new Array();

			if (YAHOO.util.Connect.isCallInProgress(this.ajax_req))
			{
				YAHOO.util.Connect.abort(this.ajax_req);
			}

			this.ajax_req = YAHOO.util.Connect.asyncRequest("POST", this.get_search_url(), {
				success: this.handle_ajax_response,
				failure: vBulletin_AJAX_Error_Handler,
				timeout: vB_Default_Timeout,
				scope: this
			}, this.get_search_post());
		}
	};

	//to be overloaded by derived class
	vB_AJAX_Suggest.prototype.get_search_url = function() {};
	vB_AJAX_Suggest.prototype.get_search_post = function() {};

	/**
	* Handles AJAX response
	*
	* @param	object	YUI AJAX
	*/
	vB_AJAX_Suggest.prototype.handle_ajax_response = function(ajax)
	{
		if (ajax.responseXML)
		{
			// ensure that the box we're attached to is still visible before showing this menu
			var node = this.textobj;
			do
			{
				if (node.style.display == 'none')
				{
					this.menu_hide();
					return;
				}
			}
			while ((node = node.parentNode) != null && node.style);

			var items = ajax.responseXML.getElementsByTagName(this.xmltag);
			if (items.length)
			{
				for (var i = 0; i < items.length; i++)
				{
					this.items[i] = items[i].firstChild.nodeValue;
				}
			}

			if (this.items.length)
			{
				this.menu_build();
				this.menu_show();
			}
			else
			{
				this.menu_hide();
			}
		}
	};

	/**
	* Builds the menu html from the list of found items
	*/
	vB_AJAX_Suggest.prototype.menu_build = function()
	{
		//create the popup container if it doesn't exist -- we may have loaded it via ajax 
		//which means the auto register wouldn't take hold.
		if (!YAHOO.vBulletin.vBPopupMenu.popups[this.menukey])
		{
			var popup_menu = new PopupMenu(YAHOO.util.Dom.get(this.menukey), YAHOO.vBulletin.vBPopupMenu);
			YAHOO.vBulletin.vBPopupMenu.register_menuobj(popup_menu);
		}

		//if we did already load it, redo the init.  It could have been loaded via a previous ajax 
		//call, in which case the DOM elements got nuked and recreated and our references aren't 
		//valid.
		
		// 28700: we do not need to redo the init for IE 5 6 7, because we have special DOM
		// manipulation routines (to get around IE's dreaded z-index bug) that make the re-init
		// unneccessary. so if IE 5,6,7, we can leave the PopupMenu object as it is
		else if (!(YAHOO.env.ua.ie > 0 && YAHOO.env.ua.ie < 8))
		{
			var popup_menu = YAHOO.vBulletin.vBPopupMenu.popups[this.menukey];
			popup_menu.init(YAHOO.util.Dom.get(this.menukey), YAHOO.vBulletin.vBPopupMenu);
		}
		
		this.menu_empty();
		var re = new RegExp('^(' + PHP.preg_quote(this.fragment) + ')', "i");

		var ul = document.createElement('ul');
		for (var i in this.items)
		{
			if (YAHOO.lang.hasOwnProperty(this.items, i))
			{
				var li = document.createElement('li');
				li.className = (i == this.selected ? 'vbmenu_hilite' : 'vbmenu_option');
				li.title = 'nohilite';
				li.innerHTML = '<a href="#" onclick="return ' + this.varname + '.set_text(' + i + ')">' +
					this.items[i].replace(re, '<strong>$1</strong>') + '</a>';

				//force a function return to create the closure;
				li.onmouseover = this.get_item_mouseover_handler(i);
				ul.appendChild(li);
			}
		}
		this.menuobj.appendChild(ul);
	};

	vB_AJAX_Suggest.prototype.get_item_mouseover_handler = function (i)
	{
		var bind = this;
		return function () {return bind.set_row_selection(i);};
	};

	/**
	* Empties the menu of all items
	*/
	vB_AJAX_Suggest.prototype.menu_empty = function()
	{
		this.selected = 0;

		while (this.menuobj.firstChild)
		{
			this.menuobj.removeChild(this.menuobj.firstChild);
		}
	};

	/**
	* Shows the menu
	*/
	vB_AJAX_Suggest.prototype.menu_show = function()
	{
		if (this.active)
		{
			YAHOO.vBulletin.vBPopupMenu.popups[this.menukey].open_menu(this.textobj.id);
			this.menuopen = true;
		}
	};

	/**
	* Hides the menu
	*/
	vB_AJAX_Suggest.prototype.menu_hide = function()
	{
		YAHOO.vBulletin.vBPopupMenu.close_all();
		this.menuopen = false;
	};


}
else
{
	// dummy functions to prevent errors
	vB_AJAX_Suggest.prototype.set_delimiters = function(delimiters) {};
}

// #############################################################################
// vB_AJAX_TagSuggest
// #############################################################################
function vB_AJAX_TagSuggest(varname, textobjid, menukey)
{
	if (use_suggest)
	{
		this.base_init(varname, textobjid, menukey);
	}
}

vB_AJAX_TagSuggest.prototype = new vB_AJAX_Suggest();

if (use_suggest)
{
	vB_AJAX_TagSuggest.prototype.get_search_url = function()
	{
		return this.rooturl + "ajax.php?do=tagsearch";
	}

	vB_AJAX_TagSuggest.prototype.get_search_post = function()
	{
		return "securitytoken=" + SECURITYTOKEN + "&do=tagsearch&fragment=" +
			PHP.urlencode(this.fragment);
	}

	vB_AJAX_TagSuggest.prototype.xmltag = 'tag';
}

// #############################################################################
// vB_AJAX_NameSuggest
// #############################################################################
function vB_AJAX_NameSuggest(varname, textobjid, menukey)
{
	if (use_suggest)
	{
		this.base_init(varname, textobjid, menukey);
		//issue 28733, the delimiter for names is a semi colon.
		this.set_primary_delimiter(";");
	}
}

vB_AJAX_NameSuggest.prototype = new vB_AJAX_Suggest();

if (use_suggest)
{
	vB_AJAX_NameSuggest.prototype.get_search_url = function()
	{
		return this.rooturl + "ajax.php?do=usersearch";
	}

	vB_AJAX_NameSuggest.prototype.get_search_post = function()
	{
		return SESSIONURL + "securitytoken=" + SECURITYTOKEN +
			"&do=usersearch&fragment=" + PHP.urlencode(this.fragment);
	}

	vB_AJAX_NameSuggest.prototype.xmltag = 'user';
}

// #############################################################################
// vB_AJAX_NameSuggest
// #############################################################################
function vB_AJAX_SocialGroupSuggest(varname, textobjid, menukey)
{
	if (use_suggest)
	{
		this.base_init(varname, textobjid, menukey);
	}
}

vB_AJAX_SocialGroupSuggest.prototype = new vB_AJAX_Suggest();

if (use_suggest)
{
	vB_AJAX_SocialGroupSuggest.prototype.get_search_url = function()
	{
		return this.rooturl + "ajax.php?do=socialgroupsearch";
	}

	vB_AJAX_SocialGroupSuggest.prototype.get_search_post = function()
	{
		return SESSIONURL + "securitytoken=" + SECURITYTOKEN +
			"&do=socialgroupsearch&fragment=" + PHP.urlencode(this.fragment);
	}

	vB_AJAX_SocialGroupSuggest.prototype.xmltag = 'socialgroup';
}

/*======================================================================*\
|| ####################################################################
|| # Downloaded: [#]zipbuilddate[#]
|| # CVS: $RCSfile$ - $Revision: 15547 $
|| ####################################################################
\*======================================================================*/
