/********************************************
(c) 2005-present, uTime Games
Despite the fact that you can see this, 
you may NOT use or copy this code for any reason.
If you'd like to use this code, please contact:
	Geoffrey Benson at
	sales@utimegames.com

Licensing terms are generally reasonable -
ranging from free to cheap - but you MUST
ask and obtain permission first.

Thank you for not being a jerk.
  --The Management
********************************************/

// Global variables used later
var enableKeyboardMove = 0;
var version = 75;
var showing_warning = 0;

var searchTimeout = 0;

var char_chart = 0;
var char_chart_series = 0;
var char_viewed_user = "";

var g_handler_cache = {};
var g_window_cache = {};

function UpdateAd()
{
	SendRequest( "refresh_ingame_ad" );
	setTimeout( "UpdateAd();", 30000 );
}

function SendRequest( action, args )
{
	// NOTE: this should only ever be called from within a game_state action function.
	
	// Check to see if we have the version warning box displayed, and if so, don't send any requests (since we won't allow them to respond anyway)
	if( showing_warning == 1 )
		return;

	if( typeof( args ) == "undefined" )
	{
		args = {};
	}

	// append the action
	args['action'] = action;

	if( char_viewed_user != "" )	// special bit for the character page
		args['char_name'] = char_viewed_user;
	
	if( action == "heartbeat" || action == "refresh_ingame_ad" || action == "load_tooltip" )
	{
		AjaxRequest.post(
			{
				'url':'/pseudoquest.php'
				,'groupName': 'Heartbeat'
				,'onSuccess': updatePage
				,'parameters': args
				,'generateUniqueUrl': true
			}
		);
	}
	else
	{
		// Shut off the tooltip, if it's active
		if( ClearTooltip )
			ClearTooltip();
		
		if( AjaxRequest.numActiveAjaxGroupRequests['PseudoQuest'] >= 5 )
		{
			alert( "Patience... we hate lag as much as you do, but clicking a million times only slows things down." );
			return -1;
		}
		
		AjaxRequest.post(
			{
				'url':'/pseudoquest.php'
				,'groupName': 'PseudoQuest'
				,'onSuccess': updatePage
				,'parameters': args
				,'generateUniqueUrl': true
			}
		);
	}
}

function Spin()
{
	if( AjaxRequest.numActiveAjaxGroupRequests['PseudoQuest'] < 2 )
	{
		// Set the body's cursor back to 'auto' if there's only 1 or 0 open requests
		var body = document.getElementsByTagName( 'body' );
		body = body[0];
		body.style.cursor = 'auto';
	}
	
	if( AjaxRequest.numActiveAjaxGroupRequests['PseudoQuest'] < 1 )
	{
		var spinner = document.getElementById( "spinner" );
		if( spinner )
			spinner.innerHTML = "";
		
		setTimeout( "Spin();", 200 );
		return;
	}

	if( AjaxRequest.numActiveAjaxGroupRequests['PseudoQuest'] > 1 )
	{
		// Set the body's cursor to 'progress' when there's more than 1 outstanding request
		var body = document.getElementsByTagName( 'body' );
		body = body[0];
		body.style.cursor = 'progress';
	}
	
	var spinner = document.getElementById( "spinner" );
	if( !spinner )
	{
		setTimeout( "Spin();", 200 );
		return;
	}

	switch( spinner.innerHTML )
	{
		case "-":
			spinner.innerHTML = "\\";
			break;
		case "\\":
			spinner.innerHTML = "|";
			break;
		case "|":
			spinner.innerHTML = "/";
			break;
		case "/":
			spinner.innerHTML = "-";
			break;
		default:
			spinner.innerHTML = "-";
			break;
	}
	
	setTimeout( "Spin();", 200 );
}

