//returns a reference to a document element
//params : elem_id - id of the desired element
//DEPRECATED - USE utilities.getElement instead
function get_elem(elem_id)
{
	if (document.getElementById){
		return document.getElementById(elem_id);
	}
	else if (document.all){
		return document.all(elem_id);
	}
	
	return false;
}

//tries to set a field to the given value
//at the moment only handles text inputs
function set_field(elem_id, value)
{
	value = value ? value : "";

	try{
		field = get_elem(elem_id);
		switch(field.type){
			case "text":
			case "textarea":
				field.value = value;
				break;
			
			case "checkbox":
				field.checked = value;
				break;
			
			case "select-one":
				field.value = value;
				break;
				
			default:
				alert("set_field does not support fields of type '" + field.type + "'");
		}
	}
	catch(e){
		alert("Could not set field\n" + e.description);
	}
}

function pop_print(web_url) {
	var PrintWindow;
	PrintWindow = window.open (web_url, "BigEditWindow", "toolbar=no,scrollbars=yes,location=no,resizable=yes,height=500,width=500");
	PrintWindow.focus();
	return PrintWindow;
}

//set up static class
function utilities(){}

//browser check
utilities.browserType = (document.all ? "IE" : "Moz");

//returns a reference to a document element from an id
utilities.getElement = function(elementId)
{
	if (document.getElementById)
		return document.getElementById(elementId);
	else if (document.all)
		return document.all(elementId);
	
	return false;
}

//add an event to the specified element, TESTED ON: IE 5.5+ & Moz
//very useful if event may already be assigned
utilities.addEvent = function(elem, evname, func) 
{
	if (utilities.browserType == "IE") 
	{
		elem.attachEvent("on" + evname, func);
	} else 
	{
		elem.addEventListener(evname, func, true);
	}
};

//add an event to the multiple elements
utilities.addEvents = function(elems, evname, func) 
{
	for (var i in elems)
	{
		utilities._addEvent(elems[i], evname, func);
	}
};

//remove an event from the specified element, TESTED ON: IE 5.5+ & Moz
utilities.removeEvent = function(elem, evname, func) 
{
	if (utilities.browserType == "IE") 
	{
		elem.detachEvent("on" + evname, func);
	} else 
	{
		elem.removeEventListener(evname, func, true);
	}
};

//remove an event from multiple elements, TESTED ON: IE 5.5+ & Moz
utilities.removeEvents = function(elems, evname, func) 
{
	for (var i in elems)
	{
		utilities._removeEvent(elems[i], evname, func);
	}
};

//convert decimal to hexidecimal
utilities.hexChars = "0123456789ABCDEF";
utilities.decToHex = function(dec_num){
	var hex_num;
	
	hex_num = utilities.hexChars.charAt(dec_num/16);
	hex_num += utilities.hexChars.charAt(dec_num%16);
	
	return hex_num;
}

//generate a password of specified size
utilities.passwordChars = new Array();
utilities.generate_password = function(size){
	var password = "";
	
	(! size) && (size = 8);	
	
	//we only have to generate passwordChars once, yay!!!
	if (utilities.passwordChars.length == 0)
	{
		for (i = 0; i <= 9; i++)
		{
			utilities.passwordChars.push( i );
		}
		for (i = 65; i <= 90; i++)
		{
			utilities.passwordChars.push( unescape("%"+ utilities.decToHex(i) ) );
		}
		for (i = 97; i <= 122; i++)
		{
			utilities.passwordChars.push( unescape("%"+ utilities.decToHex(i) ) );
		}
	}
	
	for(i = 0; i < size; i++)
	{
		password += utilities.passwordChars[Math.floor(Math.random() * utilities.passwordChars.length)];
	}

	return password;
}

//Appends query to end of url, adds necessary & or ?
utilities.appendURLQuery = function(url, query) {
	return url + (url.match("\\?") ? "&" : "?") + query;
};

