// Script to provide functionality to submit a high-score.
// Dependencies:
//				submitform.php
//        Cookie.js
//        ChkBrowser.js

// Written by Stephen Battey
// November 2006




//---------------------- The Hi-Score Class ----------------------


// Constructor for a HiScore that gets submitted to the hiscore table.

// gameId    : int     - id for the game the score was made
// score     : int     - the score made by the player
// extraInfo : String  - additional information to the score (e.g. the level the player made it to)

function HiScore( gameId, score, extraInfo )
{
	this.gameId = gameId;
	this.score = score;
	this.extraInfo = (extraInfo) ? extraInfo : "";
}




//---------------------- The PlayerDetails Class ----------------------


// Constructor for a PlayerDetails object that is submitted with the score to the hiscore table.

// name     : String   - the player's name (30 chars max)
// location : String   - the player's location (40 chars max)

function PlayerDetails( name, location )
{
	if (name)
	// use arguments to set attributes (location defaults to blank string)
	{
		this.setName( name );
		if (location)
			this.setLocation( location );
		else
			this.setLocation( "" );
	}
	else
	// restore attributes from cookie
	{
		this.restore();
	}
}

PlayerDetails.prototype.setName = function( name )
{
	if (name == null)
		this.name = "";
	else
		this.name = name.substring( 0, PlayerDetails.MAX_NAME_LEN );
}

PlayerDetails.prototype.setLocation = function( location )
{
	if (location == null)
		this.location = "";
	else
		this.location = location.substring( 0, PlayerDetails.MAX_LOCATION_LEN );
}

PlayerDetails.prototype.restore = function()
{
	if (PlayerDetails.COOKIE.exists)
	{
		var sepIndex = PlayerDetails.COOKIE.value.indexOf( PlayerDetails.COOKIE_VALUE_SEPARATOR );
		if (sepIndex == -1)
		{
			// take name from the cookie and default the location to blank
			this.setName( PlayerDetails.COOKIE.value );
			this.setLocation( "" );
		}
		else
		{
			// take name from what is before the separator, take location from after the separator
			this.setName( PlayerDetails.COOKIE.value.substring( 0, sepIndex ) );
			this.setLocation( PlayerDetails.COOKIE.value.substring( sepIndex + PlayerDetails.COOKIE_VALUE_SEPARATOR.length ) );
		}
	}
	else
	{
		// restore to initial (blank) values
		this.setName( "" );
		this.setLocation( "" );
	}
}

PlayerDetails.prototype.save = function()
{
	PlayerDetails.COOKIE.set( this.name + PlayerDetails.COOKIE_VALUE_SEPARATOR + this.location, PlayerDetails.COOKIE_DURATION );
}

PlayerDetails.COOKIE = new Cookie( "debugged_player_details" );
PlayerDetails.COOKIE_DURATION = 1000 * 60 * 60 * 24 * 60;       // 60 days
PlayerDetails.COOKIE_VALUE_SEPARATOR = ">==>";

PlayerDetails.MAX_NAME_LEN = 30;
PlayerDetails.MAX_LOCATION_LEN = 40;




//---------------------- Generic Submit-Score Routines ----------------------


// A Boolean flag that indicates if the scores are set and waiting to be submitted.
var scoreSubmitInUse = false;

// Array of HiScores  - the scores to be submitted
var scoresBeingSubmitted = null;


// The main entry point. This is the method that should be called from the game over
// routine of the specific game/program, passing the scores to be submitted.

// This function checks the submit form is present and then calls one of the 'prompt user' algorithms.

// scores : Array of HiScores  - the scores to be submitted

function promptSubmitScore( scores )
{
	
	// check the submission form is present
	var submitForm = document.scoresubmit;
	if (!submitForm)
	{
		alert( "Sorry, your score cannot be submitted for consideration as a high score.\nThis page does not support score submission." );
		return;
	}
	
	// check the form is big enough
	if (scores.length > 4)
	{
		alert( "Sorry, your score cannot be submitted for consideration as a high score.\nThis page does not support " + scores.length + " simultaneous score submissions." );
		return;
	}
	
	
	// activate the score submission
	// These variables get reset at the end of the doSubmitScore function.
	scoreSubmitInUse = true;
	scoresBeingSubmitted = scores;
	
	
	// try prompting the user with a DHTML form
	var usedDhtmlForm = promptForNameUsingDhtml();
	if (!usedDhtmlForm)
	{
		// as a backup measure, use a dialog box instead
		promptForNameUsingDialogs();
	}
		
}




// The callback point for the 'prompt user' algorithms.
// Once the user has been prompted to accept submission and enter their name/location
// the player details will be sent back to this function.

// This function populates the submit form and submits the scores.

// playerDetails : PlayerDetails      - the player's name and location