function updatePage( request )
{
	// Verify we have a valid response
	if( !request.responseXML || !request.responseXML.documentElement )
	{
		// See if there's anything we can display, error-wise
		if( request.responseText )
			AddToErrorBox( request.responseText );
		
		return;
	}
	
	var response = request.responseXML.documentElement;
	
	// check if this is an outdated version, and if so, refresh the page
	var xml_version = response.getAttribute( "version" );
	var action = response.getAttribute( "action" );
	if( version != xml_version )
	{
		var warningbox = document.getElementById( "out_of_date_warning" );
		if( warningbox )
		{
			showing_warning = 1;
			warningbox.style.display = "block";
		}
		
		return;
	}

	// Start processing	
//	AddToErrorBox( "\n---\n" + action + "\n\n" );
	for( var i = 0, node = null; node = response.childNodes[i]; i++ )
	{
		// Determine which type of node it is, and pass it off to the appropriate handler
		switch( node.nodeName )
		{
			case "Redirect":
				window.location = node.firstChild.data;
				return;
				break;
			case "RedirectFacebook":
				top.location = node.firstChild.data;
				return;
				break;
			default:
				var the_window = GetWindow( node.nodeName );
				
//				var start_time = new Date();
				the_window.Handler( node );
//				var end_time = new Date();
				
				// Add profiling information to error box
//				AddToErrorBox( node.nodeName + ": " + ( end_time.getTime() - start_time.getTime() ) + "ms\n" );
		}
	}

	// Finally, let the game_state object know we've got the data, and can proceed with what it was doing
	game_state.HandleResponse( action, response );
}

function unloadAllChildEvents( elem )
{
	// NOTE: This function can be very, very slow.  Make sure it's worth doing before doing it.
	var children = $(elem).childElements();
	for( var index = 0, len = children.length; index < len; ++index)
	{
		var child = children[index];
		$(child).stopObserving();
		
		unloadAllChildEvents( child );
	}
}

function print_r( theObj )
{
	var retVal = "";
	
	// adapted from code found at http://www.brandnewbox.co.uk/logbook/web/javascript/printr.html
	if( theObj.constructor == Array || theObj.constructor == Object )
	{
		retVal += "<ul>";
		for( var p in theObj )
		{
			if( theObj[p].constructor == Array || theObj[p].constructor == Object )
			{
				retVal += "<li>[" + p + "] => " + typeof( theObj ) + "</li>";
				retVal += "<ul>";
				retVal += print_r( theObj[p] );
				retVal += "</ul>";
			}
			else
			{
				retVal += "<li>[" + p + "] => " + theObj[p] + "</li>";
			}
		}
		retVal += "</ul>";
	}
	
	return retVal;
}

// Cookie functions adapted from code found at http://www.quirksmode.org/js/cookies.html
function createCookie( name, value, days )
{
	var expires = "";
	if( days != undefined )
	{
		var date = new Date();
		date.setTime( date.getTime() + ( days * 24 * 60 * 60 * 1000 ) );
		expires = "; expires=" + date.toGMTString();
	}
	
	document.cookie = name + "=" + value + expires + "; path=/";
}

function readCookie( name )
{
	var nameEQ = name + "=";
	var ca = document.cookie.split( ';' );
	for( var i = 0; i < ca.length; i++ )
	{
		var c = ca[i];
		while( c.charAt( 0 ) == ' ' )
			c = c.substring( 1, c.length );
		if( c.indexOf( nameEQ ) == 0)
			return c.substring( nameEQ.length, c.length );
	}
	
	return null;
}

function eraseCookie( name )
{
	createCookie( name, "", -1 );
}

function Move( event )
{
	if( enableKeyboardMove == 0 )
		return;
	
	var dx = 0;
	var dy = 0;
	
	switch( event.keyCode )
	{
		case 37:	// left arrow
			dx = -1;
			break;
		case 39:	// right arrow
			dx = 1;
			break;
		case 38:	// up arrow
			dy = 1;
			break;
		case 40:	// down arrow
			dy = -1;
			break;
		case 13:	// enter
			break;
		default:
			return;
			break;
	}
	
	SendRequest( "move", { 'x':dx, 'y':dy } );
	event.preventDefault();
	return;
}

function SetSelectedTile( tileid, tileimg )
{
	var elem = document.getElementById( "selectedtile" );
	if( elem == null )
		return;
	
	createCookie( 'builder_tile', tileid );
	elem.src = "tiles/" + tileimg + ".gif";
	elem.alt = "tileid:" + tileid;
}