//Toggle checked status on all the checkboxes in the given form
//default is the state of the checkboxes when first called, after that
//it switches between states
utilities.selected = {};
utilities.selectAll = function(formId, defaultState)
{
	try
	{
		form = get_elem(formId);
		
		if (! form || form.nodeName.toUpperCase() != "FORM")
		{
			throw("No form element given");
		}

		if (! utilities.selected[formId])
			utilities.selected[formId] = (defaultState != undefined ? defaultState : true);
		else
			utilities.selected[formId] = !utilities.selected[formId];

		for (var i = 0; i < form.elements.length; i++)
		{
			if (form.elements[i].type == "checkbox")
				form.elements[i].checked = utilities.selected[formId];
		}
	}
	catch(e){
		alert(e);
	}	
}

utilities.confirmDelete = function(recType) {
	var msg = "Are you sure that you want to delete " + recType + "?";
	if (confirm(msg)) {
		return(true);
	} else {
		return(false);
	}
}

/**
* @return void
* @param HTMLSelectElement select
* @param HTMLOptionElement option
* @param integer insertAt
* @param boolean allowDuplicates
* @desc Inserts the option into the select element at the position specified by insertAt.
* If insertAt is -1, option is inserted after currently selected option.
* If insertAt is null, option is inserted at end of list.
* allowDuplicates specifies whether duplicate entres are allowed.
*/
utilities.insertOption = function(select, option, insertAt, allowDuplicates)
{
	/* default to false */
	(allowDuplicates == undefined) && (allowDuplicates = false);
	
	if (! allowDuplicates)
	{
		/* loop through each option and check if it has the same text/value pair */
		for (var i = 0; i < select.options.length; i++)
		{
			if (select.options[i].text == option.text
				&& select.options[i].value == option.value)
			{
				alert("Item '" + option.text + "' already in list");
				return;
			}
		}
	}
	
	/* if insertAt is not defined, insert after selected option */
	if (insertAt == -1)
		insertAt = select.options.selectedIndex + 1;
	
	/* if insertAt is still not valid, add to end of list */
	if (! insertAt || insertAt < 0)
		insertAt = select.options.length;

	/* move each option */
	for (var i = select.options.length; i > insertAt; i--)
		select.options[i] = new Option(select.options[i - 1].text, select.options[i - 1].value);
	
	/* insert new option */
	select.options[insertAt] = option;
}

/**
* @return void
* @param string sourceSelectId
* @param string seperator
* @desc Converts all entries in source select to a string seperated by seperator
*/
utilities.selectToString = function(sourceSelectId, seperator)
{
	(! seperator) && (seperator = ";");
	
	sourceSelect = document.getElementById(sourceSelectId);
	
	var data = "";
	for (var i = 0; i < sourceSelect.options.length; i++)
		data += (data ? seperator : "") + sourceSelect.options[i].value;
	
	return data;
}

/**
* @return void
* @param string sourceSelectId
* @param string data
* @param string seperator
* @desc Splits data by seperator and adds each section to target select
*/
utilities.populateSelect = function(targetSelectId, data, seperator)
{
	(! seperator) && (seperator = ";");
	
	targetSelect = utilities.getElement(targetSelectId);
	
	var items = data.split(seperator);
	
	if (items[0])
	{
		for(var i in items)
			targetSelect.options[targetSelect.options.length] = new Option(items[i], items[i]);
	}
}

/**
* @return void
* @param mixed element
* @desc Toggles the visibility state of the element given by element
* element can be either a reference to the element of the id of the element
*/
utilities.toggleVisibility = function(element)
{
	/* if we have element id, get the element */
	if (typeof(element) == "string")
		element = utilities.getElement(element);

	if (element.style.display == "block")
	{
		element.style.display = "none";
	}
	else
	{
		element.style.display = "block";
	}
}

/**
* @return window
* @param string url
* @param integer winWidth
* @param integer winHeight
* @param integer winLeft
* @param integer winTop
* @param string winTarget
* @param string extraAttributes
* @desc Opens a browser window and returns it's instance.
* @author Dayl & Flash
*/
utilities.openWindow = function(url, winWidth, winHeight, winTarget, extraAttributes)
{
	
	if (! extraAttributes) {extraAttributes = 'toolbar=1,location=0,resizable=1,scrollbars=1,menubar=1';}
	if (winWidth)  {extraAttributes += ',width='+ winWidth;}
	if (winHeight) {extraAttributes += ',height='+ winHeight;}
	if (! winTarget) {winTarget = 'flash';}

	newWindow = window.open(url, winTarget, extraAttributes);
	newWindow.focus();
	
	return newWindow;
}

