/*
* DiceRoller.js  v0.6
*
* Javascript functions associated with the DiceRoller extension
*
*
Copyright 2007-2008 Arturo Gonzalez-Escribano
This file is part of Lussumo's Software Library.
Lussumo's Software Library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
Lussumo's Software Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with Vanilla; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
The latest source code is available at www.lussumo.com
Contact Arturo González-Escribano at arturo [at] infor [dot] uva [dot] es

*
*/


/*
* v0.5.1: Global properties
*
*	initState: Determines if the rolls are hidden or visible when page is loaded
*	initSort: Determines if results are sorted when page is loaded
*	initSum: Activates/Deactivates sum function when page is loaded
*	initTypes: Activates/Deactivates showing the dice-types when page is loaded
*
*	funcShow: Determines if the function to automatically show the results 
*				when the mouse is over a dice-specification is activated, or 
*				if the user can only use the cliking method to show the results 
*				when they are hidden.
*
*/
var DR_initState = "show";		// Possible values: "hide", "show"
var DR_initSort = "up";			// Possible values: "no", "up", "down"
var DR_initSum = "yes";			// Possible values: "no", "yes"
var DR_initTypes = "no";		// Possible values: "no", "yes"

var DR_funcShow = "onmouseover"; // Possible values: "onmouseover", "onclick"



/*
* v0.5.1: Global variable to record roll formatting properties and data
*/
var DR_rollProperties = new Array();


/*
* Functions for presentation of dice-roll results
*
* Several functions associated with the presentation of dice results in the
* comment text, and with the selection of options through a context menu.
*/

/*
* v0.5.1
* If javascript is active, on page load we initialize properties of rolls 
*	and we format the result-strings accordingly.
* If javascript is not active the basic result-strings created by the PHP 
*	code in the server are visible.
*/
var DR_oldOnload = window.onload;
window.onload = DR_initRolls;


/*
* v0.5.1
* DR_initRolls: Hide/show all the rolls in the page according to initialization
*				parameters (to be activated on page load)
*/
function DR_initRolls() {
	// Get all the dice description elements
	var allRolls = document.getElementsByName("DR_dice");

	// For each dice roll
	var i;
	for (i=0; i<allRolls.length; i++) {
		// Declare and initialize the formatting properties for the id
		var id = allRolls[i].id;
		DR_rollProperties[id]["task"] = DR_initState;
		DR_rollProperties[id]["sort"] = DR_initSort;
		DR_rollProperties[id]["sum"] = DR_initSum;
		DR_rollProperties[id]["types"] = DR_initTypes;

		// Attach properties to the parent for easy reference on the menu code
		allRolls[i].parentNode.DR_info = DR_rollProperties[id];

		// Attach the menu functions to the results-string element
		var rollText = allRolls[i].parentNode.childNodes[1];
		rollText.onmousedown = DR_joinMenu;
		rollText.onmouseup = DR_closeMenu;

		// Show/Hide the roll according to the init properties
		DR_diceToggle( allRolls[i] );
	}

	// Call the old onload function
	DR_oldOnload;
}

/*
* DR_hideRolls: Hide all the rolls in the page (to be activated on page load)
*	Deprecated in v0.5.1 (All this functionality is now in DR_initRolls)
*/
function DR_hideRolls() {
	var allRolls = document.getElementsByName("DR_rolls");
	for (i=0; i<allRolls.length; i++) {
		allRolls[i].innerHTML = "";
	}
	DR_oldOnload;
}




/*
* DR_diceShow: Show dice-roll information
* 	v0.5.1: Complete new function definition
*/
function DR_diceShow( elem ) {
	if (DR_funcShow == "onmouseover") {
		var info = DR_rollProperties[ elem.id ];
		info["task"]="show";
		DR_diceToggle( elem );
	}
}