function SendLoginCredentials()
{
	var username = document.getElementById( 'login_username' ).value;
	username = username.toLowerCase();
	var pass = document.getElementById( 'login_password' ).value;
	var salt = document.getElementById( 'login_salt' ).value;
	var timestamp = document.getElementById( 'login_timestamp' ).value;
	
	var securePass = hex_sha1( salt + hex_sha1( username + pass ) );
	SendRequest( 'login',
					{ 	'username':username,
						'password':securePass,
						'timestamp':timestamp,
						'salt':salt
					}
				);
}

function SendCreateAccountData()
{
	for( i = 0; i < document.accountcreate.gender.length; i++ )
	{
		if( document.accountcreate.gender[i].checked )
		{
			gender = document.accountcreate.gender[i].value;
		}
	}
	
	var username = document.accountcreate.username_new.value;
	var email = document.accountcreate.email.value;
	var confirm_email = document.accountcreate.confirm_email.value;
	var password = document.accountcreate.password_new.value;
	var password_confirm = document.accountcreate.password_confirm.value;
	var referrer = document.accountcreate.referrer.value;
	
	// todo: fit this into the theme instead of popping up an alert
	if( password != password_confirm )
	{
		alert( "mismatched passwords" );
		return;
	}
	
	var public_modulus =  	"D5FB03BC45309103D67FA22A9EA9D1908D6296BB" +
							"FA4A3D97637ACCE7E6988123B75B9DF6C2DE0F85" +
							"E53F0774F0A36979AD47FB2BA64CC5BDDEAA56A8" +
							"BBC8944ABDCF5B2D7BF693A3DD1FD4D636F25475" +
							"E2F5C2F06285FD2E85F3DD47CCB6DBC1A4A4D00A" +
							"FF96707F80A86F2E0E7C08A323B31ED6B6FC213B" +
							"DC5407B0A7CF9D4B";

	var exponent = "10001";
	
	var rsa = new RSAKey();
	rsa.setPublic( public_modulus, exponent );
	var res = rsa.encrypt( password );
	
	if( !res )
		return;

	securePass = hex2b64(res);
	
	SendRequest( 'create_account', 
							{	'username_new': username, 
								'email':email,
								'confirm_email':confirm_email,
								'securepass':securePass,
								'gender':gender,
								'referrer':referrer
							}
				);
}

function SendCreateFacebookAccountData()
{
	for( i = 0; i < document.accountcreate.gender.length; i++ )
	{
		if( document.accountcreate.gender[i].checked )
		{
			gender = document.accountcreate.gender[i].value;
		}
	}
	
	var username = document.accountcreate.username_new.value;
	var email = document.accountcreate.email.value;
	var confirm_email = document.accountcreate.confirm_email.value;
	var referrer = document.accountcreate.referrer.value;
	
	SendRequest( 'create_facebookaccount', 
							{	'username_new': username, 
								'email':email,
								'confirm_email':confirm_email,
								'gender':gender,
								'referrer':referrer
							}
				);
}

function SendChangePassword()
{
	var username = document.getElementById( 'change_password_username' ).value;
	username = username.toLowerCase();
	var pass_old = document.getElementById( 'change_password_old' ).value;
	var pass_new = document.getElementById( 'change_password_new' ).value;
	var pass_confirm = document.getElementById( 'change_password_confirm' ).value;
	var salt = document.getElementById( 'change_password_salt' ).value;
	var timestamp = document.getElementById( 'change_password_timestamp' ).value;
	
	var oldPass = hex_sha1( salt + hex_sha1( username + pass_old ) );

	// todo: fit this into the theme instead of popping up an alert
	if( pass_new != pass_confirm )
	{
		alert( "mismatched passwords" );
		return;
	}
	
	var public_modulus =  	"D5FB03BC45309103D67FA22A9EA9D1908D6296BB" +
							"FA4A3D97637ACCE7E6988123B75B9DF6C2DE0F85" +
							"E53F0774F0A36979AD47FB2BA64CC5BDDEAA56A8" +
							"BBC8944ABDCF5B2D7BF693A3DD1FD4D636F25475" +
							"E2F5C2F06285FD2E85F3DD47CCB6DBC1A4A4D00A" +
							"FF96707F80A86F2E0E7C08A323B31ED6B6FC213B" +
							"DC5407B0A7CF9D4B";

	var exponent = "10001";
	
	var rsa = new RSAKey();
	rsa.setPublic( public_modulus, exponent );
	var res = rsa.encrypt( pass_new );
	
	if( !res )
		return;

	securePass = hex2b64(res);

	SendRequest( 'change_password',
					{ 
						'securepass':securePass,
						'oldpass':oldPass,
						'timestamp':timestamp,
						'salt':salt
					}
				);
}