/**
* @return window
* @param string url
* @desc Opens a browser window for help.
* @author GL
*/
utilities.openHelpWindow = function(url)
{

	newWindow = window.open(url, "", "toolbar=no,scrollbars=yes,location=no,resizable=yes,height=600,width=750");
	newWindow.focus();
	
	return newWindow;
}

/**
* @return string
* @param string elementId
* @param string text
* @desc Appends the text 'text' to the end of the element specified by elementId
* @author Osama! 
*/
utilities.appendToInnerHTML = function(elementId, text)
{
	myElement = utilities.getElement(elementId);
	myElement.innerHTML += text;
}

/**
* @return void
* @param string url
* @param integer target
* @desc Redirects the window specified by 'target' to the url specified by 'url'
* If target is not specified, will default to current window
* If url is not specified, will reload the desired window
* @author Flash
*/
utilities.redirectPage = function(url, target)
{
	/* default target to current window */
	if (! target)
		target = window;
	
	/* default location to target's own location (reload itself) */
	if (! url)
		url = target.location.href;
		
	target.location = url;
}
		
/**
* @return string
* @param mixed element
* @param string cssStyle
* @param string jsStyle
* @desc Gets the desired style of 'element', needed if you are wanting to get styles that aren't
* inline to the element (e.g. specified in <style> tags or set in external stylesheet)
* 'element' can be either a reference to the element of the id of the element
* 'cssStyle' is the original css style name of the desired style
* 'jsStyle' is the javascript style name of the desired style, if not set, it will try to guess from
* the cssStyle
* @author Flash
*/
utilities.getStyle = function(element, cssStyle, jsStyle)
{
	/* if we have element id, get the element */
	if (typeof(element) == "string")
		element = utilities.getElement(element);
		
	/* try to guess js style if not set */
	if (! jsStyle)
	{
		/* replace -x with X, with x being any character */
		jsStyle = cssStyle.replace(/-([a-zA-Z])/g, 
				function(fullMatch, subMatch1, position)
				{
					return subMatch1.toUpperCase()
				}
			);
	}
	
	/* mozilla way using cssStyle */
    if (window.getComputedStyle)
    {
        return window.getComputedStyle(element, "").getPropertyValue(cssStyle);
    }
    /* IE way using jsStyle */
    else if (element.currentStyle)
    {
        return element.currentStyle[jsStyle];
    }
}