/*
* DR_diceToggle: Toggle (hide/show) dice-roll information
*/
function DR_diceToggle( elem ) {
	var parentElem = elem.parentNode;
	var rollText = parentElem.childNodes[1];

	// v0.5.1: Get properties
	var info = DR_rollProperties[ elem.id ];
	var taskValue = info["task"];

	// Change visibility status and do the task (hide or show)
	if (taskValue == "hide") {
		info["task"] = "show";
		rollText.innerHTML = "";
		rollText.style.margin = "0px";
		rollText.style.padding = "0px";
	}
	else {
		info["task"] = "hide";
		rollText.style.margin = "0 4px 0 4px";
		rollText.style.padding = "0 8px 0 8px";
		DR_rollShow ( rollText, info );
	}
}


/*
* DR_rollShow: Update content with the given formatting properties
*/
function DR_rollShow( elem, info ) {
	elem.innerHTML = DR_rollString( info["roll"], info["sort"], 
												info["sum"], info["types"] );
}


/*
* DR_compare: Compare the numeric value of two dice-rolls for sorting
*/
function DR_compare( a, b ) {
	var sizesA = a.split("d");
	var sizesB = b.split("d");
	return sizesA[0] - sizesB[0];
}

/*
* DR_rollString: Build the roll string, sorting if necessary
*/
function DR_rollString( rollValue, sortValue, sumValue, typesValue ) {
	var rollString;

	// Split array of numbers
	var arr = rollValue.split(" ");

	// v0.6: Take out the modifier if it exists
	var modifier = arr[arr.length-1].split("d");
	if ( !modifier[1] ) arr.pop();

	// Sorting
	if ( sortValue != "no" ) {
		arr.sort(DR_compare);
		if ( sortValue == "down" ) arr.reverse();
	}

	// v0.5: Process values (hide/show sizes and optional sum)
	var total = 0;
	var i;
	for (i=0; i<arr.length; i++) {
		// Split result
		var sizes = arr[i].split("d");

		// Sum
		if ( sumValue=="yes" ) {
			// v0.4 patch:
			// Force base 10 parsing, to avoid 08 and 09 to be incorrectly 
			// parsed as base 8 numbers
			total += parseInt(sizes[0], 10); 
		}

		// v0.6: Backwards compatibility with previous versions storing system
		sizes[0] = '' + parseInt(sizes[0], 10); 

		// v0.6: Special layout of d00 results, always two digits
		if ( sizes[1] == '00' && sizes[0].length == 1 ) 
			sizes[0] = '0' + sizes[0];

		// Result string: Skip or add dice sizes
		if ( typesValue=="yes") {
			arr[i]= sizes[0] + "<sub>d" + sizes[1] + "</sub>";
		}
		else arr[i]= sizes[0];
	}

	// v0.6: Process modifier if it exists
	if (!modifier[1]) {
		if ( sumValue=="yes" ) {
			// Add modifier to the total sum
			total += parseInt(modifier[0], 10); 
			// v0.4: Mark modifiers with brackets in the sum
			modifier[0] = "[" + modifier[0] + "]"; 	
		}
		// Add modifier string at the end
		arr.push( modifier[0] );
	}

	// Join elements
	if ( sumValue=="yes" && arr.length>1 ) {
		rollString = arr.join(" + ");
 		rollString += " = " + total;
	}
	else if ( typesValue=="yes") {
		rollString = arr.join("&nbsp; ");
	}
	else {
		rollString = arr.join(", ");
	}

	return rollString;
}



/*
* Global variables for the context menu
*/
var DR_menu = null;
// This array is filled with language dependent definitions from the PHP code
var DR_options = new Array(4);  