function collectFormData( formid )
{
	var theForm = $( formid );
	if( theForm == null )
		return;
		
	var retval = {};
	
	for( i = 0; i < theForm.elements.length; i++ )
	{
		if( theForm.elements[i].type == "checkbox" )
		{
			retval[theForm.elements[i].name] = theForm.elements[i].checked;
		}
		else
		{
			if( theForm.elements[i].type == "radio" )
			{
				if( theForm.elements[i].checked == true )
				{
					retval[theForm.elements[i].name] = theForm.elements[i].value;
				}
			}
			else
			{
				retval[theForm.elements[i].name] = theForm.elements[i].value;
			}
		}
//		alert( theForm.elements[i].name + ":" + retval[theForm.elements[i].name] );
	}
	
	return retval;
}

function StartAddressSearch( e )
{
	var keynum = 0;
	
	if( searchTimeout )
		clearTimeout( searchTimeout );
	
	// Filter out keypresses we don't care about
	if( window.event ) // IE
		keynum = e.keyCode;
	else if( e.which ) // Netscape/Firefox/Opera
		keynum = e.which;
	
	if( keynum != 32 && keynum != 8 && keynum != 46 && 
		!( keynum >= 48 && keynum <= 57 ) &&
		( keynum < 97 || keynum > 122 ) )
		return;

	searchTimeout = setTimeout( "DoAddressSearch()", 500 );
}

function DoAddressSearch()
{
	game_state.AddressBookSearch( collectFormData( "address_search" ) );
}

// Adapted from code found at http://blog.vishalon.net/Post/57.aspx
function setCaretTo( ctrl, pos )
{
	if( ctrl.setSelectionRange )
	{
		ctrl.focus();
		ctrl.setSelectionRange( pos, pos );
	}
	else if( ctrl.createTextRange )
	{
		var range = ctrl.createTextRange();
		range.collapse( true );
		range.moveEnd( 'character', pos );
		range.moveStart( 'character', pos );
		range.select();
	}
}

function DisplayCharForumBannerCode( showcode )
{
	var code_element = document.getElementById( "char_forum_banner_code_popup" );
	if( code_element == null )
		return;
		
	var normal_element = document.getElementById( "char_forum_banner_normal" );
	if( normal_element == null )
		return;
		
	if( showcode == true )
	{
		code_element.style.display = "block";
		normal_element.style.display = "none";
	}
	else
	{
		code_element.style.display = "none";
		normal_element.style.display = "block";
	}	
}

function ChangeBuySell()
{
	SendRequest( "shop", { "shop_mode": this.value } );
}

function ChangeCategory()
{
	mode = this.getAttribute( 'mode' );
	SendRequest( "shop", { "shop_mode": mode, "category": this.value } );
}

function BuySellItem( the_event )
{
	var form_element = this;
	var mode = this.getAttribute( 'mode' );
	var shop_elements = new Array();
	shop_elements["shop_mode"] = mode;
	
	var category_element = document.getElementById( "shop_category_selector" );
	if( !category_element )
		return;
	shop_elements["category"] = category_element.value;
	
	for( i = 0; i < form_element.elements.length; i++ )
	{
		var itemid = form_element.elements[i].getAttribute( "itemid" );
		var qty = form_element.elements[i]["value"];
		
		if( qty > 0 )
			shop_elements["item_" + itemid] = qty;
	}

	if( mode == "buy" )
		SendRequest( 'buy_item', shop_elements );
	else
		SendRequest( 'sell_item', shop_elements );
		
}

function InviteFacebookFriends( form_element )
{
	SendRequest( "invite_facebook_friends" );
}