function doSubmitScore( playerDetails )
{
	if (!scoreSubmitInUse)
	{
		return;
	}
	
	var submitForm = document.scoresubmit;
	// NB: the scoreSubmitInUse flag being set to true in promptSubmitScore assures us the form exists.
	
	// check if the user has failed to confirm their name
	if (playerDetails != null)
	{
		// clear *all* fields (reset method does not clear hidden fields)
		//submitForm.reset();
		for (var i=0; i<submitForm.elements.length; i++)
		{
			submitForm.elements[i].value = "";
		}
		
		// populate player details
		submitForm.name.value = playerDetails.name;
		submitForm.location.value = playerDetails.location;
		
		// populate hi-score details
		for (var i=0; i<scoresBeingSubmitted.length; i++)
		{
			var gameFieldName = "game" + (i + 1);
			var scoreFieldName = "score" + (i + 1);
			var infoFieldName = "extrainfo" + (i + 1);
			
			submitForm.elements[gameFieldName].value = scoresBeingSubmitted[i].gameId;
			submitForm.elements[scoreFieldName].value = scoresBeingSubmitted[i].score;
			submitForm.elements[infoFieldName].value = scoresBeingSubmitted[i].extraInfo;
		}
		
		if (scoresBeingSubmitted.length > 0)
		{
			// set authentication key
			submitForm.authenticationkey.value = generateAuthKey( scoresBeingSubmitted[0].gameId );
		}
		
		submitForm.submit();
	}
	
	
	// deactivate the score submission
	// These variables get set in the middle of the promptSubmitScore function.
	scoreSubmitInUse = false;
	scoresBeingSubmitted = null;
	
}




// Generates an authentication key, which verifies the score as a genuine game score.

// return : int   - an authentication key

function generateAuthKey( game )
{
	var key = debuggedGameAuthenticationKey;
	
	key = key << 6;
	key = key | game;
	
	return key;
}




//---------------------- Submit-Score Routine That Uses Window Dialogs ----------------------


// Prompts the player for their name, using dialog windows.

function promptForNameUsingDialogs()
{
	var playerDetails = null;
	
	if (window.confirm( "Would you like to submit your score to the hi-score table?" ))
	{
		playerDetails = new PlayerDetails();
		
		var name = window.prompt( "Please enter your name.\n(" + PlayerDetails.MAX_NAME_LEN + " characters max)", playerDetails.name );
		if (name == null)
			playerDetails = null;
		else
		{
			playerDetails.setName( name );
			playerDetails.save();
			
			var location = window.prompt( "Please enter your location.\n(" + PlayerDetails.MAX_LOCATION_LEN + " characters max)", playerDetails.location );
			if (location == null)
				playerDetails = null;
			else
			{
				playerDetails.setLocation( location );
				playerDetails.save();
			}
		}
	}
	
	doSubmitScore( playerDetails );
}




//---------------------- Submit-Score Routine That Uses DHTML ----------------------


// The HTML Div element that contains the player details entry form.
var submitDialog = null;

// The player details entry form.
var submitDialogForm = null;


// Prompts the player for their name, using DHTML elements and forms.
// Returns false if the browser does not support DHTML or the expected DHTML
// element/form does not exist.

function promptForNameUsingDhtml()
{
	if (!document.getElementById)
		return false;
	
	submitDialog = document.getElementById( "scoresubmitdialog" );
	if (typeof( submitDialog ) == "undefined")
		return false;
	
	submitDialogForm = document.playerdetailsentry;
	if (typeof( submitDialogForm ) == "undefined")
		return false;
	
	var playerNameInput = submitDialogForm.playername;
	var playerLocationInput = submitDialogForm.playerlocation;
	if (   (typeof( playerNameInput ) == "undefined")
	    || (typeof( playerLocationInput ) == "undefined")  )
		return false;
	
	
	// populate form with latest player details
	var playerDetails = new PlayerDetails();
	playerNameInput.value = playerDetails.name;
	playerLocationInput.value = playerDetails.location;
	
	// show the submit form
	centrePosition( submitDialog );
	submitDialog.style.display = "inline";
	
	// place focus on the player name input field
	// This has to be done after a delay to take effect in Netscape.
	window.setTimeout( "submitDialogForm.playername.select();", 25 );
	window.setTimeout( "submitDialogForm.playername.focus();", 30 );
	
	return true;
}

function closeSubmitDialog( doSubmit )
{
	if (   (submitDialog == null)
	    || (submitDialogForm == null)  )
	{
		// These variables have not been set up by the promptForNameUsingDhtml function.
		// This function has been called out of turn.
		return;
	}
	
	// store changes made to the player's details
	var playerDetails = new PlayerDetails();
	playerDetails.setName( submitDialogForm.playername.value );
	playerDetails.setLocation( submitDialogForm.playerlocation.value );
	playerDetails.save();
	
	// close the dialog
	submitDialog.style.display = "none";
	
	if (doSubmit)
	{
		doSubmitScore( playerDetails );
	}
}




//---------------------- Utility Method ----------------------


// This function may fail if the width and height properties of the element are not set
// (this requires the values to be set either via JavaScript of the style attribute, using
// CSS does not work!)
// This function returns a Boolean value indicating if the element was centrally positioned.

function centrePosition( element )
{
	var elementWidth = parseInt( element.style.width );
	var elementHeight = parseInt( element.style.height );
	
	if (   (isNaN( elementWidth ))
	    || (isNaN( elementHeight ))  )
		return false;
	
	var pageWidth = ChkBrowser.singleton().get_view_width();
	var pageHeight = ChkBrowser.singleton().get_view_height();
	
	element.style.left = "" + Math.floor( (pageWidth - elementWidth) / 2 ) + "px";
	element.style.top = "" + Math.floor( (pageHeight - elementHeight) / 2 ) + "px";
	
	//alert( "Width: element=" + elementWidth + "; page: " + pageWidth + "; posn: " + element.style.left
	//       + "\n" +
	//       "Width: element=" + elementHeight + "; page: " + pageHeight + "; posn: " + element.style.top );
	
	return true;
}