/**
* @return void
* @param object selectBox1
* @param object selectBox2
* @param string selectBox1ArrayName
* @desc Checks the selected value in SelectBox1 and uses it to update the contents of SelectBox2
* You need to create a group of predefined arrays for the values and options to be loaded into SelectBox2
* for each value of SelectBox1.
* This group of arrays should be defined as follows:
* var 'selectBox1ArrayName'V'SelectBox1 Value1' = new Array('SelectBox2 value1', 'SelectBox2 value2', etc, 0);
* var 'selectBox1ArrayName'O'SelectBox1 Value1' = new Array('SelectBox2 option1', 'SelectBox2 option2', etc, 0);
* var 'selectBox1ArrayName'V'SelectBox1 Value2' = new Array('SelectBox2 value1', 'SelectBox2 value2', etc, 0);
* var 'selectBox1ArrayName'O'SelectBox1 Value2' = new Array('SelectBox2 option1', 'SelectBox2 option2', etc, 0);
* @author dgb
*/
utilities.updateSelectBox = function(selectBox1, selectBox2, selectBox1ArrayName, selectSearch )
{
	//var selectBox1Index = eval(selectBox1.selectedIndex);
	var initSelectBox2 = -1;
	var selectBox1Val = selectBox1.value;
	var selectBox2Val = selectBox2.value;
	selectBox2.length = 0;

	if (selectBox1Val != "-1" && selectBox1Val != "" && selectBox1Val != "0")
	{
		var selectBox1OptionArray = eval(selectBox1ArrayName + 'O' + selectBox1Val);
		var selectBox1ValArray = eval(selectBox1ArrayName + 'V' + selectBox1Val);
		selectBox2.length = 0;

		for (var i = 0; i < selectBox1ValArray.length-1; i++)
		{
			selectBox2.length += 1;
			selectBox2.options[selectBox2.length - 1] = new Option( selectBox1OptionArray[i] );
			selectBox2.options[selectBox2.length - 1].value = selectBox1ValArray[i];

			if ( selectBox2Val == selectBox1ValArray[i] )
			{
				initSelectBox2 = selectBox2.length - 1;
			}
		}
	}

	selectBox2.length += 1;
	if (selectSearch) 
	{
		selectBox2.options[selectBox2.length - 1] = new Option(" - Any - ");
		selectBox2.options[selectBox2.length - 1].value = "";
	}
	else
	{
		selectBox2.options[selectBox2.length - 1] = new Option(" - not selected - ");
		selectBox2.options[selectBox2.length - 1].value = "-1";
	}

	if (initSelectBox2 != -1){
		selectBox2.selectedIndex	= initSelectBox2;
	}
	else
	{
		selectBox2.selectedIndex	= selectBox2.options.length - 1;
	}

}	

/**
* Similar to above, but provides for OPTGROUPS in the second select box.
**/
utilities.updateOptSelectBox = function(selectBox1, selectBox2, selectBox1ArrayName )
{
	//var selectBox1Index = eval(selectBox1.selectedIndex);
	var initSelectBox2 = -1;
	var selectBox1Val = selectBox1.value;
	var selectBox2Val = selectBox2.value;
	if(!selectBox2Val) selectBox2Val=selectBox2.getAttribute('selecteddefault');
	selectBox2.length = 0;

	if (selectBox1Val != "-1" && selectBox1Val != "" && selectBox1Val != "0")
	{
		var selectBox1OptionArray = eval(selectBox1ArrayName + 'O' + selectBox1Val);
		var selectBox1ValArray = eval(selectBox1ArrayName + 'V' + selectBox1Val);
		var selectBox1GroupArray = eval(selectBox1ArrayName + 'G' + selectBox1Val);
		while (selectBox2.hasChildNodes()) {
			selectBox2.removeChild(selectBox2.firstChild);
		}

		var group=selectBox1GroupArray[0];
		var optgroup=document.createElement('optgroup');
		var option;
		optgroup.label=group;
		for (var i = 0; i < selectBox1ValArray.length; i++)
		{
			if(group!=selectBox1GroupArray[i])
			{
				selectBox2.appendChild(optgroup);
				group=selectBox1GroupArray[i];
				optgroup=document.createElement('optgroup');
				optgroup.label=group;
			}
			option=new Option( selectBox1OptionArray[i] );
			option.value=selectBox1ValArray[i];
			option.innerHTML=selectBox1OptionArray[i];
			if(option.value==selectBox2Val) option.selected=true;
			optgroup.appendChild(option);
		}
	} else
	{
		while (selectBox2.hasChildNodes()) {
			selectBox2.removeChild(selectBox2.firstChild);
		}
	}
}	

utilities.GetElementLeft=function(eElement)
{
    var nLeftPos = eElement.offsetLeft;          // initialize var to store calculations
    var eParElement = eElement.offsetParent;     // identify first offset parent element  
    while (eParElement != null)
    {                                            // move up through element hierarchy
        nLeftPos += eParElement.offsetLeft;      // appending left offset of each parent
        eParElement = eParElement.offsetParent;  // until no more offset parents exist
    }
    return nLeftPos;                             // return the number calculated
}