function UpdateShopTotals()
{
	var form_element = document.getElementById( "shoppanel_form" );
	if( !form_element )
		return;
	
	var total_element = document.getElementById( "shoppanel_itemrow_total_costcol" );
	if( !total_element )
		return;
	
	var max_pyrite = form_element.getAttribute( "max_pyrite" );
	var mode = form_element.getAttribute( "mode" );
	
	var total = 0;
	// Go through the child elements of the form, computing cost
	for( i = 0; i < form_element.elements.length; i++ )
	{
		cost = parseInt( form_element.elements[i].getAttribute( "cost" ) );
		qty = parseInt( form_element.elements[i]["value"] );
		max_qty = parseInt( form_element.elements[i].getAttribute( "qty" ) );
		
		if( max_qty && qty > max_qty )
		{
			qty = max_qty;
			form_element.elements[i]["value"] = qty;
		}

		if( cost && qty )
			total += qty * cost;
	}
	
	var output = "Total: " + NumberFormat( total ) + " pyrite";
	if( mode == "buy" && total > max_pyrite )
		output = "<span class='warning_text'>" + output + "</span>";

	total_element.innerHTML = output;
}

// Adapted from code found at http://www.mredkj.com/javascript/numberFormat.html#addcommas
function NumberFormat( nStr )
{
	nStr += '';	// cast to string
	x = nStr.split('.');
	x1 = x[0];
	if( x.length > 1 )
		x2 = "." + x[1];
	else
		x2 = "";

	var rgx = /(\d+)(\d{3})/;
	while( rgx.test( x1 ) )
	{
		x1 = x1.replace( rgx, '$1' + ',' + '$2' );
	}
	
	return x1 + x2;
}

// Adapted from code found at http://www.netlobo.com/url_query_string_javascript.html
function GetURLParam( name )
{
	name = name.replace( /[\[]/, "\\\[" ).replace( /[\]]/, "\\\]" );
	var regexS = "[\\?&]" + name + "=([^&#]*)";
	var regex = new RegExp( regexS );
	var results = regex.exec( window.location.href );
	if( results == null )
		return "";

	return results[1];
}

function GetWindow( window_name )
{
	if( typeof( g_handler_cache[window_name] ) != "object" )
	{
		// Load the window, add to cache, and then return it
		var script_name = "/script/handlers/" + window_name.toLowerCase() + ".js";

		// Always reload when not on production
		if( window.location.toString().search( /pseudoquest\.com/i ) != -1 &&
			window.location.toString().search( /pqdojo\.com/i ) != -1 )
		{
			script_name += "?v=" + version;
		}
		else
		{
			var temp_date = new Date();
			script_name += "?r=" + temp_date.getTime();
		}
		
		// Show loading indicator (if applicable)
		var loading_indicator = $( 'loading_indicator' );
		if( loading_indicator )
			loading_indicator.style.display = "block";
			
		Script.include( script_name );	// dynamically include the script
		
		// Hide the loading indicator, if applicable
		if( loading_indicator )
			loading_indicator.style.display = "none";

		// Make a new version of this class, and cache it for later
		if( !g_is_ie6 && !g_is_ie7 && !g_is_safari )
			g_handler_cache[window_name] = globalEval( "new PQHandler" + window_name + "();" );
		else if( g_is_safari )
		{
			g_handler_cache[window_name] = eval( "new PQHandler" + window_name + "();" );
		}
		else
		{
			g_ie_bucket = false;
			window.execScript( "g_ie_bucket = new PQHandler" + window_name + "();", "javascript" );
			g_handler_cache[window_name] = g_ie_bucket;
		}
		
		if( g_handler_cache[window_name] == false )
		{
			// We were unable to load the window script, so we're going to have a hard time doing anything else with it.
			AddToErrorBox( "Error: Unable to load handler for " + window_name );
			return false;
		}
	}
	
	return g_handler_cache[window_name];
}

function AddToErrorBox( text )
{
	// Spit out error information gracefully, maybe to a normally-hidden status box
	var errorBox = $( "errorbox" );

	if( errorBox )
	{
		errorBox.value += text;
		errorBox.style.display = "block";
	}
	else
		alert( text );
}