/*
* DR_joinMenu: Joins the hidden menu to an element. It creates it the first
*	time.
*/
function DR_joinMenu( event ) {
	// Create it the first time
	if (DR_menu == null) {
		DR_menu = document.createElement("div");
		DR_menu.className = "DR_menu";

		for (i=0; i<DR_options.length; i++) {
			// New lines for all except first
			if (i!==0) {
				br = document.createElement("br");
				DR_menu.appendChild( br );
			}
			// Create and add option
			option = document.createElement("a");
			option.className = "DR_menuOption";
			option.onmouseup = DR_menuOption;

			// Trick to simulate correct CSS hover behaviour in IExplorer
			option.onmouseover = new Function("this.className = 'DR_menuOptionOver'");
			option.onmouseout = new Function("this.className = 'DR_menuOption'");

			option.innerHTML = DR_options[i];
			option.setAttribute( "numOpt", i );

			DR_menu.appendChild( option );
		}
	}
	// Join it	
	var parentElem = this.parentNode;
	parentElem.appendChild( DR_menu );

	var pos = DR_getMousePos( event );
	DR_menu.style.left= pos.x + "px";
	DR_menu.style.top= pos.y + "px";

	// Stop selecting text
	document.onmousedown = new Function("return false;"); // NE browser family
	document.onselectstart = new Function("return false;"); // IE browser family

	// Close menu when releasing the button outside of the menu options 
	document.onmouseup = DR_closeMenu; // NE browser family
}


/*
* DR_getMousePos: Adapter to get mouse position on as many browses as possible
*/
function DR_getMousePos(e) {
	var result = new Object();

	if (!e) e = window.event;
	if (e.pageX) {
		result.x = e.pageX;
		result.y = e.pageY;
		}
	else if (e.clientX) {
		result.x = e.clientX;
		result.y = e.clientY;
		if ( ! document.documentElement.scrollLeft )
			result.x += document.body.scrollLeft;
		else result.x += document.documentElement.scrollLeft;

		if ( ! document.documentElement.scrollTop ) 
			result.y += document.body.scrollTop;
		else result.y += document.documentElement.scrollTop;
	}
	else return null;

	return result;
}


/*
* DR_menuOption: Actions associated with the options of the menu
*/
function DR_menuOption( ) {
	elem = this;
	var parentElem = elem.parentNode;
	var ancestorElem = parentElem.parentNode;
	var rollElem = ancestorElem.childNodes[1];

	var info = ancestorElem.DR_info;
//	var info = DR_rollProperties[ ancestorElem.childNodes[0].id ];

	opt = elem.getAttribute("numOpt");
	if ( opt==0 ) {
		info["sort"] = "no";		
		DR_rollShow( rollElem, info );
	}
	else if ( opt==1 ) {
		info["sort"] = "up";		
		DR_rollShow( rollElem, info );
	}
	else if ( opt==2 ) {
		info["sort"] = "down";		
		DR_rollShow( rollElem, info );
	}
	else if ( opt==3 ) {
		info["sum"] = (info["sum"]=="no") ? "yes":"no";
		DR_rollShow( rollElem, info );
	}
	else if ( opt==4 ) {
		info["types"] = (info["types"]=="no") ? "yes":"no";
		DR_rollShow( rollElem, info );
	}

	// Trick to simulate pseudoclass :hover normal behaviour in IExplorer 
	// (back to non-highlighted class)
	elem.className = "DR_menuOption";

	// Any option chosen: Hide menu
	DR_closeMenu();
}


/*
* DR_closeMenu: Hide menu removing it from the document hierarchy
*/
function DR_closeMenu() {
	var parentElem = DR_menu.parentNode;
	parentElem.removeChild( DR_menu );

	// Normal mouse behaviour
	document.onmousedown = null; // NE browser family;
	document.onmouseup = null; // NE browser family;
	document.onselectstart = null; // IE browser family;
}


/*
* DR_beb: DiceRoller 'block edit button'
*
*	Invoked just after the Comment options has been rendered, it searchs and
*	blocks the edit button for that comment.
*
*	For eficiency, the php code should include the call to this script
*	only when the AuthUserID is the UserID, but if the button does not exist 
*	the script does not complain.
*
*/
function DR_beb( id, editText ) {
	var scriptElement=document.getElementById(id); 
	var parentElement=scriptElement.parentNode; 
	var i=0; 
	var sibling=parentElement.childNodes[0]; 

	// Locate an anchor sibling with the text of the edit button 
	while(sibling!=null) {
		if (sibling.nodeType==1 
					&& sibling.nodeName == "A" 
					&& sibling.innerHTML == editText ) {
			// Eliminate the link
			parentElement.removeChild( sibling );
			break;
		} 
		i=i+1; 
		sibling=parentElement.childNodes[i]; 
	}
} 

