Enjin_Core = { };
Enjin_UI = { };

Enjin_Core.favicon = {
	favicon_url: '',
		
	init: function() {
		if (jQuery.browser.mozilla) { 
			//get current favicon
			this.favicon_url = '';
			var self = this;
			
			$('head link').each(function() {
				var is_attr = ($(this).attr('rel') == 'shortcut icon');
				if (is_attr) {
					self.favicon_url = $(this).attr('href');
				}
			});			
		}
	},
	fix: function() {
		if (this.favicon_url != '') {
			var html = '<link href="'+ this.favicon_url +'" rel="shortcut icon" type="image/x-icon" />'
					+ '<link href="'+ this.favicon_url +'" rel="icon" type="image/x-icon" />';
			//force to update the head icon
			$('head link[rel=icon]').remove();
			$(html).appendTo('head');
		}
	}
}

///Enjin_Core.MAX_ZINDEX = 2147483580;
Enjin_Core.MAX_ZINDEX = 19999;
Enjin_Core._popup_separator = null;
Enjin_Core.floor = function(value, decimals) {
	var base = Math.pow(10, decimals)*1.0; 
	value *= base;
	value = Math.floor(value);
	value /= base;
	
	return value;
}

Enjin_Core.checkMaxChars = function(element, max_length) {
	var length = $(element).val().length;
	
	if (length >= max_length) {
		var trimmed = $(element).val().substr(0, max_length);
		$(element).val(trimmed);
		return false;
	}
	
	return true;
}

Enjin_Core.limitMaxChars = function(element, max_length) {
	$(element).bind('keyup', function() {
        Enjin_Core.checkMaxChars(element, max_length);
	});
}

/* from phpjs */
Enjin_Core.__html_translation_table = null;
Enjin_Core.prepare_html_translation_table = function(table, quote_style) {
	if (Enjin_Core.__html_translation_table)
		return; //avoid memory usage
	
    // http://kevin.vanzonneveld.net
    // +   original by: Philip Peterson
    // +    revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   bugfixed by: noname
    // +   bugfixed by: Alex
    // +   bugfixed by: Marco
    // +   bugfixed by: madipta
    // +   improved by: KELAN
    // +   improved by: Brett Zamir (http://brett-zamir.me)
    // +   bugfixed by: Brett Zamir (http://brett-zamir.me)
    // +      input by: Frank Forte
    // +   bugfixed by: T.Wild
    // +      input by: Ratheous
    // %          note: It has been decided that we're not going to add global
    // %          note: dependencies to php.js, meaning the constants are not
    // %          note: real constants, but strings instead. Integers are also supported if someone
    // %          note: chooses to create the constants themselves.
    // *     example 1: get_html_translation_table('HTML_SPECIALCHARS');
    // *     returns 1: {'"': '&quot;', '&': '&amp;', '<': '&lt;', '>': '&gt;'}
    
    var entities = {}, hash_map = {}, decimal = 0, symbol = '';
    var constMappingTable = {}, constMappingQuoteStyle = {};
    var useTable = {}, useQuoteStyle = {};
    
    // Translate arguments
    constMappingTable[0]      = 'HTML_SPECIALCHARS';
    constMappingTable[1]      = 'HTML_ENTITIES';
    constMappingQuoteStyle[0] = 'ENT_NOQUOTES';
    constMappingQuoteStyle[2] = 'ENT_COMPAT';
    constMappingQuoteStyle[3] = 'ENT_QUOTES';

    useTable       = !isNaN(table) ? constMappingTable[table] : table ? table.toUpperCase() : 'HTML_SPECIALCHARS';
    useQuoteStyle = !isNaN(quote_style) ? constMappingQuoteStyle[quote_style] : quote_style ? quote_style.toUpperCase() : 'ENT_COMPAT';

    if (useTable !== 'HTML_SPECIALCHARS' && useTable !== 'HTML_ENTITIES') {
        throw new Error("Table: "+useTable+' not supported');
        // return false;
    }

    entities['38'] = '&amp;';
    if (useTable === 'HTML_ENTITIES') {
        entities['160'] = '&nbsp;';
        entities['161'] = '&iexcl;';
        entities['162'] = '&cent;';
        entities['163'] = '&pound;';
        entities['164'] = '&curren;';
        entities['165'] = '&yen;';
        entities['166'] = '&brvbar;';
        entities['167'] = '&sect;';
        entities['168'] = '&uml;';
        entities['169'] = '&copy;';
        entities['170'] = '&ordf;';
        entities['171'] = '&laquo;';
        entities['172'] = '&not;';
        entities['173'] = '&shy;';
        entities['174'] = '&reg;';
        entities['175'] = '&macr;';
        entities['176'] = '&deg;';
        entities['177'] = '&plusmn;';
        entities['178'] = '&sup2;';
        entities['179'] = '&sup3;';
        entities['180'] = '&acute;';
        entities['181'] = '&micro;';
        entities['182'] = '&para;';
        entities['183'] = '&middot;';
        entities['184'] = '&cedil;';
        entities['185'] = '&sup1;';
        entities['186'] = '&ordm;';
        entities['187'] = '&raquo;';
        entities['188'] = '&frac14;';
        entities['189'] = '&frac12;';
        entities['190'] = '&frac34;';
        entities['191'] = '&iquest;';
        entities['192'] = '&Agrave;';
        entities['193'] = '&Aacute;';
        entities['194'] = '&Acirc;';
        entities['195'] = '&Atilde;';
        entities['196'] = '&Auml;';
        entities['197'] = '&Aring;';
        entities['198'] = '&AElig;';
        entities['199'] = '&Ccedil;';
        entities['200'] = '&Egrave;';
        entities['201'] = '&Eacute;';
        entities['202'] = '&Ecirc;';
        entities['203'] = '&Euml;';
        entities['204'] = '&Igrave;';
        entities['205'] = '&Iacute;';
        entities['206'] = '&Icirc;';
        entities['207'] = '&Iuml;';
        entities['208'] = '&ETH;';
        entities['209'] = '&Ntilde;';
        entities['210'] = '&Ograve;';
        entities['211'] = '&Oacute;';
        entities['212'] = '&Ocirc;';
        entities['213'] = '&Otilde;';
        entities['214'] = '&Ouml;';
        entities['215'] = '&times;';
        entities['216'] = '&Oslash;';
        entities['217'] = '&Ugrave;';
        entities['218'] = '&Uacute;';
        entities['219'] = '&Ucirc;';
        entities['220'] = '&Uuml;';
        entities['221'] = '&Yacute;';
        entities['222'] = '&THORN;';
        entities['223'] = '&szlig;';
        entities['224'] = '&agrave;';
        entities['225'] = '&aacute;';
        entities['226'] = '&acirc;';
        entities['227'] = '&atilde;';
        entities['228'] = '&auml;';
        entities['229'] = '&aring;';
        entities['230'] = '&aelig;';
        entities['231'] = '&ccedil;';
        entities['232'] = '&egrave;';
        entities['233'] = '&eacute;';
        entities['234'] = '&ecirc;';
        entities['235'] = '&euml;';
        entities['236'] = '&igrave;';
        entities['237'] = '&iacute;';
        entities['238'] = '&icirc;';
        entities['239'] = '&iuml;';
        entities['240'] = '&eth;';
        entities['241'] = '&ntilde;';
        entities['242'] = '&ograve;';
        entities['243'] = '&oacute;';
        entities['244'] = '&ocirc;';
        entities['245'] = '&otilde;';
        entities['246'] = '&ouml;';
        entities['247'] = '&divide;';
        entities['248'] = '&oslash;';
        entities['249'] = '&ugrave;';
        entities['250'] = '&uacute;';
        entities['251'] = '&ucirc;';
        entities['252'] = '&uuml;';
        entities['253'] = '&yacute;';
        entities['254'] = '&thorn;';
        entities['255'] = '&yuml;';
    }

    entities['60'] = '&lt;';
    entities['62'] = '&gt;';    


    // ascii decimals to real symbols
    for (decimal in entities) {
        symbol = String.fromCharCode(decimal);
        hash_map[symbol] = entities[decimal];
    }
    
    hash_map["'"] = '&#039;';
    Enjin_Core.__html_translation_table =  hash_map;
}