// A helper function for randomly ordering an array
function RandomOrder()
{
	return ( Math.round( Math.random() ) - 0.5 );
}

function htmlentities( s )
{
	// http://kevin.vanzonneveld.net
	// +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
	// *     example 1: htmlentities('Kevin & van Zonneveld');
	// *     returns 1: 'Kevin &amp; van Zonneveld'

	var div = document.createElement( 'div' );
	var text = document.createTextNode( s );
	div.appendChild( text );
	
	return div.innerHTML;
}

// Prototype's update, insert, and replace functions call evalScripts even when there's no need to, so extend it with our own version that doesn't call these
Element.addMethods( {
  update: function(element, content) {
	element = $(element);
    if (content && content.toElement) content = content.toElement();
    if (Object.isElement(content)) return element.update().insert(content);
    content = Object.toHTML(content);
    element.innerHTML = content;
    return element;
  },

  replace: function(element, content) {
    element = $(element);
    if (content && content.toElement) content = content.toElement();
    else if (!Object.isElement(content)) {
      content = Object.toHTML(content);
      var range = element.ownerDocument.createRange();
      range.selectNode(element);
    }
    element.parentNode.replaceChild(content, element);
    return element;
  },

  insert: function(element, insertions) {
    element = $(element);

    if (Object.isString(insertions) || Object.isNumber(insertions) ||
        Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
          insertions = {bottom:insertions};

    var content, insert, tagName, childNodes;

    for (var position in insertions) {
      content  = insertions[position];
      position = position.toLowerCase();
      insert = Element._insertionTranslations[position];

      if (content && content.toElement) content = content.toElement();
      if (Object.isElement(content)) {
        insert(element, content);
        continue;
      }

      content = Object.toHTML(content);

      tagName = ((position == 'before' || position == 'after')
        ? element.parentNode : element).tagName.toUpperCase();

      childNodes = Element._getContentFromAnonymousElement(tagName, content);

      if (position == 'top' || position == 'after') childNodes.reverse();
      childNodes.each(insert.curry(element));
    }

    return element;
  }
});

// Clone adapted from code found at http://keithdevens.com/weblog/archive/2007/Jun/07/javascript.clone
function clone( obj )
{
    if( obj == null || typeof( obj ) != 'object' )
        return obj;

    var temp = new obj.constructor();
    for( var key in obj )
        temp[key] = clone( obj[key] );

    return temp;
}

// globalEval adapted from code found at http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
// as well as portions of jquery 1.2.6
function globalEval( data )
{
	if( !g_is_ie6 && !g_is_ie7 && !g_is_safari )
	{
		return (	function( code )
					{
						return eval.call( window, code );
					}
				)( data );
	}
	else if( g_is_safari == true )
	{
		var head = document.getElementsByTagName("head")[0] || document.documentElement;
		var script = document.createElement("script");

		script.type = "text/javascript";
		
		if ( g_is_ie6 || g_is_ie7 )
			script.text = data;
		else
			script.appendChild( document.createTextNode( data ) );

		// Use insertBefore instead of appendChild  to circumvent an IE6 bug.
		// This arises when a base node is used (#2709).
		head.insertBefore( script, head.firstChild );
		head.removeChild( script );
	}
	else
	{
		window.execScript( data, 'javascript' );
	}
}

// Adapted from code found at http://stackoverflow.com/questions/593419/how-do-you-dynamically-load-a-javascript-file-from-different-domain
var Script = {
	_loadedScripts: [],
	
	include: function(script)
	{
		// include script only once
		if( this._loadedScripts.include( script ) )
		{
			return false;
		}

		// request file synchronous
		var code = new Ajax.Request(script, {
				asynchronous: false, 
				method: "GET",
				evalJS: false, 
				evalJSON: false
			}).transport.responseText;

		// eval code on global level
		if( Prototype.Browser.IE )
		{
			window.execScript(code);
		}
		else if( Prototype.Browser.WebKit )
		{
			$$("head").first().insert( 
				Object.extend(
					new Element( "script", { 'type': "text/javascript" } ), { 'text': code }
				)
			);
		}
		else
		{
			window.eval(code);
		}

		// remember included script
		this._loadedScripts.push( script );
	}
};