utilities.GetElementTop=function(eElement)
{
    var nTopPos = eElement.offsetTop;            // initialize var to store calculations

    var eParElement = eElement.offsetParent;     // identify first offset parent element  
    while (eParElement != null)
    {                                            // move up through element hierarchy
        nTopPos += eParElement.offsetTop;        // appending top offset of each parent
        eParElement = eParElement.offsetParent;  // until no more offset parents exist
    }
    return nTopPos;                              // return the number calculated
}




/** 
* class bug
* Makes a nice little bug that can run around the page :)
*/

/* array of all current bugs */
bug.objects = new Array();

/* 32 different directions to z_move, these are the vector coordinates */
bug.z_moveCoords = new Array(
	[  0, -5], [  1, -5], [  2, -5], [  3, -5], [  4, -4], [  5, -3], [  5, -2], [  5, -1], 
	[  5,  0], [  5,  1], [  5,  2], [  5,  3], [  4,  4], [  3,  5], [  2,  5], [  1,  5],
	[  0,  5], [ -1,  5], [ -2,  5], [ -3,  5], [ -4,  4], [ -5,  3], [ -5,  2], [ -5,  1],
	[ -5,  0], [ -5, -1], [ -5, -2], [ -5, -3], [ -4, -4], [ -3, -5], [ -2, -5], [ -1, -5]
);
bug.numDirections = 32;
var bugcount=0;

/** 
* @return bug
* @param integer width
* @param integer height
* @param string imgUrl
* @desc Constructor
*/
function bug(width, height, imageDir, isKillable)
{
	/* get id and set in global list of bugs */
	this.z_id = bug.objects.length;
	bug.objects[this.z_id] = this;
	
	this.z_width = width;
	this.z_height = height;
	this.z_imageDir = imageDir;
	this.z_isKillable = isKillable;
	
	/* the actual image tag */
	this.z_image;
	
	/* misc attributes */
	this.z_moveDelay = 70;
	this.z_direction = 0; /* in degrees we use every 10 */
	this.z_isActive;
	
	/* timer stuff */
	this.z_intervalId;
	
	/* chance of bug turning either direction */
	this.z_turnLeftChance;
	this.z_turnRightChance;
	this.z_turningBuffer = 0;
	this.z_currentTurn = 0;
	
	this.setTurnChance(15, 15);
	
	this.z_preloadImages();
}

/** 
* @return void
* @desc Generates the bug's HTML
*/
bug.prototype.generate = function()
{
	var self = this;
	
	this.z_image = document.createElement("img");
	this.z_image.style.position = "absolute";
	this.z_image.style.zIndex = 100;
	this.start_x='400px';
	this.start_y='200px';
	this.z_image.style.left = this.start_x;
	this.z_image.style.top = this.start_y;
	
	this.z_image.onclick = function(){self.z_onclick()};
	
	this.z_updateImage();
	this.z_setVisibility(false);
	
	document.body.appendChild(this.z_image);
	
	this.enable();
	
	bugcount++;
}

/** 
* @return void
* @param boolean isVisible
* @desc Sets the bug's visibility to isVisible
*/
bug.prototype.z_setVisibility = function(isVisible)
{
	this.z_image.style.visibility = isVisible ? "visible" : "hidden";
}

/** 
* @return void
* @desc Changes the bug's image so it looks animated
*/
bug.prototype.z_updateImage = function()
{
	this.z_image.src = this.z_imageDir + this.z_direction + ".gif";
}

/** 
* @return void
* @desc onclick event, kills the bug if desired
*/
bug.prototype.z_onclick = function()
{
	if (this.z_isKillable)
	{
		this.disable();
		this.z_image.src = this.z_imageDir + "splat" + this.z_direction + ".gif";
		this.z_isKillable=false;
	}
}

/**
* @return void
* @desc Displays the bug and starts it moving
*/
bug.prototype.enable = function()
{
	this.z_setVisibility(true);
	this.z_intervalId = setInterval("bug.objects[" + this.z_id + "].z_move()", this.z_moveDelay);
}

/** 
* @return void
* @desc Stops the bug from moving
*/
bug.prototype.disable = function()
{
	clearInterval(this.z_intervalId);
	bugcount--;
}