//fast and "enough version"
Enjin_Core.htmlentities = function(string, quote_style) {	
	return string
			.replace(/&/g, '&amp;')
			.replace(/</g, '&lt;')
			.replace(/>/g, '&gt;')
			.replace(/"/g, '&quot;')
			.replace(/'/g, '&#039;');
			
}

/* from phpjs */
Enjin_Core.html_entity_decode = function(str) {
	var chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
	var random_separator;
	var code;
	var cp;
	
	do {
		code = '';
		for (i=0; i<5; i++) {
			cp = parseInt(Math.random() * chars.length);
			code += chars.substr(cp, 1);
		}
		
		random_separator = '@'+code+'@';
	} while (str.indexOf(random_separator) != -1);
	
	
	  var ta=document.createElement("textarea");
	  ta.innerHTML=str.replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(new RegExp("\n", 'g'), random_separator);	  
	  return ta.value.replace(new RegExp(random_separator, 'g'), "\n");
}

Enjin_Core.alert = function(title, options) {
	if (!options)
		options = {};
	
	var opts = {};
	$.extend(opts, {
		callback: function() {}, /* doing nothing on call since will be the swf upload part */
		cancel_click_document: true
	}, options, {
		//values that cannot be changed
		message: title,
		button_continue: 'Ok',
		scope: this
	});
	
	Enjin_Core.showMessagePopup(opts);
}

Enjin_Core._popup = null;
Enjin_Core.showMessagePopup = function(options) {
	var middle = 0;
	var _options = {
		top: null,
		message: '',
		button_continue: 'Ok',
		callback: null
	};
	jQuery.extend(_options, options);
	
	if (Enjin_Core._popup)
		Enjin_Core.cancelPopup();
	
	var html = '<div class="delete-comment element_popup hidden">\
		<div class="inner inner-message">\
			<span class="message">'+_options.message+'</span><br><br>\
			<div class="element_button"><div class="l"><!-- --></div><div class="r"><!-- --></div><input type="button" value="'+_options.button_continue+'" class="btncontinue"></div>\
		</div>\
	</div>';
	
	Enjin_Core._popup = $(html);
		
	Enjin_Core._popup.appendTo($(document.body));
	
	Enjin_Core.createPopupSeparator();
	Enjin_Core.placeAfterPopupSeparator(Enjin_Core._popup);
	
	
	//position	
	if (_options.top == null) {
		_options.top = $(window).scrollTop() +
						($(window).height() - Enjin_Core._popup.height())*0.5;
	}	
	Enjin_Core._popup.css('top', _options.top);
	
	middle = ($(document.body).width() - Enjin_Core._popup.width())*0.5;	
	Enjin_Core._popup.css('left', middle);
	Enjin_Core._popup.show();
	
	Enjin_Core._popup.find('input[type=button].btncontinue').click(function(){
		Enjin_Core.cancelPopup();
		
		if (_options.callback)
			_options.callback.apply(_options.scope);
	});
}

/**
 * Show a popup window with a single input field in the body, ala JS prompt() method
 * The callback for the popup must take a single param, which will be the value of the input field, e.g
 *
 *   Enjin_Core.showPromptPopup({
 *                                 message: 'Field label',
 *                                 value: 'input default value',
 *								   width: force width of the input							
 *								   type: 'input field type attr (e.g. password), default: text',
 *                                 callback: function(input_value) { alert('You typed ' + input_value + ' in the input field'); }
 *                             });
 *
 */
Enjin_Core.showPromptPopup = function(options) {

    // the message is the input field DOM
	var type = ( typeof options.type !== 'undefined' ? options.type : 'text' );
    options.message1 = '<input type="' + type + '" class="popup-prompt-input" value="' + ( typeof options.value !== 'undefined' ? options.value : '' ) + '">';
    
    // call the callback before we destory the popup DOM so the callback can extract the user value from the input field
    options.callbackFirst = true;
    
    // we need to intercept the user-defined callback function and put a step before it to first extract the 
    // input value, and then execute the original callback with the input value as a parameter
    var redirect = options.callback;
    options.callback = function() { var value = $('.element_popup .popup-prompt-input').val(); redirect(value); } 
    
    var popup = Enjin_Core.showPopup(options);
	if ( typeof options.width !== 'undefined' ) { popup.find('.popup-prompt-input').css({width:options.width}); }
}

/**
 *
 * Display a generic window style popup, with a title bar and an X icon to close window
 *
 *   Enjin_Core.showWindowPopup({
 *                                 title: 'windox title',
 *                                 closable: true|false,		// optional - true to show X close icon
 *								   modal: true|false,  			// true to show popup seperator
 *								   content: string|JQuery,		// window body content
 *								   button_text: 'Ok'			// Ok button text	
 *								   footer: string|JQuery		// content show in the footer to left of Ok button
 *								   cancel_link:true|false		// default true, show "or Cancel" link to cancel window
 *								   cancel_click_document:true|false		// default true, clicking document body will cancel window
 *                                 callback: function			// called on click of the OK button, return true to close popup
 *								   form:
 *                             });
 */
Enjin_Core.showWindowPopup = function(options)
{
	var _options = {title:'',closable:true, modal:true, button_text:'OK', cancel_link:true, cls:'', cancel_click_document:true};
	$.extend(_options, options);
	var window = $('<div class="element_popup element_popup_core element_popup_window '+_options.cls+'"><div class="inner"></div></div>');
	var inner = window.find('.inner');
	inner.addClass('window-frame');
	
	var title = $("'<div class='popup_window_title'></div>");
	title.text(_options.title);
	if ( _options.closable )
	{
		title.append('<a class="close" href="#" onclick="Enjin_Core.cancelPopup();return false;"></a>');
	}

	inner.append(title);
	
	var content = $('<div class="content"></div>').append(_options.content);
	inner.append( content );
	
	if ( _options.hideFooter !== true )
	{
		var footer = $("<div class='footer'><div class='content-footer'></div><div class='buttons'></div></div>");
		if ( _options.footer ) { footer.find('.content-footer').append(_options.footer); }
		
		var okClick = function()
						{
							var form = {};
							var formEl = $(this).closest('.element_popup_window').find('form');
							if ( formEl.valid() )
							{
								$(this).closest('.element_popup_window').find('.content form :input').each( function() { form[$(this).attr('name')] = $(this).val(); } );
								_options.callback(form,formEl);
							}	
						};
		
		var buttons = Enjin_UI.button({value:_options.button_text, click:okClick});
		if ( _options.cancel_link ) { buttons.insertAfter('&nbsp; or &nbsp;<a href="javascript:void(0);" class="cancel" onclick="Enjin_Core.cancelPopup(true)">Cancel</a>'); }
		footer.find('.buttons').append( buttons );

		inner.append(footer);

		inner.find('form :input').keypress( function(event) { if ( event.which == 13 ) { $(this).closest('.element_popup_window').find('.footer input[type=button]').click(); } } );
	}
	
	window.appendTo($(document.body));
	Enjin_Core._popup = window;
	
	Enjin_Core.showCustomPopup(window,{center:true, use_separator:options.modal});

	
	// reindex the form field tab order to ensure that tabbing through fields on this form go in order
	$('body').applyTabIndex();
	return window;
}

/**
 *
 * Shows the login window
 *
 * Enjin_Core.showLoginPopup({
 *								site_name: string	// name of the site
 *							});
 */
Enjin_Core.showLoginPopup = function(options)
{
	if ( typeof options === "string" ) { options = {site_name:options}; }
	
	options.cls = 'login-window';
	options.button_text = 'Login';
	options.content = '<div>';
	if ( typeof options.msg !== 'undefined' ) { options.content += '<div class="msg-text">' + options.msg + '</div>'; }
	options.content += '<form>' +
						 '<div class="label">Email</div>' +
						 '<div><div class="input-text"><input type="text" name="username" tabindex="1"/></div></div>' +
						 '<div class="label">Password<span><a href="/login/do/forgotpass">Forgot password?</a></span></div>' +
						 '<div class="input-text"><input type="password" name="password" tabindex="2" /></div>' +
						'</form></div>';					
	if ( options.site_name.length > 24 ) { options.site_name = options.site_name.substr(0,24) + '...'; }
	options.title = "Login to " + options.site_name;
	
	options.footer = 'Don\'t have an account? <a href="/login/do/register">Register</a>';	
	options.callback = function( form, formEl )
					   {
						  form.cmd = 'login';
						  $.post( '/ajax.php?s=login'
								 ,form
								 ,function(result) 
									{
										if ( result.success )
										{
											window.location.reload(true);
											return true;
										}
										else
										{
											var validator = formEl.validate();
											if ( result.error_email )
											{
												validator.showErrors({username:result.error_email});
											}
											else
											{
												validator.showErrors({password:result.error_password});
											}
										}
										
										return false;
									}
								 ,'json'
								);
						  return false;
					   };
					  
	Enjin_Core.showWindowPopup(options); 

	$('.login-window form').error( {rules:{username:'required',password:'required'}, hideError:true} );
	$('.login-window input[name=username]').focus();
	
	return false;
}

Enjin_Core.joinWebsiteApproval = function(event)
{
	event.cancelBubble = true;
	if (event.stopPropagation) event.stopPropagation();		
	Enjin_Core.showPopup({message:'This website requires an administrator to approve your registration.<br/>You will be sent an email when approved',
	
						  callback:function() { document.location.href = "/login/do/joinsite"; }
						});
}

Enjin_Core.showCustomPopup = function(popup, params) {
	params = $.extend({
		center: true,
		top: null, //to center
		use_scrolltop: true,
		use_separator: true
	}, params);
	
	if (typeof popup == 'string') //selector
		popup = $(popup);
	
	if (params.use_separator) {
		Enjin_Core.createPopupSeparator();
		Enjin_Core.placeAfterPopupSeparator(popup);
	}
	
	if (params.center) {
		Enjin_Core.centerPopup(popup, params.top, params.use_scrolltop);
	}
	
	popup.show();
}

Enjin_Core.hideCustomPopup = function(popup) {
	if (typeof popup == 'string') //selector
		popup = $(popup);
	
	Enjin_Core.removePopupSeparator();
	popup.hide();
}

Enjin_Core.centerPopup = function(popup, top, use_scrolltop) {
	if (typeof use_scrolltop == 'undefined')
		use_scrolltop = true;
	
	var window_top = 0;
	if (use_scrolltop)
		window_top = $(window).scrollTop();
	
	if (top == null) {
		//console.log("T: "+$(window).height()+" -- "+popup.height());
		top = window_top + ($(window).height() - popup.height())*0.5;
	} else {
		top = window_top + top;
	}
	popup.css('top', top);
	
	middle = ($(document.body).width() - popup.width())*0.5;	
	popup.css('left', middle);	
}

Enjin_Core.showPopup = function(options) {
	var middle = 0;
	var html_title = ''; 
	var _options = {
		top: null,
		message: '',
		message1: '',
		button_continue: 'Ok',
		focus_button: false,
		scope: this,
		params: [],
		callback: function() {},
		callback_cancel: function() {},
		cancel_click_document: true,
		callbackFirst: false                // if true the continue callback will be called before the popup DOM is destroyed
	};
	jQuery.extend(_options, options);
	
	if (Enjin_Core._popup)
		Enjin_Core.cancelPopup();

	var html = '<div class="delete-comment element_popup element_popup_core hidden">\
		<div class="inner">\
			<span class="message">'+_options.message+'</span><br><br>\
			|@extra@|\
			<div class="element_button"><div class="l"><!-- --></div><div class="r"><!-- --></div><input type="button" value="'+_options.button_continue+'" class="btncontinue"></div>&nbsp; or &nbsp;<a href="javascript:void(0);" class="cancel" onclick="Enjin_Core.cancelPopup(true)">Cancel</a>\
		</div>\
	</div>';
		
	if (_options.message1 != "") {
		html_title = '<span class="message1">'+_options.message1+'</span><div class="clearing"></div><br>';
	}
	
	html = html.replace('|@extra@|', html_title);
	
	//prepare base
	Enjin_Core._popup_separator = Enjin_Core.createPopupSeparator();
	
	Enjin_Core._popup = $(html); 
	Enjin_Core._popup.appendTo($(document.body));
	
	//position	
	if (_options.top == null) {
		_options.top = $(window).scrollTop() + 
						($(window).height() - Enjin_Core._popup.height())*0.5;
	}
	if(_options.top < 0) _options.top = 30;
	Enjin_Core._popup.css('top', _options.top);
	
	
	middle = ($(document.body).width() - Enjin_Core._popup.width())*0.5;	
	Enjin_Core._popup.css('left', middle);
	Enjin_Core._popup.show();
	Enjin_Core._popup._options = _options;
	Enjin_Core.placeAfterPopupSeparator(Enjin_Core._popup);
	
	if(_options.focus_button) {
		Enjin_Core._popup.find('input.btncontinue').focus();
	}
	
	Enjin_Core._popup.find('input[type=button].btncontinue').click(function(){
	    if ( _options.callbackFirst === true )
	    {
		    _options.callback.apply(_options.scope, _options.params);
		    Enjin_Core.cancelPopup();
	    }
	    else
	    {
		    Enjin_Core.cancelPopup();
		    _options.callback.apply(_options.scope, _options.params);
        }		    
	});
	
	if (_options.cancel_click_document) {
		$(document).bind("click", Enjin_Core._waitPopupClick);	
	} else {
		//needed to remove the previous binding
		$(document).unbind("click", Enjin_Core._waitPopupClick);
	}
	
	return Enjin_Core._popup;
}

Enjin_Core._waitPopupClick = function(event) {
	if($(event.target).closest('.element_popup_core').length == 0)
		Enjin_Core.cancelPopup(true);
}

Enjin_Core.createPopupSeparator = function(callback) {
	if (Enjin_Core._popup_separator) {
		return Enjin_Core._popup_separator; //already created
	}
	
	var separator = $('<div class="s_popup-canvas-separator">&nbsp;</div>')
				.css('width', $(document).width())
				.css('height', $(document).height())
				.appendTo(document.body);
	
	$(window).bind('resize', function() {
		separator.css('width', $(document).width());
		separator.css('height', $(document).height());		
	});
	
	if (callback) {
		separator.bind('click', function(response) {
			separator.unbind('click');
			callback.apply();
		});
	}
	
	Enjin_Core._popup_separator = separator;	
	return separator;
}

Enjin_Core.placeAfterPopupSeparator = function(el, index) {
	if (!index)
		index = Enjin_Core.MAX_ZINDEX+1;
	
	el = $(el);
	el.css('zIndex', index);
	el.appendTo($(document.body));
}

Enjin_Core.removePopupSeparator = function() {
	if (Enjin_Core._popup_separator) {
		Enjin_Core._popup_separator.remove();
		Enjin_Core._popup_separator = null;
	}
}

Enjin_Core.cancelPopup = function(callback) {
	var docall = false;
	$(document).unbind("click", Enjin_Core._waitPopupClick);
	
	if (callback && Enjin_Core._popup) {
		docall = $.extend(Enjin_Core._popup._options, {}); //copy		
	}
	
	if (Enjin_Core._popup) {
		Enjin_Core._popup.remove();
		Enjin_Core._popup = null;
	}
	
	Enjin_Core.removePopupSeparator();
	
	if (docall) {
		docall.callback_cancel.apply(
				docall.scope, 
				docall.params);		
	}
}

Enjin_Core.centerPopupSimple = function(element) {
	var t = $(window).scrollTop() + ($(window).height() - element.height())*0.5;
	var l = ($(document.body).width() - element.width())*0.5;
	element.css({'top': t, 'left': l});	
}

Enjin_Core.limitText = function(limitField, limitNum) {
	if ($(limitField).val().length > limitNum) {
		$(limitField).val($(limitField).val().substring(0, limitNum));
	}
}

Enjin_Core.buttonState = function(button, state)
{
	if(state == false)
	{
		button.attr('disabled', 'disabled');
		button.parent().addClass('disabled');
	}
	else
	{
		button.removeAttr('disabled');
		button.parent().removeClass('disabled');
	}
}


Enjin_Core._anchorState = {};
Enjin_Core.prepareState = function() {
	var curl = document.location.toString();
	if (curl.match('#')) { // the URL contains an anchor
	  var anchors = curl.split('#');
	  anchors.shift();
	  
	  jQuery.each(anchors, function() {
		  if (this == '#')
			  return; //nothing to do
		  
		  var info = this.split('_');
		  var i=1;
		  var iid = info[1];
		  Enjin_Core._anchorState[iid] = {
				  params: {},
				  anchor: this
		  };
		  
		  
		  for (i=1; i<info.length; i++) {
			  var name = info[i];
			  var value = null; 
			  
			  if (i+1 < info.length)
				  value = info[i+1];
			  
			  Enjin_Core._anchorState[iid][name] = value;
		  }
		  
		  //simulate clicks on anchor		  
		  $('a[href="#' + this + '"]').click();
	  });
	}	
}
Enjin_Core.getState = function(module) {
	if ( Enjin_Core._anchorState[module] ) {
		return Enjin_Core._anchorState[module];
	}
	
	return null;
}

Enjin_Core.disableButton = function(input, seconds, disabledText) {
	if(disabledText != undefined) {
		var origText = $(input).val();
		$(input).val(disabledText);
	}
	
	function reenableButton()
	{
		$(input).removeAttr('disabled');
		$(input).parent().removeClass('disabled');
		if(disabledText != undefined) $(input).val(origText);
	}
	
	$(input).attr('disabled', true);
	$(input).parent().addClass('disabled');
	setTimeout(reenableButton, seconds*1000);
}

/*
 * Dropdown Menu
 */
Enjin_Core.dd_timeout = 500;
Enjin_Core.dd_closetimer = 0;
Enjin_Core.dropdownMenu = function(items, button, cclass, right, xOffset) {
	Enjin_Core.dd_canceltimer();
	$('.element_dropdown_menu').remove();
	
	if(cclass != undefined) var cssClass = ' ' + cclass;
	else var cssClass = '';
	
	var html = '<div class="element_popup element_dropdown_menu' + cssClass + '">\
		<div class="inner">\
			<ul>';

	var bindFunctions = [];
	var bindCount = 0;
	for(i in items) {
		if(items[i][0] != undefined)
		{
			if(items[i][1] == 'html') {
				html += '<li>' + items[i][0] + '</li>';
			}
			else if(items[i][1] == 'divider') {
				html += '<li><div class="menu-divider-line"></div></li>';
			}
			else {
				var target = '';
				if(items[i][2] == 1) target = ' target="_blank"';
				// functions to be bound on click
				if(items[i][3] != undefined) {
					bindFunctions.push(items[i][3]);
					var bindRef = ' bindref-' + bindCount;
					bindCount++;
				}
				else bindRef = '';
				html += '<li><a class="menu-link' + bindRef + '" href=\"' + items[i][1] + '\"' + target + '>' + items[i][0] + '</a></li>';
			}
		}
	}
	
	html += '</ul>\
		</div>\
	</div>';
	
	var alignside = 'left';
	if(right != undefined && right == true) alignside = 'right';
	if(xOffset == undefined) xOffset = 0;
	
	var popup = $(html);
	// bind any onclick functions if they exist
	if(bindCount > 0) {
		for(var i=0; i<bindCount; i++) {
			var btn = popup.find('.bindref-' + i);
			btn.data('bindClick', bindFunctions[i]);
			btn.bind('click', function(ev){$(this).data('bindClick')(); return false;});
		}
	}

	if(right != undefined && right == true)
		popup.css({'top': $(button).offset().top + $(button).height(), 'right': $(window).width() - $(button).offset().left - $(button).width() + xOffset});
	else
		popup.css({'top': $(button).offset().top + $(button).height(), 'left': $(button).offset().left + xOffset});
	popup.bind('mouseleave', function(e){
		Enjin_Core.dd_timer();
	});
	popup.bind('mouseenter', Enjin_Core.dd_canceltimer);
	
	$(button).unbind('mouseleave');
	$(button).bind('mouseleave', function(e){
		if(!(e.pageX > $(button).offset().left
		&& e.pageX < $(button).offset().left + $(button).width()
		&& e.pageY > $(button).offset().top)) Enjin_Core.dd_timer();
	});
	
	$('body').prepend(popup);
}
Enjin_Core.dd_close = function() {
	$('.element_dropdown_menu').remove();
}

Enjin_Core.dd_timer = function() {
	Enjin_Core.dd_closetimer = window.setTimeout(Enjin_Core.dd_close, Enjin_Core.dd_timeout);
}
Enjin_Core.dd_canceltimer = function() {
	if(Enjin_Core.dd_closetimer) {
		window.clearTimeout(Enjin_Core.dd_closetimer);
		Enjin_Core.dd_closetimer = null;
	}
}



/* Trial Plan */
Enjin_Core.startTrial = function() {
	$.post("/ajax.php?s=signup", { cmd: 'start-trial' },
		function(data){
			document.location = location.href;
		}
	);
}
Enjin_Core.declineTrial = function() {
	$.post("/ajax.php?s=signup", { cmd: 'decline-trial' },
		function(data){
			$('.trial_popup').fadeOut(400);
		}
	);
}
Enjin_Core.closeTrialReminder = function() {
	$.post("/ajax.php?s=signup", { cmd: 'close-trial-reminder' },
		function(data){
			$('.trial_popup').fadeOut(400);
		}
	);
}

Enjin_Core.stopBubble = function(event) {
	if ($.browser.msie) {
		window.event.cancelBubble = true;
		event.returnValue = false;
	} else
		event.stopPropagation();	
}
Enjin_Core.prepareEvent = function(event) {
	if ($.browser.msie) {
		//put some "cross" events
		event.pageX = $(document).scrollLeft() + event.offsetX;
		event.pageY = $(document).scrollTop() + event.offsetY;
	} 	
}

Enjin_Core.popupWindow = function(url, w, h) {
	var winl = (screen.width-w)/2;
	var wint = (screen.height-h)/2;
	mywindow = window.open(url, "cms_popup","location=0,toolbar=0,status=1,scrollbars=1,width=" + w + ",height=" + h + ",top=" + wint + ",left=" + winl);
}

Enjin_Core.liveSupport = function() {
	$('#livesupport').click(function(){
		if($(this).children('a').text() == 'Live Help') {
			window.location = 'http://www.enjin.com/support/form';
			return false;
		}
	});
}

Enjin_Core.toggleEditMode = function(self) {
	$(".editmode-module").toggle();
	$(self).toggleClass("enabled");
	/*if($(self).hasClass("enabled"))
		$(self).html("Finish editing");
	else
		$(self).html("Quick edit content");*/
}



/* Quick Wall Post */

Enjin_Core.showQuickPostBox = function(event) {
	event.stopPropagation();

	$('#global-search-box').hide();
	var box = $('#quick-post-box');
	
	box.css({'top': $(this).offset().top + $(this).height() + 2, 'right': $(window).width() - $(this).offset().left - $(this).width() - 5});
	box.show();
	box.find('textarea').focus();
	
	$('#quick-post-box textarea').autoResize({minHeight:10, maxHeight:640, extraSpace:16, animate: false});
	
	$(document).bind('mousedown', Enjin_Core.closePostInput);
	setTimeout(function(){$('#quick-post-box .wall-post-input textarea').focus()}, 400);
}

Enjin_Core.initQuickPost = function(icon, id) {
	icon.mousedown(Enjin_Core.showQuickPostBox);
	
	$('#quick-post-box, #quick-post-box .wall-post-input textarea').bind('click mousedown', function(event){
		event.stopPropagation();
	});
	
	$('#quick-post-box .wall-post-share input').click(function(){
		var message = $('#quick-post-box .wall-post-input textarea').val();
		if($.trim(message).length == 0) return;
		
		$('#quick-post-box .wall-post-share').addClass('disabled').children('input').attr('disabled', 'disabled');
		$('#quick-post-box .wall-post-input textarea').attr('disabled', 'disabled').css({ opacity: 0.5 });
		
		$.ajax({
    		type: "POST",
    		url: "/ajax.php?s=profile_wall",
    		data: {cmd: 'post', wall_user_id: $('#enjin-bar').attr('data-user_id'), message: message, access: $('#quick-post-box .wall-post-access').attr('data-access')},
    		dataType: "json",
    		success: function(data){
    			if(data.error !== undefined) alert('Error', data.error);
    			else {
    				$('#quick-post-box .wall-post-share').removeClass('disabled').children('input').removeAttr('disabled');
    				$('#quick-post-box .wall-post-input textarea').removeAttr('disabled').css({ opacity: null });
    				$('#quick-post-box .wall-post-input textarea').val('').blur();
    				Enjin_Core.closePostInput();
    				
    				if((Enjin_Core.owns_profile !== undefined && Enjin_Core.is_wall !== undefined) || Enjin_Core.is_activity !== undefined) {
    					var newpost = $(Enjin_Wall_System.createWallPost(data.post_id, data.username, data.message, data.avatar, data.timestamp, data.posted, data.access));
	    				newpost.hide();
	    				$('.wall-posts-empty').remove();
	    				$('.wall-mywall .posts, .activity-index .posts').prepend(newpost);
	    				newpost.fadeIn(600);
	    				Enjin_Wall_System.updatePostClasses();
    				}
    			}
    		},
    		error: function (XMLHttpRequest, textStatus, errorThrown) {
    		}
    	});
	});
	
	$('#quick-post-box .wall-post-access').click(function(){
		if($(this).attr('data-access') == 'everyone') $(this).attr('data-access', 'friends').html('Friends');
		else $(this).attr('data-access', 'everyone').html('Public');
		$(this).blur();
	});
}

Enjin_Core.closePostInput = function(event) {
	if($('#quick-post-box .wall-post-input textarea').val().length == 0) {
		$('#quick-post-box').hide();
		$(document).unbind('click', Enjin_Core.closePostInput);
	}
}


/* Global Search */

Enjin_Core.showGlobalSearchBox = function(event) {
	event.stopPropagation();

	$('#quick-post-box').hide();
	var box = $('#global-search-box');
	
	box.css({'top': $(this).offset().top + $(this).height() + 2, 'right': $(window).width() - $(this).offset().left - $(this).width() - 5});
	box.find('.global-search-box-input input').focus().val('');
	
    // ensure the results area is hidden
    box.find('.search-results ul').empty();
    box.find('.results').addClass('hidden');
    box.find('.empty').addClass('hidden');
    box.find('.loading').addClass('hidden');

	box.show();
	
	$(document).bind('mousedown', Enjin_Core.closeSearchInput);
	setTimeout(function(){$('#global-search-box .global-search-box-input input').focus()}, 400);
}

Enjin_Core.renderSearchItem = function(item, smallAvatar)
{
    var html = '';
    if ( item.type == "site" || item.type == "team" )
    {
            html += '<div class="avatar element_avatar simple ' + ( smallAvatar === true ? 'mediumsmall' : 'medium' ) + '">' + item.avatar + '</div>';
    }
    else
    {
            html += '<div class="avatar">' + item.avatar + '</div>';
    }        
    html += '<div class="body"><div class="header">';

    switch ( item.type )
    {
        case 'user':
        html +=	'<a href="/profile/' + item.user_id + '">' + item.displayname + '</a></div>';
        html += '<div class="bottom">Registered User';
        html += Enjin_Core.searchItemFriendHTML(item);         
        html += '</div>'
        break;
        
        case 'site':
        html +=	'<a href="' + item.domain + '">' + item.site_name + '</a></div>';
        html += '<div class="bottom"><div>' + item.member_count + ' members&nbsp;&middot;&nbsp;<a href="' + item.domain + '">' + item.domain + '</a></div></div>'
        break;
        
        case 'post':
        html += '<a href="' + item.url + '">' + item.thread_subject + '</a></div>';
        html += '<div class="snippet">' + item.post_content + '</div>';
        html += '<div class="bottom"><a href="' + item.site + '">' + item.site_name + '</a>';
        html += '&nbsp;&raquo;&nbsp;<a href="' + item.category_url + '">' + item.category_name + '</a>';
        html += '&nbsp;&raquo;&nbsp;<a href="' + item.url + '">' + item.forum_name + '</a>';
        html += '&nbsp;&middot;&nbsp;' + item.post_count + ' post' + (parseInt(item.post_count,10) > 1 ? 's' : '') + '&nbsp;&middot;&nbsp;' + item.post_time + '&nbsp;&middot;&nbsp;By <a href="/profile/' + item.post_user_id + '">' + item.post_username + '</a></div>';
        break;
        
        case 'article':
        html +=	'<a href="' + item.url + '">' + item.title + '</a></div>';
        html +=	'<div class="snippet">' + item.content + '</div>';
        html += '<div class="bottom"><a href="' + item.domain + '">' + item.site_name + '</a>&nbsp;&middot;&nbsp;' + item.timestamp + '&nbsp;&middot;&nbsp;By <a href="/profile/' + item.user_id + '">' + item.displayname + '</a></div>'
        break;

        case 'team':
        html +=	'<a href="' + item.url + '">' + item.team_name + '</a></div>';
        html += '<div class="bottom"><a href="' + item.url + '">' + item.url + '</a>';
        html += '&nbsp;&middot;&nbsp;' + item.game_name + (item.location ? ' - ' + item.location : '') + '</div>';            
        break;
        
        case 'character':
        html +=	'<a href="' + item.url + '">' + item.character_name + ' (' + item.displayname + ')</a></div>';
        html += '<div class="snippet">' + item.game_name + (item.location ? ' - ' + item.location : '') + '</div>';
        html += '<div class="bottom">Character';
        html += Enjin_Core.searchItemFriendHTML(item);         
        html += '</div>';
        break;
    }			

    html += '</div>';		
    return html;
}

Enjin_Core.searchItemFriendHTML = function(item)
{
    var html = '';
    
    // you cannot friend or message yourself!!
    if ( item.active_user_id != item.user_id )
    {
        html += '&nbsp;&middot;&nbsp;'; 
        if ( typeof item.state === 'undefined' || !item.state )
        { 
            html += '<a href="/profile/' + item.user_id + '/friends//op/add/subaction/friends/user/' + item.user_id + '">Add Friend</a>';
        }
        else if ( item.state == 'request' )
        {
            html += 'Friend Request Pending';
        }
        else if ( item.state == 'friend' )
        {
            html += '<a href="/profile/' + item.user_id + '/friends//op/remove/subaction/friends/user/' + item.user_id + '">Remove Friend</a>';
        }
                                                    
        if ( typeof item.state !== 'undefined' && item.state != 'blocked' )
        {
            html += '&nbsp;&middot;&nbsp;<a href="/dashboard/messages/compose/to/id-' + item.user_id + '">Message</a>';
        }                
    }
    
    return html;
}


Enjin_Core.initGlobalSearch = function(icon, id) {
	if(icon.length == 0) return false;
	
	icon.mousedown(Enjin_Core.showGlobalSearchBox);
	
	$('#global-search-box, #global-search-box .global-search-box-input input').bind('click mousedown', function(event){
		event.stopPropagation();
	});
	$('#global-search-box .search-box-area .icon').click(function(){
		$('#global-search-box form').trigger('submit');
	});
	
    var searchInput = $( "#global-search-box .global-search-box-input input" );
    var ac = searchInput.autocomplete({
		minLength: 3,
		delay:750,
	    appendTo: '#global-search-box .search-results',
		source: '/ajax.php?s=search',
		focus: function( event, ui ) {
			searchInput.val( ui.item.label );
			return false;
		},
		select: function( event, ui ) {
			searchInput.val( ui.item.label );
			return false;
		},
		search: function( event, ui ) {
		    var searchArea = $('#global-search-box .search-results');
		    
		    // make sure the entire lower area is visible
		    searchArea.removeClass('hidden');
		    
		    // ensure the results area is hidden
		    searchArea.find('.results').addClass('hidden');
		    searchArea.find('.empty').addClass('hidden');
		    
		    // show the loading icon
		    searchArea.find('.loading').removeClass('hidden');
		},
		response: function( event, results ) {		    
		    var searchArea = $('#global-search-box .search-results');
		    if ( results.content.length == 0 ) 
		    { 
		        searchArea.find('.empty').removeClass('hidden'); 
		    }
		    else
		    {
		        searchArea.find('.count').text(results.content.length);
		    }
		    searchArea.find('.loading').addClass('hidden');
		}
	});
	
	ac.data( "autocomplete" )._suggest = function( items ) 
	{
        var searchArea = $('#global-search-box .search-results');
        searchArea.find('.loading').addClass('hidden');
	    searchArea.find('.results').removeClass('hidden');
        var ul = $('#global-search-box .search-results ul').empty();
        
        this._renderMenu( ul, items );
    }	
	ac.data( "autocomplete" )._renderItem = function( ul, item ) 
	{
	    var el = $( "<li></li>" );	                
        el.append( Enjin_Core.renderSearchItem(item) );	        
	    el.data( "item.autocomplete", item ).appendTo( ul );
		return el;
			
	};
	
}

Enjin_Core.closeSearchInput = function(event) {
	//if($('#global-search-box .global-search-input input').val().length == 0) {
		$('#global-search-box').hide();
		$(document).unbind('click', Enjin_Core.closeSearchInput);
//	}
}


/*
 * Like Site
 */
Enjin_Core.enjinLikeSite = function(el) {
	var likes = $(el).siblings('.likes').children('span');


	if($(el).hasClass('liked')) {
		$(el).removeClass('liked');
		var cmd = 'unlike-site';
		likes.text(parseInt(likes.text(), 10)-1);
	}
	else {
		$(el).addClass('liked');
		var cmd = 'like-site';
		likes.text(parseInt(likes.text(), 10)+1);
	}
	$.post('/ajax.php?s=site', {cmd: cmd, site_id: Enjin_Core.site_id});
}


/*
 * Tooltips
 */
Enjin_Core.bindTooltip = function(el, html, cls) {
	Enjin_Core.createTooltipElement();
	
	if(cls == undefined) var cls = '';
	else cls = ' ' + cls;
	
	el.mouseover(function(e){
		$('#mouse_tooltip').attr('class', 'element_tooltip element_popup' + cls).children('.inner').html(html);
		$('#mouse_tooltip').show();
	});
	
	Enjin_Core.createTooltipBindings(el);
}

Enjin_Core.createTooltipElement = function() {
	if($('#mouse_tooltip').length == 0) {
		$('body').append("<div id='mouse_tooltip' class='element_tooltip element_popup' style='display: none;'><div class='inner'></div></div>");
	}
}

Enjin_Core.createTooltipBindings = function(el) {
	el.mousemove(function(e){
		var posY = (e.pageY + 14);
		var posX = (e.pageX + 10);
		
		var overflow = Enjin_Core.withinWindow(posX, posY);
           if(overflow[0]) posX = posX - $('#mouse_tooltip').outerWidth() - 22;
		if(overflow[1]) posY = posY - $('#mouse_tooltip').outerHeight() - 20;
		
		$('#mouse_tooltip').css({
			top: posY + "px",
			left: posX + "px"
		});
	});
	
	el.mouseout(function(){
		$('#mouse_tooltip').hide();
	});
}

Enjin_Core.withinWindow = function(posX, posY)
{
	var newX = posX + $('#mouse_tooltip').outerWidth();
	var newY = posY + $('#mouse_tooltip').outerHeight();
	
	var windowWidth = jQuery(window).width() + jQuery(window).scrollLeft();
	var windowHeight = jQuery(window).height() + jQuery(window).scrollTop();
	
	return [(newX >= windowWidth), (newY >= windowHeight)];
}





/*
 * Beacon
 */
Enjin_Core.handleBeacon = function(data) {
	if (data.name == 'gchat') {
		 //process through enjinmessaging
		 Enjin_Messaging_BeaconPush.triggerMessage(data.data);
	} else if(data.name == "chat-close") {
		Enjin_Core.Chat.StatusUpdate(data.data);
	} else if(data.name == 'alert') {
		Enjin_Core.newAlert(data);
	} else if(data.name == 'notify') {
		if(notification_count[data.data.type] == undefined) notification_count[data.data.type] = 0;
		notification_count[data.data.type]++;
		Enjin_Core.updateNotifyTip(data.data.type);
		if(data.data.growl != undefined) {
			if(data.data.growl) Enjin_Core.Notifications.addGrowl(data.data.type, data.data.growl);
			Enjin_Core.Notifications.lastUpdate[data.data.type] = Math.round(new Date().getTime()/1000);
		}
	} else if(data.name == 'chat-message') {
		Enjin_Core.Chat.handleMessage(data.data);
		if ( !$("#chat-"+ data.data.userId).is(':visible') ) {
			Enjin_Core.Chat.displayMicroTip(data.data.userId, true);
		}		
	}
}

Enjin_Core.newAlert = function(payload) {
	
	var type = payload.name;
	var data = payload.data;
	var trayAlert = $("#tray-alert");
	
	//populate alert	
	trayAlert.find("div.element_avatar a").attr("href", '/profile/' + data.senderId);
	//trayAlert.find("div.element_avatar img").attr("src", data.avatar_url);
	
	trayAlert.find("span.username a").text(data.from);
	
	// move into position
	var pos = $("#chatpanel").offset();
	trayAlert.css('right', 15).css('top', pos.top - 40 );
	

	switch (data.name) {
		case "user-login":			
			var message = "is now online.";
			break;
		case "user-logout":
			var message = "has gone offline.";				
			break;
		default:
			break;
	}
	
		
	trayAlert.find("span.message").text(message);
	$("#tray-alert div.element_avatar").remove();
	Enjin_Core.Chat.getUserAvatar(data.userId, function(avatar) {
		trayAlert.prepend(avatar);
		var clone = $("#tray-alert div.element_avatar").clone();
		clone.removeClass("small");
		clone.addClass("verysmall");
		clone.addClass(data.senderId);		
		Enjin_Core.Chat.StatusUpdate(data, clone);
		trayAlert.fadeIn("fast").delay(5000).fadeOut("fast");
	});	
}

Enjin_Core.updateNotifyTip = function(type) {
	$.get('/ajax.php?s=dashboard_notifications&cmd=get-' + type + '-count', function(data) {
		if(notification_count[type] == undefined) notification_count[type] = 0;
		notification_count[type] = parseInt(data, 10);
		Enjin_Core.notifyTip(type, notification_count[type]);

		// update read/unread status
		$('#enjin-tray .subpanel.'+type+' li').addClass('read');
		for(i=0; i<notification_count[type]; i++) {
			$('#enjin-tray .subpanel.'+type+' li:eq(' + i +')').removeClass('read');
		}
	});
};

/* Notifications */
Enjin_Core.notifyTip = function(type, num) {
	if(type == 'messages' || type == 'general' || type == 'apps') {
		if(num == 0) {
			$('#'+type+'-notification-tip').remove();
			if(type == 'messages') $('#mail-icon-link').hide();
		}
		else {
			var tooltip = Enjin_Core.microTip({right: $(window).width() - $('#notificationpanel .notification-icon.'+type).offset().left - 22, bottom: 28}, num, 'bl', type+'-notification-tip', 'fff471', '000000', type);
			tooltip.addClass('clickable');
			tooltip.click(function() {
				var trayid = Enjin_Core.Notifications.getTrayId($(this));
				if(trayid) Enjin_Core.Notifications.showPanel(trayid);
			});
			tooltip.mouseover(Enjin_Core.Notifications.onHoverTrayButton);

			if(type == 'messages') $('#mail-icon-link').show();
		}
	}
}


/* Micro Tooltips */
Enjin_Core.microTip = function(cssObject, content, triangle_position, id, bgcolor, color, idClass) {
	if(color != undefined) color = 'color: #' + color + '; ';
	
	var triangle_border = '';
	if(triangle_position == undefined) triangle_position = 'bl';
	if(triangle_position == 'bl' || triangle_position == 'br') triangle_border = 'top';
	if(triangle_position == 'tl' || triangle_position == 'tr') triangle_border = 'bottom';
	
	if(bgcolor != undefined) {
		var bg = 'background: #' + bgcolor + '; ';
		var triangle_color = 'border-' + triangle_border + '-color: #' + bgcolor + ';';
	}
	else {
		var bg = ''
		var triangle_color = '';
	}
	
	if(id != undefined) {
		$('#' + id).remove();
		id = ' id="' + id + '"';
	}
	else id = '';
	
	if (idClass != undefined) {
		idClass = ' ' + idClass;
	} else idClass = '';
	
	var html = '<div class="element_microtip'+idClass+'" style="' + bg + color + '"' + id + '><div class="inner">' + content + '<div class="triangle ' + triangle_position + '" style="' + triangle_color + '"></div></div></div>';
	var tooltip = $(html);
	tooltip.css(cssObject);
	$('body').prepend(tooltip);
	
	return tooltip;
}

/*
 * Bind Microtip to an element as hover tooltip
 */
Enjin_Core.bindMicroTip = function(el, data) {
	//var tooltip = Enjin_Core.microTip({right: $(window).width() - $('#notificationpanel .notification-icon.'+type).offset().left - 22, bottom: 28}, num, 'bl', type+'-notification-tip', 'fff471', '000000', type);
}

/*
 * Game Item Tooltips
 */
Enjin_Core.itemTooltipCache = {};
Enjin_Core.itemNameCache = {};
Enjin_Core.itemIdCache = {};
Enjin_Core.initItemTooltips = function() {
	$(document).bind("mouseover", function(ev){
		if(ev.target.nodeName != 'A' && ev.target.parentNode && ev.target.parentNode.nodeName == 'A')
			var el = $(ev.target.parentNode);
		else if(ev.target.nodeName == 'A')
			var el = $(ev.target);

		if(el != undefined) {
			var itemtooltip = el.attr('data-itemtooltip');
			if(itemtooltip != undefined) {
				Enjin_Core.createTooltipElement();
				
				if(Enjin_Core.itemTooltipCache[itemtooltip] != undefined) {
					var html = Enjin_Core.itemTooltipCache[itemtooltip];
				}
				else {
					var html = 'Loading...';
					$.get('/ajax.php?s=itemtooltip&item=' + itemtooltip, function(data) {
						Enjin_Core.itemTooltipCache[itemtooltip] = data;
						$('#mouse_tooltip .inner').html(data);
					});
				}
				
				$('#mouse_tooltip').attr('class', 'element_tooltip element_popup element_itemtooltip').children('.inner').html(html);
				$('#mouse_tooltip').show();
				
				
				Enjin_Core.createTooltipBindings(el);
				
				$(document).one("mouseup", function(ev){
					$('#mouse_tooltip').hide();
				});
			}
			else {
				var game = el.attr('data-itemgame');
				if(game != undefined) {
					var itemname = el.attr('data-itemid');
					if(itemname == undefined) var itemname = el.attr('data-itemname');
					if(itemname == undefined) var itemname = el.text();

					if(itemname != undefined && itemname.length > 0) {
						var key = game + '|' + itemname;
						var gameurl = '';

						if(game == 'wow' || game == '14') {
							game = '14';
							gameurl = '/ajax.php?s=redirect&cmd=wowitem&id=';
						}
						else if(game == 'rift' || game == '4910') {
							game = '4910';
							gameurl = '/ajax.php?s=redirect&cmd=riftitem&id=';
						}

						Enjin_Core.createTooltipElement();
						
						if(Enjin_Core.itemNameCache[key] != undefined) {
							var html = Enjin_Core.itemNameCache[key];
						}
						if(Enjin_Core.itemIdCache[key] != undefined) {
							var id = Enjin_Core.itemIdCache[key];
						}
						else {
							var html = 'Loading...';
							var id = '';

							$.getJSON('/ajax.php?s=itemtooltip&g=' + game + '&name=' + itemname, function(data) {
								Enjin_Core.itemNameCache[key] = data.html;
								Enjin_Core.itemIdCache[key] = data.id;
								$('#mouse_tooltip .inner').html(data.html);
								el.attr('href', gameurl + data.id);
							});
						}
						
						$('#mouse_tooltip').attr('class', 'element_tooltip element_popup element_itemtooltip').children('.inner').html(html);
						if(id.length) el.attr('href', gameurl + id);
						$('#mouse_tooltip').show();
						
						Enjin_Core.createTooltipBindings(el);
						
						$(document).one("mouseup", function(ev){
							$('#mouse_tooltip').hide();
						});
					}
				}
			}
		}
	});
}



/**
 *
 */
Enjin_Core.tooltipHover = null;
Enjin_Core.initHoverTips = function() 
{
	$(document).bind("mouseover", function(ev)
	{
		if(ev.target.nodeName != 'A' && ev.target.parentNode && ev.target.parentNode.nodeName == 'A')
			var el = $(ev.target.parentNode);
		else if(ev.target.nodeName == 'A')
			var el = $(ev.target);
		
		if ( el != undefined ) 
		{
			var tooltip = el.attr('data-minitooltip');

			if ( typeof tooltip !== 'undefined' && tooltip )
			{
				// just in case, if there is a tip being shown, remove it
				if ( Enjin_Core.tooltipHover != null ) { Enjin_Core.tooltipHover.remove(); }
				
				Enjin_Core.tooltipHover = Enjin_Core.microTip({top:'-32px',left:'16px'}, tooltip, 'bl', 'mini-tooltip', '', '', 'mini-tooltip');				
				
				var tipOffset = "0 4";
				var triOffset = "0 22";
				if ( $.browser.mozilla )
				{
					tipOffset = "0 -8";
					triOffset = "0 0";
				}
				else if ( $.browser.webkit )
				{ 
					tipOffset = "0 -4";
				}

				Enjin_Core.tooltipHover.position({of:el, my:"center bottom", at:"center top",collision:"none",offset:tipOffset});
				Enjin_Core.tooltipHover.find('.triangle').position({of:Enjin_Core.tooltipHover,my:"center top", at:"center bottom",offset:triOffset});
				
				el.mouseout( function() { Enjin_Core.tooltipHover.remove(); Enjin_Core.tooltipHover = null; el.unbind('mouseout'); });				
			}			
		}
	});
}

/** 
 * Site Announcements
 */ 
Enjin_Core.announcementTip = null;
Enjin_Core.Announcements = {
	
	init: function( announcements )
	{
		Enjin_Core.Announcements.announcements = announcements;
		Enjin_Core.Announcements.index = 0;
		
		this.showAlert();
		$('#site-announcements a').click(Enjin_Core.Announcements.show);

		for ( var n in Enjin_Core.Announcements.announcements )
		{
			if ( parseInt(Enjin_Core.Announcements.announcements[n].maximize,10) ) 
			{ 
				Enjin_Core.Announcements.index = parseInt(n,10); 
				Enjin_Core.Announcements.show(false);				
				break; 
			}
		}
	}
	
	,show: function(event)
	{
		if ( event ) { event.cancelBubble = true; if (event.stopPropagation) event.stopPropagation(); }		
		
		Enjin_Core.Announcements.showAnnouncement();
		$('#site-announcements a').unbind('click').click(Enjin_Core.Announcements.close);
		return false;
	}
	
	,showAlert: function( )
	{
		if(Enjin_Core.Announcements.announcements == undefined) var num = 0;
		else var num = Enjin_Core.Announcements.announcements.length;
		
		if ( num > 0 )
		{
			$('#site-announcements').removeClass('active').show();
			
			if ( !Enjin_Core.announcementTip )
			{
				Enjin_Core.announcementTip = Enjin_Core.microTip({left:$('#site-announcements').offset().left+6,bottom:28}, num, 'bl', 'announcement-tooltip', 'fff471', '000000', 'announcement-tooltip');
				Enjin_Core.announcementTip.addClass('clickable');
				Enjin_Core.announcementTip.click(Enjin_Core.Announcements.show);
			}
			else
			{
				Enjin_Core.announcementTip.find('.inner').text(num);
			}
		}
		else
		{	
			this.hideTip();
			$('#site-announcements').hide();
		}
	}
	
	,showAnnouncement: function()
	{			
		var a = Enjin_Core.Announcements.announcements[Enjin_Core.Announcements.index];
		
		var can_delete = a.expires == 'delete';
		var can_next = Enjin_Core.Announcements.index+1 < Enjin_Core.Announcements.announcements.length;
		var can_prev = Enjin_Core.Announcements.index > 0;
		
		var el = $('.site-announcement');
		el.find('.content').html( a.announcement );

		el.find('.title .index').text(Enjin_Core.Announcements.index+1);
		el.find('.title .total').text(Enjin_Core.Announcements.announcements.length);

		if ( can_delete || can_next || can_prev )
		{		
			el.find('.nav-bar').show();
			el.find('.delete')[ can_delete ? 'show' : 'hide' ]();
			el.find('.nav .prev')[ can_prev ? 'show' : 'hide' ]();
			el.find('.nav .next')[ can_next ? 'show' : 'hide' ]();
		}
		else
		{
			el.find('.nav-bar').hide();
		}
		
		this.hideTip();
		el.show(); //.position({of:$('#site-announcements'),my:"left bottom",at:"left top",offset:"0 2"});
		
		// show the fragment div covering the bottom left border giving appearance of flowing into the icon
		$('#site-announcements .border').show();
		
		$('#site-announcements').addClass('active');
		
		// now flag that the user has seen this announcement for computation of exiry etc
		if ( a.expires == 'days' || parseInt(a.maximize,10) )
		{
			$.post('/ajax.php?s=announcements',{op:'view', announcement_id:a.announcement_id});
		}
	}
	
	,hideTip: function()
	{
		if ( Enjin_Core.announcementTip ) { Enjin_Core.announcementTip.remove(); Enjin_Core.announcementTip = null; }
	}
	
	,close: function()
	{
		$('.site-announcement').hide();
		$('#site-announcements .border').hide();
		$('#site-announcements a').unbind('click').click(Enjin_Core.Announcements.show);
		Enjin_Core.Announcements.showAlert();
	}
	
	,remove: function()
	{
		var id = Enjin_Core.Announcements.announcements[Enjin_Core.Announcements.index].announcement_id;
		$.post('/ajax.php?s=announcements',{op:'delete', announcement_id:id});
		
		// they removed the last announcement, so close window and hide icon
		if ( Enjin_Core.Announcements.announcements.length == 1 )
		{
			Enjin_Core.Announcements.announcements = [];
			this.close();		
		}
		else
		{		
			var tmp = Enjin_Core.Announcements.announcements;
			Enjin_Core.Announcements.announcements = [];
			for ( var i = 0; i < tmp.length; i++ ) { if ( tmp[i].announcement_id != id ) {Enjin_Core.Announcements.announcements.push(tmp[i]);} }
			if ( Enjin_Core.Announcements.index >= Enjin_Core.Announcements.announcements.length ) 
			{
				Enjin_Core.Announcements.prev();
			}
			else
			{
				Enjin_Core.Announcements.showAnnouncement();
			}			
		}
	}
	
	,prev: function()
	{
		Enjin_Core.Announcements.index--;
		Enjin_Core.Announcements.showAnnouncement();
	}
	
	,next: function()
	{
		Enjin_Core.Announcements.index++;
		Enjin_Core.Announcements.showAnnouncement();
	}
}


/*
 * Notifications
 */
Enjin_Core.Notifications = {
	panels: ['messages', 'general', 'apps'],
	lastLoaded: {'messages': 0, 'general': 0, 'apps': 0},
	lastUpdate: {'messages': 1, 'general': 1, 'apps': 1},
	
	init: function() {
		$('#enjin-tray .tray-button').mouseover(Enjin_Core.Notifications.onHoverTrayButton);
		$('#enjin-tray .tray-button').mousedown(Enjin_Core.Notifications.onClickTrayButton);
		$('#enjin-tray .subpanel .subpanel-header').click(Enjin_Core.Notifications.onPanelMinimize);
		$('#enjin-tray #notificationpanel .subpanel .faux-icon').click(Enjin_Core.Notifications.onPanelMinimize);
	},
	
	onClickTrayButton: function(event) {
		var trayid = Enjin_Core.Notifications.getTrayId($(this));
		if(trayid) Enjin_Core.Notifications.showPanel(trayid);
	},
	
	onPanelMinimize: function(event) {
		var trayid = Enjin_Core.Notifications.getTrayId($(this).parent());
		if(trayid) Enjin_Core.Notifications.hidePanel(trayid);
	},
	
	onHoverTrayButton: function(event) {
		var trayid = Enjin_Core.Notifications.getTrayId($(this));
		if(trayid && Enjin_Core.Notifications.lastLoaded[trayid] < Enjin_Core.Notifications.lastUpdate[trayid]) {
			Enjin_Core.Notifications.loadData(trayid, notification_count[trayid]);
		}
	},
	
	showPanel: function(id) {
		var i = 0;

		// update read/unread status
		$('#enjin-tray .subpanel.'+id+' li').addClass('read');
		for(i=0; i<notification_count[id]; i++) {
			$('#enjin-tray .subpanel.'+id+' li:eq(' + i +')').removeClass('read');
		}

		if(id == 'general' || id == 'apps') {
			$('#enjin-tray .subpanel.'+id+' .notification-list').scrollTop(0);

			// remove notify tip
			if($('#'+id+'-notification-tip').length) {
				$.get('/ajax.php?s=dashboard_notifications&cmd=clear-tip&type='+id);
				$('#'+id+'-notification-tip').remove();
				notification_count[id] = 0;
			}
		}
		
		i=Enjin_Core.Notifications.panels.length; while(i--) {
			if(Enjin_Core.Notifications.panels[i] != id) Enjin_Core.Notifications.hidePanel(Enjin_Core.Notifications.panels[i]);
		}
		$('#enjin-tray .subpanel.'+id).show(160);
		$('#enjin-tray .notification-growls ul li').remove();

		// hide any notify tips
		$('#messages-notification-tip, #general-notification-tip, #apps-notification-tip').hide();
	},
	
	hidePanel: function(id) {
		$('#enjin-tray .subpanel.'+id).hide(160);
		$('#messages-notification-tip, #general-notification-tip, #apps-notification-tip').show();
	},
	
	loadData: function(type, unread_count) {
		Enjin_Core.Notifications.lastLoaded[type] = Math.round(new Date().getTime()/1000);
		$('#enjin-tray .subpanel.' + type + ' .notification-list').html('<div class="loading-info">Loading...</div>');
		
		if(type == 'messages') {
			$.getJSON('/ajax.php?s=dashboard_notifications&cmd=get-messages', function(data) {
				var html = '';
				var cls = 'first ';
				
				if(!data.length) html = '<li class="first">There are no new messages. <a href="/dashboard/messages">View your Inbox</a>.</li>';
				
				for(var i=0; i<5 && i<data.length; i++) {
					html += Enjin_Core.Notifications.createItem('messages', data[i], cls);
					cls = '';
				}
				$('#enjin-tray .subpanel.messages .notification-list').html(html);
				$('#enjin-tray .subpanel.messages li').addClass('read');
				for(i=0; i<unread_count; i++) {
					$('#enjin-tray .subpanel.messages li:eq(' + i +')').removeClass('read');
				}
			});
		}
		else if(type == 'general') {
			$.getJSON('/ajax.php?s=dashboard_notifications&cmd=get-general', function(data) {
				var html = '';
				var cls = 'first ';
				
				if(!data.length) html = '<li class="first">There are no new notifications. <a href="/dashboard">View Activity Wall</a>.</li>';

				for(var i=0; i<data.length; i++) {
					html += Enjin_Core.Notifications.createItem('general', data[i], cls);
					cls = '';
				}
				if(data.length > 7) $('#enjin-tray .subpanel.general .notification-list').addClass('scrolling');
				$('#enjin-tray .subpanel.general .notification-list').html(html);
				$('#enjin-tray .subpanel.general li').addClass('read');
				for(i=0; i<unread_count; i++) {
					$('#enjin-tray .subpanel.general li:eq(' + i +')').removeClass('read');
				}
			});
		}
		else if(type == 'apps') {
			$.getJSON('/ajax.php?s=dashboard_notifications&cmd=get-apps', function(data) {
				var html = '';
				var cls = 'first ';
				
				if(!data.length) html = '<li class="first">There are no new applications. <a href="/applications">View Applications</a>.</li>';
				for(var i=0; i<data.length; i++) {
					html += Enjin_Core.Notifications.createItem('apps', data[i], cls);
					cls = '';
				}
				if(data.length > 7) $('#enjin-tray .subpanel.apps .notification-list').addClass('scrolling');
				$('#enjin-tray .subpanel.apps .notification-list').html(html);
				$('#enjin-tray .subpanel.apps li').addClass('read');
				for(i=0; i<unread_count; i++) {
					$('#enjin-tray .subpanel.apps li:eq(' + i +')').removeClass('read');
				}
			});
		}
	},

	createItem: function(type, data, cls, growl) {
		switch(type) {
			case 'messages':
				return Enjin_Core.Notifications.generatePanelItem(
					data['avatar'],
					data['username'],
					data['time'],
					data['title'],
					'/dashboard/messages/view/message/' + data['id'],
					data['msg'],
					data['read'] == 1 ? cls + 'read' : cls + '',
					growl
				);
				break;

			case 'general':
				var url = '';
				if(data['type'] == 'wall_post' || data['type'] == 'wall_reply' || data['type'] == 'wall_post_like')
					url = '/profile/'+ data['wall_uid'] + '#post' + data['id'];
				else if(data['type'] == 'site_registration') url = data['wall_uid'];
				else if(data['type'] == 'site_news_comment') url = 'link-to-site-here';
				else if(data['type'] == 'forum_thread_reply') url = '/ajax.php?s=redirect&cmd=forum-post&id=' + data['id'] + '&preset=' + data['wall_uid'];
				else if(data['type'] == 'forum_thread') url = '/ajax.php?s=redirect&cmd=forum-thread&id=' + data['id'] + '&preset=' + data['wall_uid'];
				else if(data['type'] == 'friend_request') url = data['wall_uid'];
				else if(data['type'] == 'friend_confirmed') url = data['wall_uid'];
				else if(data['type'] == 'friend_accepted') url = data['wall_uid'];
				else if(data['type'] == 'modulecomments_news') url = '/ajax.php?s=redirect&cmd=news-article&id=' + data['id'] + '&preset=' + data['wall_uid'];
				else if(data['type'] == 'modulecomments_events') url = '/ajax.php?s=redirect&cmd=event&id=' + data['id'] + '&preset=' + data['wall_uid'];
				else if(data['type'] == 'modulecomments_gallery') url = '/ajax.php?s=redirect&cmd=gallery-image&id=' + data['id'] + '&preset=' + data['wall_uid'];
				else if(data['type'] == 'modulecomments_children') url = '/ajax.php?s=redirect&cmd=module&id=' + data['id'] + '&preset=' + data['wall_uid'];
					
				return Enjin_Core.Notifications.generatePanelItem(
					data['avatar'],
					data['username'],
					data['time'],
					data['title'],
					url,
					data['msg'],
					cls,
					growl
				);
				break;

			case 'apps':
				return Enjin_Core.Notifications.generatePanelItem(
					data['avatar'],
					data['username'],
					data['time'],
					data['title'],
					data['wall_uid'],
					data['msg'],
					cls,
					growl
				);
				break;
		}
	},

	addGrowl: function(type, data) {
		if(typeof(data)=='string') var el = $("<li class='" + type + "'><div class='inner'>" + data + "</div></li>");
		else var el = $(Enjin_Core.Notifications.createItem(type, data, '', true));
		el.mouseenter(function() {
			$(this).addClass('over');
		});
		el.mouseleave(function() {
			$(this).removeClass('over');
		});

		setTimeout(function(){
			if(!el.hasClass('over')) el.slideUp(300);
			else {
				var onTime = arguments.callee;
				el.mouseleave(function() {
					setTimeout(onTime, 1600);
				});
			}
		}, 5500);

		el.hide();
		$('#enjin-tray .notification-growls ul').prepend(el);
		el.fadeIn(300);
	},
	
	getTrayId: function(el) {
		if(el.hasClass('messages')) return 'messages';
		if(el.hasClass('general')) return 'general';
		if(el.hasClass('apps')) return 'apps';
		return false;
	},
	
	generatePanelItem: function(avatar, username, time, title, title_link, body, cls, growl) {
		avatar = avatar.replace('mediumsmall', 'small');
		
		var html = "<li class='" + cls + "'>"
		if(growl) html += "<div class='inner'>";
		html += "<div class='item-user'>\
				" + avatar + "\
				<div class='name-line'>" + username + "</div>\
				<div class='time-line'>" + time + "</div>\
			</div>\
			<div class='item-notification'>\
				<div class='link-line'><a href='" + title_link + "'>" + title + "</a></div>\
				<div class='info-line'>" + body + "</div>\
			</div>";
		if(growl) html += "</div>";
		html += "</li>";

		return html;
	}
};

Enjin_Core.WowFetcher = {
	runFetcher: function(data) {
		if(data != undefined && data.name && data.server && data.region) Enjin_Core.WowFetcher.loadCharacter(data);
		else {
			$.get('/ajax.php?s=profile_characters&cmd=fetcher-get-wow', function(response){
				if(window.console) window.console.debug('got new char to fetch:');
				if(window.console) window.console.debug(response);
				Enjin_Core.WowFetcher.loadCharacter(response);
			}, 'json');
		}
	},

	loadCharacter: function(data) {
		if(window.console) window.console.debug('loadCharacter starting, name: ' + data.name + ' server: ' + data.server + ' region: ' + data.region);
		var character_id = data.character_id;
		if(data.character_id && data.name && data.server && data.region) {
			if(window.console) window.console.debug('Fetching...');
			var timer = setTimeout(Enjin_Core.WowFetcher.runFetcher, 11000);
			$.getJSON('http://' + data.region + '.battle.net/api/wow/character/' + data.server + '/' + data.name + '?fields=guild,stats,talents,items,titles,professions,achievements,progression,pvp&jsonp=?', function(fetched) {
				clearTimeout(timer);
				if(window.console) window.console.debug('Got response from Armory: ', fetched);
				if(Enjin_Core.WowFetcher.validateData(fetched)) {
					$.post('/ajax.php?s=profile_characters&cmd=fetcher-save-wow', {data: fetched, character_id: character_id}, function(response){
						if(window.console) window.console.debug('Data Saved. Got response: ', response);
						if(response.name && response.server && response.region) {
							setTimeout(function(){
								Enjin_Core.WowFetcher.runFetcher(response)
							}, Math.floor(Math.random()*3001));
						}
					}, 'json');
				}
			});
		}
	},

	validateData: function(data) {
		if(window.console) window.console.debug('Validating data: ', data);
		if(data.name && data.realm) return true;
		else return false;
	}
};



/* Init */

$(document).ready(function(){
	Enjin_Core.initQuickPost($('#enjin-bar .quick-wall-post-icon'));
	Enjin_Core.initGlobalSearch($('#enjin-bar .global-search-icon'));
	Enjin_Core.initItemTooltips();
	Enjin_Core.initHoverTips();
	Enjin_Core.Notifications.init();
});


/* IE9 fix */
if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
    Range.prototype.createContextualFragment = function(html) {
        var doc = this.startContainer.ownerDocument;
        var container = doc.createElement("div");
        container.innerHTML = html;
        var frag = doc.createDocumentFragment(), n;
        while ( (n = container.firstChild) ) {
            frag.appendChild(n);
        }
        return frag;
    };
}

/* IE9 draggable hotfix */
if($.ui && $.ui.mouse && $.ui.mouse.prototype) (function($){var a=$.ui.mouse.prototype._mouseMove;$.ui.mouse.prototype._mouseMove=function(b){if($.browser.msie&&document.documentMode>=9){b.button=1};a.apply(this,[b]);}}(jQuery));


/* plugin for select options */
(function( $ ){
	$.fn.setSelectOptions = function(opts) {
		assignOptions = function(el, opts) {
			el = $(el);
			el.empty();
			  
			jQuery.each(opts, function(key, value) {
				if (typeof value == 'object') {
					var nel = $('<optgroup />').attr('label', key);
					assignOptions(nel, value);
					el.append(nel);
				} else {
					el.append(
								$('<option />')
									.attr('value', key)
									.attr('label', value)
									.text(value)
								);
				}
			});
		}
	
		jQuery.each(this, function() {
			if (this.nodeName.toLowerCase() == 'select') {
				assignOptions(this, opts);
			}
		});
	};
	
	
	var documentGlobalHandler = {
		handlers: [],
		addHandler: function(el) {
			for (var i=0; i<this.handlers.length; i++) {
				if (this.handlers[i] == el)
					return; //already
			}
			
			this.handlers.push(el);
		},
		removeHandler: function(el) {
			var nhandlers = [];
			for (var i=0; i<this.handlers.length; i++) {
				if (this.handlers[i] == el)
					continue;
				
				nhandlers.push(this.handlers[i]);
			}
			
			this.handlers = nhandlers;
		},
		
		haveParent: function(el, parent) {
			 return (el == parent) ||  
			 	($(el).parents().index(parent) >= 0);
		},
		
		init: function() {
			var self = this;
			$(document).bind('click', function(evt) {
				for (var i=0; i<self.handlers.length; i++) {
					var handler = self.handlers[i];
					if (self.haveParent(evt.target, handler)
						|| self.haveParent(evt.currentTarget, handler)) {
						return; //we won't process it
					}
					
					if ($(handler).is(':visible'))
						$(handler).trigger("outsideClick");
				}
			});
		}
	}
	documentGlobalHandler.init();
	
	$.fn.outsideClick = function(opts) {		
		jQuery.each(this, function() {
			var el = this;
			documentGlobalHandler.addHandler(el);
			$(el).bind('outsideClick', function() {
				opts.callback.apply(el)
			});
		});
	};
})( jQuery );

/*
bindWithDelay jQuery plugin
Author: Brian Grinstead
MIT license: http://www.opensource.org/licenses/mit-license.php

http://github.com/bgrins/bindWithDelay
http://briangrinstead.com/files/bindWithDelay

Usage:
	See http://api.jquery.com/bind/
	.bindWithDelay( eventType, [ eventData ], handler(eventObject), timeout, throttle )

Examples:
	$("#foo").bindWithDelay("click", function(e) { }, 100);
	$(window).bindWithDelay("resize", { optional: "eventData" }, callback, 1000);
	$(window).bindWithDelay("resize", callback, 1000, true);
*/

(function($) {
$.fn.bindWithDelay = function( type, data, fn, timeout, throttle ) {
	var wait = null;
	var that = this;

	if ( $.isFunction( data ) ) {
		throttle = timeout;
		timeout = fn;
		fn = data;
		data = undefined;
	}

	function cb() {
		var e = $.extend(true, { }, arguments[0]);
		var throttler = function() {
			wait = null;
			fn.apply(that, [e]);
		};

		if (!throttle) { clearTimeout(wait); }
		if (!throttle || !wait) { wait = setTimeout(throttler, timeout); }
	}

	return this.bind(type, data, cb);
}
})(jQuery);

/**
 * Focus at any position in an input
 */
(function($) {
$.fn.setCursorPosition = function(pos) {
  this.each(function(index, elem) {
    if (elem.setSelectionRange) {
      elem.setSelectionRange(pos, pos);
    } else if (elem.createTextRange) {
      var range = elem.createTextRange();
      range.collapse(true);
      range.moveEnd('character', pos);
      range.moveStart('character', pos);
      range.select();
    }
  });
  return this;
}
})(jQuery);


/**
 * Zero-fills a number to the specified length (works on floats and negatives, too).
 *
 * @param number
 * @param width
 * @param includeDecimal
 * @return string
 */
Enjin_Core.zeroFill = function(number, width, includeDecimal) {
	if (includeDecimal === undefined)
		includeDecimal = false;

	var result = parseFloat(number),
		negative = false,
		length = width - result.toString().length,
		i = length - 1;

	if (result < 0) {
		result = Math.abs(result);
		negative = true;
		length++;
		i = length - 1;
	}

	if (width > 0) {
		if (result.toString().indexOf('.') > 0) {
			if (!includeDecimal)
				length += result.toString().split('.')[1].length;

			length++;
			i = length - 1;
		}

		if (i >= 0) {
			do {
				result = '0' + result;
			} while (i--);
		}
	}

	if (negative)
		return '-' + result;

	return result;
};


/*******************************************************************************************************************
 *
 * Enjin_UI - JQuery helper functions for generating Enjin specific UI elements
 *
 *******************************************************************************************************************/


Enjin_UI.input = function( options )
{
	var el = $('<div class="input-text"><input type="text" /></div>'); 
	var elInput = el.find('input');
	for ( var n in options ) { elInput.attr(n,options[n]); }
	return el;
};

Enjin_UI.textarea = function( options )
{
	var el = $('<div class="input-textarea"><textarea></textarea></div>'); 
	var elText = el.find('textarea');
	if ( typeof options === 'object' )
	{
		if ( typeof options.value !== 'undefined' ) { elText.text(options.value); delete options.value; }
		for ( var n in options ) { elText.attr(n,options[n]); }
	}	
	return el;
};

Enjin_UI.container = function( label )
{
	return $("<div class='" + label + "-body'>" +
			 "<div class='" + label + "-body-left'><!--  --></div><div class='" + label + "-body-right'><!--  --></div>" +
			 "<div class='" + label + "-header-left'><!--  --></div><div class='" + label + "-header-right'><!--  --></div>" +
			 "<div class='" + label + "-footer-left'><!--  --></div><div class='" + label + "-footer-right'><!--  --></div>" +
			 "<div class='" + label + "-body-content'>" +
			 "</div>" +
			 "</div>" 
			);
}

Enjin_UI.blockContainer = function( options )
{
	var el = $("<div class='block-container " + (typeof options !== 'undefined' ? options.cssClass : '') + "'></div>");
	el.html( "<div class='he l'><!--  --></div>" + 
				"<div class='he r'><!--  --></div>" + 
				"<div class='he tl'><!--  --></div>" + 
				"<div class='he tr'><!--  --></div>" + 
				"<div class='he bl'><!--  --></div>" + 
				"<div class='he br'><!--  --></div>" + 
				"<div class='structure'></div>");
	return el;
};

Enjin_UI.button = function( options )
{
	var button_type = 'element_button';
	if(options.button_type != undefined) button_type = options.button_type;
	var el = $('<div class="' + button_type + '"><div class="l"><!-- --></div><div class="r"><!-- --></div><input type="button"/></div>');
	var elInput = el.find('input');
	for ( var n in options ) { if ( typeof options[n] === 'function' ) { elInput[n](options[n]); } else { elInput.attr(n,options[n]); } }	
	return el;
};


/* just an util function, check maybe extending to get
 * something like el.bind('enter')
 * in jquery
 */
Enjin_Core.bindEnter = function(el, callback) {
	el.bind('keyup', function(event) {
		if (event.keyCode == 0xD) {
			callback.call(el);
		}
	});
}


/* 
 * persistence utilitie
 * fields it's an array
 * [name1, name2, name3] 
 */
Enjin_Core_Persistence = function(namespace, el, fields) {
	this.init(namespace, el, fields);
}
Enjin_Core_Persistence.prototype = {
	namespace: null,	
	el: null,
	
	init: function(namespace, el, fields) {
		this.namespace = namespace;
		this.el = el;
		
		for (var i=0; i<fields.length; i++) {
			var ftype = 'value';
			var field = fields[i];
			var fvalue;
			var fpname = this.getPersistenceFieldKey(field);
			
			fvalue = this.getPersistence(field);
			if (typeof fvalue != 'undefined'
				&& fvalue != null) {
				el[field] = fvalue;
			}
		}
	},
	
	set: function(field, value) {
		if (typeof value != 'undefined')
			this.el[field] = value;
		
		this.savePersistence(field, this.el[field]);
	},
	
	getPersistence: function(field) {
		var fpname = this.getPersistenceFieldKey(field);
		return $.jStorage.get(fpname);
	},
	
	savePersistence: function(field, value) {
		var fpname = this.getPersistenceFieldKey(field);
		$.jStorage.set(fpname, value);
	},
	
	getPersistenceFieldKey: function(field) {
		return this.namespace+"-"+field;
	}
}


/* detect and parse equal strings 
 * used for fast replacement*/
Enjin_Dictionary_Replace = function() {
	this.init();
}

Enjin_Dictionary_Replace.prototype = {
	dictionary: null,
	dictionary_hash: null,
	
	init: function() {
		this.dictionary = {};
		this.dictionary_hash = {};
	},
	
	add: function(key, replace) {
		if (this.dictionary_hash[key]) {
			//skip readding, first will be the good
			return;
		}
		
		this.dictionary_hash[key] = replace;
		var dd = this.dictionary;
		var chr = '';
		
		for (var i=0; i<key.length; i++) {
			chr = key.charAt(i);
			
			//check if the current queue 
			//has the item, if not create
			if (!dd[chr]) {
				dd[chr] = {};
			}
			
			//make the pointer for next item
			dd = dd[chr];
		}		
	},
	
	parse: function(string) {
		var index = -1;
		var hash = '';
		var str_copy = '';
		
		var dict = this.dictionary;
		var chr = null;
		var i = 0;
		var advance_index = true;
		
		while (true) {
			advance_index = true;
			if (i == string.length)
				chr = ''; //dummy
			else
				chr = string.charAt(i);
			
			if (i != string.length
				&& dict[chr]) {
				//found a match
				index = i;
				dict = dict[chr];
				hash += chr;
			} else {
				if (index == -1) {
					//haven't got any hash so just append
					str_copy += chr;
				} else {
					//we got a hash, check if is valid, if so append, if not
					//just append substring
					if (this.dictionary_hash[hash]) {
						str_copy += this.dictionary_hash[hash];
					} else {
						str_copy += hash;
					}
					
					//reset
					index = -1;
					hash = '';
					dict = this.dictionary;
					advance_index = false; //keep on the same char
				}
			}
			
			if (advance_index)
				i++;
			
			if (i > string.length)
				break; //no more processing
		}
		
		return str_copy;
	}
}

Enjin_BBCode_Smileys = new Enjin_Dictionary_Replace();

//basic escape chars 
/*Enjin_BBCode_Smileys.add('<', '&lt;');
Enjin_BBCode_Smileys.add('>', '&gt;');
Enjin_BBCode_Smileys.add('&', '&amp;')
Enjin_BBCode_Smileys.add('"', '&quot;')
Enjin_BBCode_Smileys.add("'", '&#039;');*/

Enjin_Core.ucFirst = function(string) {
	return string.substr(0, 1).toUpperCase()+string.substr(1);
}

Enjin_Core_Storage_Cache = {
	get: function(key, def) {
		var el = $.jStorage.get(key, def);
		var now = (new Date()).getTime();
		
		if (el && el.xcache) {
			//check if still valid
			if (el.xcache < now) //not valid
				return def;
			else
				return el.data;
		} else
			return el;
	},
	
	set: function(key, data, until) {
		if (!until)
			until = 3600; //cache for an hour
		
		$.jStorage.set(key, {
			xcache: (new Date()).getTime() + until*1000,
			data: data
		});
	},
	
	invalidate: function(key) {
		//for now just delete item
		$.jStorage.deleteKey(key, null);
	}
}