/** 
* @return void
* @param float left
* @param float right
* @desc Sets the change of the bug turning left or right, in the range 0 - 100 for each
* If it turns both or neither directions, it will go stright
*/
bug.prototype.setTurnChance = function(leftChance, rightChance)
{
	/* chance of bug turning either direction */
	this.z_turnLeftChance = leftChance;
	this.z_turnRightChance = rightChance;
}

/** 
* @return void
* @desc Moves the bug
*/
bug.prototype.z_move = function()
{
	var newDirection = 0;
			
	/* 
	we use a turning buffer, so bug doesn't look like it has a tick :D (turns smoothly)
	don't do anything while this is still counting down
	*/
	this.z_turningBuffer--;
	
	if (this.z_turningBuffer > 0)
	{
		newDirection = this.z_currentTurn;
	}
	/* else we are free to turn */
	else
	{
		/* should we turn left? */
		if (Math.random() * 100 < this.z_turnLeftChance)
		{
			newDirection--;
		}
		
		/* should we turn right? */
		if (Math.random() * 100 < this.z_turnRightChance)
		{
			newDirection++;
		}
	}
	
	/* only do extra processing if we have actually changes direction */
	if (newDirection != 0)
	{
		/* if turning buffer has expired, restart it */
		if (this.z_turningBuffer < 0)
		{
			/* change this to make turns longer */
			this.z_turningBuffer = 3;
			
			this.z_currentTurn = newDirection;
		}
		
		this.z_direction += newDirection;
		
		/* wrap direction if necessary */
		if (this.z_direction >= bug.numDirections)
		{
			/* we are future proofing for crazy bugs that turn more then 1 pos at a time */
			this.z_direction = -(bug.numDirections - this.z_direction);
		}
		else if (this.z_direction < 0)
		{
			this.z_direction = (bug.numDirections + this.z_direction);
		}
	}
	
	this.z_updateImage();
	
	/* move in the direction we are facing */
	this.z_image.style.left = (parseInt(this.z_image.style.left) + bug.z_moveCoords[this.z_direction][0])+'px';
	this.z_image.style.top = (parseInt(this.z_image.style.top) + bug.z_moveCoords[this.z_direction][1])+'px';
	
	//Where are we going?
	var main_dir=Math.atan2(parseInt(this.z_image.style.left)-this.start_x,parseInt(this.z_image.style.top)-this.start_y);
	var point_dir=Math.atan2(bug.z_moveCoords[this.z_direction][0],bug.z_moveCoords[this.z_direction][1]);
	var dist=Math.sqrt(Math.pow(parseInt(this.z_image.style.left)-this.start_x,2)+Math.pow(parseInt(this.z_image.style.top)-this.start_y,2));
	//Are we going clockwise or anticlockwise?
	var clockwise=false;
	if(main_dir != point_dir)
	{
		if(main_dir>=0 && point_dir>=0 || main_dir<0 && point_dir<0 )
		{
			//Straight compare of radians. Atan2 returns positive anticlockwise
			if(main_dir>point_dir) clockwise=true; 
		} else if(main_dir-point_dir<Math.PI && main_dir-point_dir>0 ||
				  main_dir+Math.PI*2-point_dir<Math.PI && main_dir+Math.PI*2-point_dir>0)
		{
			clockwise=true;
		}
		if(clockwise)
		{
			//Raise the chance of turning further clockwise (i.e. right) depending on how far we are.
			this.setTurnChance(15, parseInt(15+dist/7));
		} else
		{
			this.setTurnChance(parseInt(15+dist/7), 15);
		}
	}
	if (Math.random() * (10000*bugcount) < 7)
	{
		//Spawn a new bug. Hehehe...
		//newbug = new bug(44, 44, this.z_imageDir, true);
		//newbug.generate()
	}
}

/** 
* @return void
* @desc Preloads the images used
*/
bug.prototype.z_preloadImages = function()
{
	var images = new Array();
	for (var i = 0; i < bug.numDirections; i++) {
		images[i] = new Image();
		images[i].src = this.z_imageDir + i + ".gif";
	}
	
	images[images.length] = new Image();
	images[images.length - 1].src = this.z_imageDir + "splat.gif";
}

/**
 * Colour picker control
 */
function getColour(control_name)
{
	//alert(control_name);
	//alert(utilities.getElement(control_name).tagName);
	//alert(utilities.getElement(control_name).value);
	//alert(control_name+'_box');
	//alert(utilities.getElement(control_name+'_box').tagName);

	// Line 18
	on_close = function(colour)
	{
		//alert('closing');
		try {
			if (colour)
			{
				colour = '#' + colour;
			}
			
			updateColour(colour, control_name);
		}
		catch(e){
			alert('Error setting colour');
			//alert(e.name+e.message);
		}
	};

	Dialog2(
		'index.php?page=popups&f=select_color.php',
		null, // width
		null, // height
		utilities.getElement(control_name).value, // init
			on_close //action
		);
}

function updateColour(new_colour, control_name)
{
    utilities.getElement(control_name+'_box').bgColor = utilities.getElement(control_name).value = new_colour; 
}


/**
* Clock
*/

var clock_is_hidden = new Array();

//shows \ hides the clock
function showClock(clock_num){

	//check if clock is hidden
	if (clock_is_hidden[clock_num]){
		clock_is_hidden[clock_num] = false;
		
		//update the clock display
		updateClock(clock_num);
		
		//show clock
		getElem("clock_shell["+clock_num+"]").style.visibility="visible";
	}
	//else hide clock
	else{
		getElem("clock_shell["+clock_num+"]").style.visibility="hidden";
		clock_is_hidden[clock_num] = true;
	}
}

//updates the clocks display to match the current time on the form
function updateClock(clock_num){
	//only update if clock is showing, just in case javascript doesn't work
	if (!clock_is_hidden[clock_num]){
	
		//get hour and minute from input fields
		hour = getElem("hour["+clock_num+"]").value/1;
		minute = getElem("minute["+clock_num+"]").value/5;
		time_type = getElem("time_type["+clock_num+"]").value;
		
		//change the time on the clock
		changeHour(clock_num, hour);
		changeMinute(clock_num, minute);
		changeTimeType(clock_num, time_type);
	}
}

//used to keep track of currently selected hour
var curr_hour = false;

//changes the given hour to be the selected hour
function changeHour(clock_num, hour){
	//convert hour so clock will work
	if (hour == 12)
		hour = 0;

	//move hours image to the desired position
	getElem("hour_hands"+clock_num).style.left = - (hour * 99);
	
	//check if we need to change old hour's dot to be unselected
	if (curr_hour)
		getElem("hour"+curr_hour).src = hour_dot;
		
	//change hour's dot to be selected
	getElem("hour"+hour).src = hour_dot_selected;
	
	//set current hour as new curr_hour
	curr_hour = hour;
		
	//adjust so that all values have 2 digits
	if (hour == 0){
		hour = "12";
	}
	else if (hour < 10)
		hour = "0"+hour;
		
	//set input hour to select hour
	getElem("hour["+clock_num+"]").value = hour;
}

//used to keep track of currently selected minute
var curr_minute;

//changes the given minute to be the selected minute
function changeMinute(clock_num, minute){
	getElem("minute_hands"+clock_num).style.left = - (minute * 99);

	//check if we need to change old minute's dot to be unselected
	if (curr_minute || curr_minute == 0)
		getElem("minute"+curr_minute).src = minute_dot;
		
	//change minute's dot to be selected
	getElem("minute"+minute).src = minute_dot_selected;
	
	//set current hour as new curr_hour
	curr_minute = minute;
	
	//adjust so that all values have 2 digits
	minute = minute * 5;
	if (minute < 10)
		minute = "0"+minute;
		
	getElem("minute["+clock_num+"]").value = minute;
}

function changeTimeType(clock_num, time_type){
	if (time_type == "AM"){
		getElem("AM["+clock_num+"]").className = "time_type_over";
		getElem("PM["+clock_num+"]").className = "time_type";
	}
	else{
		getElem("AM["+clock_num+"]").className = "time_type";
		getElem("PM["+clock_num+"]").className = "time_type_over";
	}

	getElem("time_type["+clock_num+"]").value = time_type;
}


/**
 * WYSIWYG
 */

/**
 * A class to parse color values.
 * This is a lighter version of a bigger RGBColor class found on the following link
 * @link   http://www.phpied.com/rgb-color-parser-in-javascript/
 * @license Use it if you like it
 * @author Stoyan Stefanov <sstoo@gmail.com>
 */
function RGBColorLite(color_string)
{
    this.ok = false;

    // strip any leading #
    if (color_string.charAt(0) == '#') { // remove # if any
        color_string = color_string.substr(1,6);
    }

    color_string = color_string.replace(/ /g,'');
    color_string = color_string.toLowerCase();


    // array of color definition objects
    var color_defs = [
        {
            re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,
            example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'],
            process: function (bits){
                return [
                    parseInt(bits[1]),
                    parseInt(bits[2]),
                    parseInt(bits[3])
                ];
            }
        },
        {
            re: /^(\w{2})(\w{2})(\w{2})$/,
            example: ['#00ff00', '336699'],
            process: function (bits){
                return [
                    parseInt(bits[1], 16),
                    parseInt(bits[2], 16),
                    parseInt(bits[3], 16)
                ];
            }
        },
        {
            re: /^(\w{1})(\w{1})(\w{1})$/,
            example: ['#fb0', 'f0f'],
            process: function (bits){
                return [
                    parseInt(bits[1] + bits[1], 16),
                    parseInt(bits[2] + bits[2], 16),
                    parseInt(bits[3] + bits[3], 16)
                ];
            }
        }
    ];

    // search through the definitions to find a match
    for (var i = 0; i < color_defs.length; i++) {
        var re = color_defs[i].re;
        var processor = color_defs[i].process;
        var bits = re.exec(color_string);
        if (bits) {
            channels = processor(bits);
            this.r = channels[0];
            this.g = channels[1];
            this.b = channels[2];
            this.ok = true;
        }

    }

    // validate/cleanup values
    this.r = (this.r < 0 || isNaN(this.r)) ? 0 : ((this.r > 255) ? 255 : this.r);
    this.g = (this.g < 0 || isNaN(this.g)) ? 0 : ((this.g > 255) ? 255 : this.g);
    this.b = (this.b < 0 || isNaN(this.b)) ? 0 : ((this.b > 255) ? 255 : this.b);

    // some getters
    this.toRGB = function () {
        return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')';
    }
    this.toHex = function () {
        var r = this.r.toString(16);
        var g = this.g.toString(16);
        var b = this.b.toString(16);
        if (r.length == 1) r = '0' + r;
        if (g.length == 1) g = '0' + g;
        if (b.length == 1) b = '0' + b;
        return '#' + r + g + b;
    }
}

utilities.in_array =function(needle, haystack, argStrict) {
    // http://kevin.vanzonneveld.net
    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   improved by: vlado houba
    // +   input by: Billy
    // +   bugfixed by: Brett Zamir (http://brett-zamir.me)
    // *     example 1: in_array('van', ['Kevin', 'van', 'Zonneveld']);
    // *     returns 1: true
    // *     example 2: in_array('vlado', {0: 'Kevin', vlado: 'van', 1: 'Zonneveld'});
    // *     returns 2: false
    // *     example 3: in_array(1, ['1', '2', '3']);
    // *     returns 3: true
    // *     example 3: in_array(1, ['1', '2', '3'], false);
    // *     returns 3: true
    // *     example 4: in_array(1, ['1', '2', '3'], true);
    // *     returns 4: false

    var key = '', strict = !!argStrict;

    if (strict) {
        for (key in haystack) {
            if (haystack[key] === needle) {
                return true;
            }
        }
    } else {
        for (key in haystack) {
            if (haystack[key] == needle) {
                return true;
            }
        }
    }

    return false;
}

utilities.urlencode=function(str) {
   return encodeURIComponent(str).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').
                                  replace(/\)/g, '%29').replace(/\*/g, '%2A');
}
