function taskSwapOrderValues(id, direction)
{
	if( direction == 'down' )
	{
		var upID = Number(id) + 1;
		var upOrder = document.getElementById(upID).value;
		var oldOrder = document.getElementById(id).value;
		document.getElementById(id).value = upOrder;
		document.getElementById(upID).value = oldOrder;
	} else {
		var downID = Number(id) - 1;
		var downOrder = document.getElementById(downID).value;
		var oldOrder = document.getElementById(id).value;
		document.getElementById(id).value = downOrder;
		document.getElementById(downID).value = oldOrder;
	}
}

var helpTimeoutid;

function showHelpInformation(key)
{
  helpTimeoutId = setTimeout('doShowHelpInformation(\''+key+'\')', 500);
}

function doShowHelpInformation(key)
{
	ajaxLoadingScreen('Loading');
	x_phpFunc('getHelpInformation', key, handleShowHelpInformation);
}

function handleShowHelpInformation(response)
{
	hideAjaxLoadingScreen();
	document.getElementById('help_information_holder').innerHTML = response;
	document.getElementById('help_information_holder').style.visibility = 'visible';
	document.getElementById('help_information_holder').style.display = 'block';
}

function hideHelpInformation()
{
  clearInterval(helpTimeoutId);

	document.getElementById('help_information_holder').innerHTML = '';
	document.getElementById('help_information_holder').style.visibility = 'hidden';
	document.getElementById('help_information_holder').style.display = 'none';
}

function getWindowID()
{
	var id;

	if( window.opener )
	{
		id = window.opener.location.href;

		if( id )
		{
			return hex_md5(id);
		} else {
			return false;
		}
	}
}

function rememberHideHeader()
{
	applyRememberHideHeader();

	if( location.href.match('hide_header') || location.href.match('quick=1') )
	{
		if( id = getWindowID() )
		{
			setCookie(id, 1);
		}
	}
}

function applyRememberHideHeader()
{
	var id = getWindowID();
	
	var cookie = getCookie(id);
	
	if( cookie == 1 )
	{
		hideMenu();
		showQuickMenu();
	}
}

function showQuickMenu()
{
	if( document.getElementById('the_quick_menu_id') )
	{
		document.getElementById('the_quick_menu_id').style.visibility = 'visible';
		document.getElementById('the_quick_menu_id').style.display = '';
	}
}

function hideMenu()
{
	if( document.getElementById('the_menu_id') )
	{
		document.getElementById('the_menu_id').style.visibility = 'hidden';
		document.getElementById('the_menu_id').style.display = 'none';
	}
}

function showPage()
{
	if( document.getElementById('main_wrapper') )
	{
		document.getElementById('main_wrapper').style.visibility = 'visible';
	}
}

function addBlankTaskToProject(name, project_id)
{
	x_phpFunc('addBlankTaskToProject', name, project_id, handleAddBlankTaskToProjectResult);
}

function handleAddBlankTaskToProjectResult(result)
{
	location.reload();
}

var signupForm;
function applySignupCoupon(form)
{
	signupForm = form;

	x_phpFunc('getCouponDetails', form.coupon_code.value, doApplySignupCoupon);
}

function doApplySignupCoupon(result)
{
	if( result == false )
	{
		document.getElementById('coupon_msg').innerHTML = '<font color="red"><strong>Coupon invalid!</strong></font>';

		handleSignupForm(signupForm);
	} else {
		// signup_cost, monthly_cost, per_user_monthly_cost
		var costs = result.split(':');

		signupForm.signup_cost.value = costs[0];
		signupForm.monthly_cost.value = costs[1];
		signupForm.per_user_monthly_cost.value = costs[2];
		signupForm.account_cost.value = Number(Number(costs[0]) + Number(costs[1]) + Number(costs[2])).toFixed(2);

		document.getElementById('coupon_msg').innerHTML = '<font color="green"><strong>Coupon applied!</strong></font>';
	}

	if( signupForm.account_cost.value > 0 )
	{
		toggleCreditCardInformationDisabled(signupForm, false);
	} else {
		toggleCreditCardInformationDisabled(signupForm, true);
	}
}

function toggleCreditCardInformationDisabled(form, bool)
{
	form.cc1.disabled = bool;
	form.cc2.disabled = bool;
	form.cc3.disabled = bool;
	form.cc4.disabled = bool;
	form.expiration_date_month.disabled = bool;
	form.expiration_date_year.disabled = bool;

	form.first_name.disabled = bool;
	form.last_name.disabled = bool;
	form.address.disabled = bool;
	form.city.disabled = bool;
	form.state.disabled = bool;
	form.zipcode.disabled = bool;
}

function selectExportType(button)
{
	var form = button.form;

	form.action_to_perform.value = button.name;

	form.submit();

	return false;
}

function printURL(url)
{
	url = urlAppend(url,'hide_header=1');
	url = urlAppend(url,'hide_search_forms=1&print=1');
	
	var theWindow = window.open(url);
	
	theWindow.print();
}

function saveReport(name, searchForm)
{
	var url = buildGetURL(searchForm);

	if( searchForm.report_name.value == '' )
	{
		alert('You must enter a report name in order to save it!');
		return false;
	} else {
		name = searchForm.report_name.value;
	}

	ajaxLoadingScreen('Loading...');
	x_phpFunc('saveReport', name, url, reloadReport);
}

function deleteReport(report_id)
{
	ajaxLoadingScreen('Loading...');
	x_phpFunc('deleteReport', report_id, reloadReport);
}

function loadReport(report_id)
{
	ajaxLoadingScreen('Loading...');
	x_phpFunc('getReportURL', report_id, reloadReport);
}

function reloadReport(url)
{
	hideAjaxLoadingScreen();
	location.href = url;
}

function setFormCurrentTab(formID, value)
{
	x_phpFunc('setFormCurrentTab',formID,value,nothing);
}

function setListOrders(listName, orders)
{
	x_phpFunc('setListOrders',listName,orders,nothing);
}

function checkWithName(names)
{
	var names = names.split(',');
	
	for(i = 0; i < document.forms.length; i++)
	{
		var form = document.forms[i];

		for(j = 0; j < form.elements.length; j++)
		{
			var element = form.elements[j];
			
			if( element.type == 'checkbox' )
			{
				element.checked = false;
			
				for(k = 0; k < names.length; k++)
				{
					var name = 'Permission[' + names[k] + ']';
					
					if( name == element.name )
					{
						element.checked = true;
					}
				}
			}
		}
	}
}

var id;

function changeFormTab(tab, tabs, formID)
{
	var tabs = tabs.split(',');

	for(i = 0; i < tabs.length; i++)
	{
		id = 'tabbed_form_content_' + tabs[i];

		document.getElementById(id).style.visibility = 'hidden';
		document.getElementById(id).style.display = 'none';

		document.getElementById('tabbed_form_tab_' + tabs[i]).className = 'tabbed_form_tab';
	}

	id = 'tabbed_form_content_' + tab;
	
	document.getElementById(id).style.visibility = 'visible';
	document.getElementById(id).style.display = 'block';
	document.getElementById('tabbed_form_tab_' + tab).className = 'tabbed_form_tab_selected';
	document.getElementById('current_tab_' + formID).value = tab;

	setFormCurrentTab(document.getElementById('tabbed_form_id_' + formID).value, tab);
}

function changeTotalTrackedTimeForThe(thisis)
{
	if(thisis.value == 'day')
	{
		thisis.form.track_weekends.disabled = false;
	} else {
		thisis.form.track_weekends.disabled = true;
		thisis.form.track_weekends.checked = false;
	}
}

function mouseOverMenuItem(refName)
{
	document.getElementById('arrow_' + refName).style.visibility = 'visible';
	document.getElementById('arrow_' + refName).style.position = 'relative';
	document.getElementById('label_' + refName).style.fontWeight = 'bold';
	document.getElementById('row_' + refName).className = 'menu_row_hover';
}

function mouseOutMenuItem(refName)
{
	document.getElementById('arrow_' + refName).style.visibility = 'hidden';
	document.getElementById('arrow_' + refName).style.position = 'absolute';
	document.getElementById('label_' + refName).style.fontWeight = 'normal';
	document.getElementById('row_' + refName).className = 'menu_row_normal';
}

function loadTimeEntryHoverInfo(time_entry_id)
{
	id = time_entry_id;

	if( document.getElementById('time_entry_hover_box_'+id).innerHTML.match('Loading...') )
	{
		ajaxLoadingScreen('Loading...');
		
    	x_phpFunc('timeEntryHoverBoxInfo', time_entry_id, showTimeEntryHoverBoxInfo);
	}
}

function showTimeEntryHoverBoxInfo(html)
{
	document.getElementById('time_entry_hover_box_' + id).innerHTML = html;
	
  	hideAjaxLoadingScreen();
}

function checkReviewTimeEntryCheckbox(form,time_entry_id)
{
	for(i = 0; i < form.elements.length; i++)
	{
		if(form.elements[i].id == "checked_time_entry" && form.elements[i].value == time_entry_id)
		{
			form.elements[i].disabled = false;
			form.elements[i].checked = true;
			//ajaxReviewTimeEntry(time_entry_id);
			break;
		}
	}
}

function checkReviewTimeSheetCheckbox(form,time_sheet_id)
{
	for(i = 0; i < form.elements.length; i++)
	{
		if(form.elements[i].id == "checked_time_sheet" && form.elements[i].value == time_sheet_id)
		{
			form.elements[i].disabled = false;
			form.elements[i].checked = true;
			//ajaxReviewTimeSheet(time_sheet_id);
			break;
		}
	}
}

function ajaxReviewTimeEntry(time_entry_id)
{
	x_phpFunc('reviewTimeEntry', time_entry_id, removeRow);
}

function ajaxReviewTimeSheet(time_sheet_id)
{
	x_phpFunc('reviewTimeSheet', time_sheet_id, removeRow);
}

function removeRow(id)
{
	//document.getElementById('row_id_'+id).style.display = 'none';
}

function checkUsernameAvailability(name)
{
	x_phpFunc('checkUsernameAvailability', name, checkUsernameAvailabilityNotify);
}

function checkUsernameAvailabilityNotify(response)
{
	document.getElementById('username_available_error').innerHTML = response;
}

function showInternalComments(bool)
{
	if( bool == false )
	{
		document.getElementById('internal_comments_holder').style.visibility = 'hidden';
		document.time_entry.internal_comment.disabled = true;
	} else {
		document.getElementById('internal_comments_holder').style.visibility = 'visible';
		document.time_entry.internal_comment.disabled = false;
	}
}

function autoHidePageResponseBox()
{
	setTimeout(doAutoHidePageResponseBox, 4000);
}

function doAutoHidePageResponseBox()
{
	if( document.getElementById('page_response_box_msgs') )
	{
		document.getElementById('page_response_box_msgs').style.visibility = 'hidden';
		document.getElementById('page_response_box_msgs').style.display = 'none';
	}

	if( document.getElementById('page_response_box_errors') )
	{
		document.getElementById('page_response_box_errors').style.visibility = 'hidden';
		document.getElementById('page_response_box_errors').style.display = 'none';
	}
}

function rememberPosition(id, left, top, width, height)
{
	x_phpFunc('rememberPosition', id, left, top, width, height, nothing);
}

function setSetupBillingProjectRateType(thisis, project_id)
{
	var prjStr = 'project_' + project_id;

	if(thisis.value == 'custom')
	{
		document.getElementById(prjStr + '_inherit_rate_from').disabled = true;
		document.getElementById(prjStr + '_hourly_rate').disabled = false;
		document.getElementById(prjStr + '_inherit_rate_from').selectedIndex = 0;
	}
	else if(thisis.value == 'inherited')
	{
		document.getElementById(prjStr + '_inherit_rate_from').disabled = false;
		document.getElementById(prjStr + '_hourly_rate').disabled = true;
		document.getElementById(prjStr + '_hourly_rate').value = '';
	}
}

function setRateType(thisis)
{
	if(thisis.value == 'custom')
	{
		thisis.form.inherit_rate_from.disabled = true;
		thisis.form.hourly_rate.disabled = false;
		thisis.form.inherit_rate_from.selectedIndex = 0;
	}
	else if(thisis.value == 'inherited')
	{
		thisis.form.inherit_rate_from.disabled = false;
		thisis.form.hourly_rate.disabled = true;
		thisis.form.hourly_rate.value = '';
	}
}

function xmlHttpObject()
{
	var xmlhttp = false;
	/*@cc_on @*/
	/*@if (@_jscript_version >= 5)
	// JScript gives us Conditional compilation, we can cope with old IE versions.
	// and security blocked creation of the objects.
	 try {
		xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
	 } catch (e) {
		try {
		 xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
		} catch (E) {
		 xmlhttp = false;
		}
	 }
	@end @*/
	if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
		try {
			xmlhttp = new XMLHttpRequest();
		} catch (e) {
			xmlhttp=false;
		}
	}
	if (!xmlhttp && window.createRequest) {
		try {
			xmlhttp = window.createRequest();
		} catch (e) {
			xmlhttp=false;
		}
	}

	return xmlhttp;
}

function confirmAction(txt)
{
	var agree=confirm(txt);
	if (agree)
	{
		return true;
	} else {
		return false;
	}
}

function setCookie(name,value)
{
	var today = new Date();
	var expire = new Date();
	var days = 9999;

	expire.setTime(today.getTime() + 3600000*24*days);
	document.cookie = name+"="+escape(value)+";expires="+expire.toGMTString();
}

function getCookie(name)
{
	var doc = document.cookie;

	var index = doc.indexOf(name+'=');
	if(index == -1)
		return null;

	index = doc.indexOf('=',index) + 1;
	var endstr = doc.indexOf(';',index);

	if(endstr == -1)
		endstr = doc.length;

	return unescape(doc.substring(index,endstr));
}

function ecDiv(elementid,force,theDefault)
{
	var block = document.getElementById(elementid);
	var image = document.getElementById('ecicon_'+ elementid);

	if(block && image)
	{
		if((block.style.display == '' || force == 'collapse') && force != 'expand')
		{
			display = 'none';
			newsrc = image.src.replace('collapse.gif','expand.gif');
			//setCookie('ec','collapsed');
			setECState(elementid,'collapsed',theDefault);
		}

		if((block.style.display == 'none' || force == 'expand') && force != 'collapse')
		{
			display = '';
			newsrc = image.src.replace('expand.gif','collapse.gif');
			//setCookie('ec','expanded');
			setECState(elementid, 'expanded',theDefault);
		}

		block.style.display = display;

		image.src = newsrc;
	}
}

function setECState(elementid, state,theDefault)
{
	var cookieString = getCookie('ec');

	if(theDefault == 'expanded')
	{
		if( state == 'collapsed' )
		{
			cookieString = appendECState(elementid,cookieString);
		} else {
			cookieString= removeECState(elementid,cookieString);
		}
	} else {
		if( state == 'expanded' )
		{
			cookieString = appendECState(elementid,cookieString);
		} else {
			cookieString= removeECState(elementid,cookieString);
		}
	}

	setCookie('ec',cookieString);
}

function appendECState(elementid,cookieString)
{
	if( cookieString && !cookieString.match(elementid) )
	{
		cookieString = cookieString+elementid;
	} else {
		cookieString = elementid;
	}

	return cookieString;
}

function removeECState(elementid,cookieString)
{
	if( cookieString && cookieString.match(elementid) )
	{
		cookieString = cookieString.replace(elementid,'');
	}

	return cookieString;
}

function ecIcon(elementid)
{
	//alert(elementid);
	var image = document.getElementById('ecicon_'+ elementid);
	var cookie = getCookie('ec');

	if(cookie)
	{
		if( cookie.match(elementid) )
		{
			state = "collapsed";
		} else {
			state = "expanded";
		}
	} else {
		state = "expanded";
	}
	//alert(state);
	pos = image.src.lastIndexOf("/");
	basesrc = image.src.substr(0,pos);

	//alert(basesrc);
	//alert(pos);
	if(state=='collapsed')
	{
		//alert('collapsed icon');
		newsrc = basesrc+'/expand.gif';
	} else {
		//alert('expanded icon');
		newsrc = basesrc+'/collapse.gif';
	}

	//alert(newsrc);
	image.src = newsrc;
}



// ===================================================================
// Author: Matt Kruse <matt@mattkruse.com>
// WWW: http://www.mattkruse.com/
//
// NOTICE: You may use this code for any purpose, commercial or
// private, without any further permission from the author. You may
// remove this notice from your final code if you wish, however it is
// appreciated by the author if at least my web site address is kept.
//
// You may *NOT* re-distribute this code in any way except through its
// use. That means, you can include it in your product, or your web
// site, or any other form where the code is actually being used. You
// may not put the plain javascript up on your site for download or
// include it in your javascript libraries for download.
// If you wish to share this code with others, please just point them
// to the URL instead.
// Please DO NOT link directly to my .js files from your site. Copy
// the files to your server and use them there. Thank you.
// ===================================================================

// HISTORY
// ------------------------------------------------------------------
// April 20, 2005: Fixed the removeSelectedOptions() function to
//                 correctly handle single selects
// June 12, 2003: Modified up and down functions to support more than
//                one selected option
/*
DESCRIPTION: These are general functions to deal with and manipulate
select boxes. Also see the OptionTransfer library to more easily
handle transferring options between two lists

COMPATABILITY: These are fairly basic functions - they should work on
all browsers that support Javascript.
*/


// -------------------------------------------------------------------
// hasOptions(obj)
//  Utility function to determine if a select object has an options array
// -------------------------------------------------------------------
function hasOptions(obj) {
	if (obj!=null && obj.options!=null) { return true; }
	return false;
	}

// -------------------------------------------------------------------
// selectUnselectMatchingOptions(select_object,regex,select/unselect,true/false)
//  This is a general function used by the select functions below, to
//  avoid code duplication
// -------------------------------------------------------------------
function selectUnselectMatchingOptions(obj,regex,which,only) {
	if (window.RegExp) {
		if (which == "select") {
			var selected1=true;
			var selected2=false;
			}
		else if (which == "unselect") {
			var selected1=false;
			var selected2=true;
			}
		else {
			return;
			}
		var re = new RegExp(regex);
		if (!hasOptions(obj)) { return; }
		for (var i=0; i<obj.options.length; i++) {
			if (re.test(obj.options[i].text)) {
				obj.options[i].selected = selected1;
				}
			else {
				if (only == true) {
					obj.options[i].selected = selected2;
					}
				}
			}
		}
	}

// -------------------------------------------------------------------
// selectMatchingOptions(select_object,regex)
//  This function selects all options that match the regular expression
//  passed in. Currently-selected options will not be changed.
// -------------------------------------------------------------------
function selectMatchingOptions(obj,regex) {
	selectUnselectMatchingOptions(obj,regex,"select",false);
	}
// -------------------------------------------------------------------
// selectOnlyMatchingOptions(select_object,regex)
//  This function selects all options that match the regular expression
//  passed in. Selected options that don't match will be un-selected.
// -------------------------------------------------------------------
function selectOnlyMatchingOptions(obj,regex) {
	selectUnselectMatchingOptions(obj,regex,"select",true);
	}
// -------------------------------------------------------------------
// unSelectMatchingOptions(select_object,regex)
//  This function Unselects all options that match the regular expression
//  passed in.
// -------------------------------------------------------------------
function unSelectMatchingOptions(obj,regex) {
	selectUnselectMatchingOptions(obj,regex,"unselect",false);
	}

// -------------------------------------------------------------------
// sortSelect(select_object)
//   Pass this function a SELECT object and the options will be sorted
//   by their text (display) values
// -------------------------------------------------------------------
function sortSelect(obj) {
	var o = new Array();
	if (!hasOptions(obj)) { return; }
	for (var i=0; i<obj.options.length; i++) {
		o[o.length] = new Option( obj.options[i].text, obj.options[i].value, obj.options[i].defaultSelected, obj.options[i].selected) ;
		}
	if (o.length==0) { return; }
	o = o.sort(
		function(a,b) {
			if ((a.text+"") < (b.text+"")) { return -1; }
			if ((a.text+"") > (b.text+"")) { return 1; }
			return 0;
			}
		);

	for (var i=0; i<o.length; i++) {
		obj.options[i] = new Option(o[i].text, o[i].value, o[i].defaultSelected, o[i].selected);
		}
	}

// -------------------------------------------------------------------
// selectAllOptions(select_object)
//  This function takes a select box and selects all options (in a
//  multiple select object). This is used when passing values between
//  two select boxes. Select all options in the right box before
//  submitting the form so the values will be sent to the server.
// -------------------------------------------------------------------
function selectAllOptions(obj) {
	if (!hasOptions(obj)) { return; }
	for (var i=0; i<obj.options.length; i++) {
		obj.options[i].selected = true;
		}
	}

// -------------------------------------------------------------------
// moveSelectedOptions(select_object,select_object[,autosort(true/false)[,regex]])
//  This function moves options between select boxes. Works best with
//  multi-select boxes to create the common Windows control effect.
//  Passes all selected values from the first object to the second
//  object and re-sorts each box.
//  If a third argument of 'false' is passed, then the lists are not
//  sorted after the move.
//  If a fourth string argument is passed, this will function as a
//  Regular Expression to match against the TEXT or the options. If
//  the text of an option matches the pattern, it will NOT be moved.
//  It will be treated as an unmoveable option.
//  You can also put this into the <SELECT> object as follows:
//    onDblClick="moveSelectedOptions(this,this.form.target)
//  This way, when the user double-clicks on a value in one box, it
//  will be transferred to the other (in browsers that support the
//  onDblClick() event handler).
// -------------------------------------------------------------------
function moveSelectedOptions(from,to) {
	// Unselect matching options, if required
	if (arguments.length>3) {
		var regex = arguments[3];
		if (regex != "") {
			unSelectMatchingOptions(from,regex);
			}
		}
	// Move them over
	if (!hasOptions(from)) { return; }
	for (var i=0; i<from.options.length; i++) {
		var o = from.options[i];
		if (o.selected) {
			if (!hasOptions(to)) { var index = 0; } else { var index=to.options.length; }
			to.options[index] = new Option( o.text, o.value, false, false);
			}
		}
	// Delete them from original
	for (var i=(from.options.length-1); i>=0; i--) {
		var o = from.options[i];
		if (o.selected) {
			from.options[i] = null;
			}
		}
	if ((arguments.length<3) || (arguments[2]==true)) {
		sortSelect(from);
		sortSelect(to);
		}
	from.selectedIndex = -1;
	to.selectedIndex = -1;
	selectAllOptions(to);
	selectAllOptions(from);
	}

// -------------------------------------------------------------------
// copySelectedOptions(select_object,select_object[,autosort(true/false)])
//  This function copies options between select boxes instead of
//  moving items. Duplicates in the target list are not allowed.
// -------------------------------------------------------------------
function copySelectedOptions(from,to) {
	var options = new Object();
	if (hasOptions(to)) {
		for (var i=0; i<to.options.length; i++) {
			options[to.options[i].value] = to.options[i].text;
			}
		}
	if (!hasOptions(from)) { return; }
	for (var i=0; i<from.options.length; i++) {
		var o = from.options[i];
		if (o.selected) {
			if (options[o.value] == null || options[o.value] == "undefined" || options[o.value]!=o.text) {
				if (!hasOptions(to)) { var index = 0; } else { var index=to.options.length; }
				to.options[index] = new Option( o.text, o.value, false, false);
				}
			}
		}
	if ((arguments.length<3) || (arguments[2]==true)) {
		sortSelect(to);
		}
	from.selectedIndex = -1;
	to.selectedIndex = -1;
	}

// -------------------------------------------------------------------
// moveAllOptions(select_object,select_object[,autosort(true/false)[,regex]])
//  Move all options from one select box to another.
// -------------------------------------------------------------------
function moveAllOptions(from,to) {
	selectAllOptions(from);
	if (arguments.length==2) {
		moveSelectedOptions(from,to);
		}
	else if (arguments.length==3) {
		moveSelectedOptions(from,to,arguments[2]);
		}
	else if (arguments.length==4) {
		moveSelectedOptions(from,to,arguments[2],arguments[3]);
		}
	}

// -------------------------------------------------------------------
// copyAllOptions(select_object,select_object[,autosort(true/false)])
//  Copy all options from one select box to another, instead of
//  removing items. Duplicates in the target list are not allowed.
// -------------------------------------------------------------------
function copyAllOptions(from,to) {
	selectAllOptions(from);
	if (arguments.length==2) {
		copySelectedOptions(from,to);
		}
	else if (arguments.length==3) {
		copySelectedOptions(from,to,arguments[2]);
		}
	}

// -------------------------------------------------------------------
// swapOptions(select_object,option1,option2)
//  Swap positions of two options in a select list
// -------------------------------------------------------------------
function swapOptions(obj,i,j) {
	var o = obj.options;
	var i_selected = o[i].selected;
	var j_selected = o[j].selected;
	var temp = new Option(o[i].text, o[i].value, o[i].defaultSelected, o[i].selected);
	var temp2= new Option(o[j].text, o[j].value, o[j].defaultSelected, o[j].selected);
	o[i] = temp2;
	o[j] = temp;
	o[i].selected = j_selected;
	o[j].selected = i_selected;
	}

// -------------------------------------------------------------------
// moveOptionUp(select_object)
//  Move selected option in a select list up one
// -------------------------------------------------------------------
function moveOptionUp(obj) {
	if (!hasOptions(obj)) { return; }
	for (i=0; i<obj.options.length; i++) {
		if (obj.options[i].selected) {
			if (i != 0 && !obj.options[i-1].selected) {
				swapOptions(obj,i,i-1);
				obj.options[i-1].selected = true;
				}
			}
		}
	}

// -------------------------------------------------------------------
// moveOptionDown(select_object)
//  Move selected option in a select list down one
// -------------------------------------------------------------------
function moveOptionDown(obj) {
	if (!hasOptions(obj)) { return; }
	for (i=obj.options.length-1; i>=0; i--) {
		if (obj.options[i].selected) {
			if (i != (obj.options.length-1) && ! obj.options[i+1].selected) {
				swapOptions(obj,i,i+1);
				obj.options[i+1].selected = true;
				}
			}
		}
	}

// -------------------------------------------------------------------
// removeSelectedOptions(select_object)
//  Remove all selected options from a list
//  (Thanks to Gene Ninestein)
// -------------------------------------------------------------------
function removeSelectedOptions(from) {
	if (!hasOptions(from)) { return; }
	if (from.type=="select-one") {
		from.options[from.selectedIndex] = null;
		}
	else {
		for (var i=(from.options.length-1); i>=0; i--) {
			var o=from.options[i];
			if (o.selected) {
				from.options[i] = null;
				}
			}
		}
	from.selectedIndex = -1;
	}

// -------------------------------------------------------------------
// removeAllOptions(select_object)
//  Remove all options from a list
// -------------------------------------------------------------------
function removeAllOptions(from) {
	if (!hasOptions(from)) { return; }
	for (var i=(from.options.length-1); i>=0; i--) {
		from.options[i] = null;
		}
	from.selectedIndex = -1;
	}

// -------------------------------------------------------------------
// addOption(select_object,display_text,value,selected)
//  Add an option to a list
// -------------------------------------------------------------------
function addOption(obj,text,value,selected) {
	if (obj!=null && obj.options!=null) {
		obj.options[obj.options.length] = new Option(text, value, false, selected);
		}
	}

function autoTab( input,len )
{
	var e = 'event';
	var isNN = ( navigator.appName.indexOf( "Netscape" ) != -1 );
	var keyCode	= ( isNN ) ? e.which : e.keyCode;
	var filter	= ( isNN ) ? [0,8,9] : [0,8,9,16,17,18,37,38,39,40,46];
	if( input.value.length >= len && !containsElement( filter, keyCode ))
	{
		input.value = input.value.slice( 0, len );
		input.form[( getIndex( input ) + 1 ) % input.form.length].focus();
	}
	return true;
}

function containsElement( arr, ele )
{
	var found = false, index = 0;
	while( !found && index < arr.length )
	if( arr[index] == ele )
	{
		found = true;
	} else {
		index++;
	}
	return found;
}

function getIndex( input )
{
	var index = -1, i = 0, found = false;
	while ( i < input.form.length && index == -1 )
	if ( input.form[i] == input )
	{
		index = i;
	} else {
		i++;
	}
	return index;
}

var TimerIDArray = new Array();
var TimerIDCount = 0;

function runningCounter(name,sec)
{
	var increment = 1;
	var mins = Math.floor(sec/60);
	var seconds = sec % 60;
	var hours = Math.floor(mins/60);
	var minutes = mins % 60;
	var m = '';
	var s = '';

	if(minutes < 10) m = 0;
	if(seconds < 10) s = 0;

	var time = hours+':'+m+''+minutes+':'+s+''+seconds;

	if( document.getElementById(name) )
	{
		document.getElementById(name).innerHTML = time;
	}

	if( document.getElementById(name+'_hidden') )
	{
		document.getElementById(name+'_hidden').value = sec;
	}

	var next = sec + increment;
	var nextCount = TimerIDCount++;

	TimerIDArray[TimerIDCount++] = setTimeout('runningCounter(\''+name+'\','+next+')',increment * 1000);
}

function checkAll(thisis, what)
{
	var theform = thisis.form;
	
	if( what )
	{
		for(i = 0; i < theform.elements.length; i++)
		{
			if(theform.elements[i].type == 'checkbox' && theform.elements[i].name != 'checkall' && theform.elements[i].id.match(what))
			{
				if( thisis.checked == true )
				{
					theform.elements[i].checked = true;
				} else {
					theform.elements[i].checked = false;
				}
			}
		}
	} else {
		for(i = 0; i < theform.elements.length; i++)
		{
			if( theform.elements[i].type == 'checkbox' )
			{
				if( theform.elements[i].checked == true )
				{
					theform.elements[i].checked = true;
				} else {
					theform.elements[i].checked = false;
				}
			}
		}
	}
}

function nothing() {}

function loadTimeEntryOptions(thisis, parent_id, which, status, archived, this_record_id)
{
	ajaxLoadingScreen('Loading...');
	var xmlhttp = xmlHttpObject();
	var url = 'find.php?which='+which+'&parent_id='+parent_id+'&status='+status+'&archived='+archived+'&this_record_id=' + this_record_id;
	
	xmlhttp.open("GET",url,true);
	xmlhttp.onreadystatechange = function()
	{
		if(xmlhttp.readyState == 4)
		{
			var string = xmlhttp.responseText;
			var selectMenu = thisis.form.elements[which+'_id'];
			
			buildOptions(string, selectMenu);
			loadStaticOptions(selectMenu, status);

			selectMenu.style.visibility = 'visible';
			selectMenu.style.position = 'relative';
		}
	}

	xmlhttp.send(null);

	if( which == 'project' )
	{
    if( thisis.form.elements['project_id'] )
    {
		  thisis.form.elements['project_id'].selectedIndex = 0;
		}

    if( thisis.form.elements['task_id'] )
    {
      thisis.form.elements['task_id'].length = 0;
	  }
  }

  hideAjaxLoadingScreen();
}

function loadUserOptions(thisis)
{
	ajaxLoadingScreen('Loading...');

	var xmlhttp = xmlHttpObject();
	var url = 'find.php?which=user&status='+thisis.value+'&this_record_id='+thisis.value;

	xmlhttp.open("GET",url,true);
	xmlhttp.onreadystatechange = function()
	{
		if(xmlhttp.readyState == 4)
		{
			var string = xmlhttp.responseText;
			var selectMenu = thisis.form.elements['user_id'];

			buildOptions(string, selectMenu, thisis.value);

			selectMenu.options[selectMenu.options.length] = new Option('----------------------','spacer');
			selectMenu.options[selectMenu.options.length] = new Option('Show All','show_all');
			selectMenu.options[selectMenu.options.length] = new Option('Show Active','show_active');
			selectMenu.options[selectMenu.options.length] = new Option('Show Inactive','show_inactive');

			selectMenu.style.visibility = 'visible';
			selectMenu.style.position = 'relative';
			hideAjaxLoadingScreen();
		}
	}

	xmlhttp.send(null);
}

function buildOptions(result, selectMenu)
{
  if( !selectMenu )
  {
    return '';
  }

	var string = new String(result);
	var records = string.split(':::');
  
	selectMenu.options.length = records.length;

	if( string.length > 3 )
	{
		for(i = 0; i < records.length; i++)
		{
			record = records[i].split('=');
			selectMenu.options[i] = new Option(record[1],record[0]);
		}
	} else {
		selectMenu.length = 0;
	}
}

function loadStaticOptions(selectMenu, status)
{
	selectMenu.options[selectMenu.options.length] = new Option('----------------------','spacer');
	selectMenu.options[selectMenu.options.length] = new Option('Show All','show_all');
	selectMenu.options[selectMenu.options.length] = new Option('Show Recent','show_recent');
	selectMenu.options[selectMenu.options.length] = new Option('Add New','add_new');
}

function showEditIcon(which)
{
	if( !document.getElementById(which+'_id') || !document.getElementById(which+'_edit_icon') )
	{
		return;
	}

	if(document.getElementById(which+'_id').value != '' && document.getElementById(which+'_id').value != 'show_all' && document.getElementById(which+'_id').value != 'show_recent' && document.getElementById(which+'_id').value != 'add_new' && document.getElementById(which+'_id').value != 'spacer')
	{
		document.getElementById(which+'_edit_icon').style.visibility = 'visible';
		document.getElementById(which+'_edit_icon').style.position = 'relative';
	} else {
		document.getElementById(which+'_edit_icon').style.visibility = 'hidden';
		document.getElementById(which+'_edit_icon').style.position = 'absolute';
	}
}

function changeIcons()
{
	showEditIcon('organization');
	showEditIcon('project');
	showEditIcon('task');
}

function openerShowEditIcon(which)
{
	if( !opener.document.getElementById(which+'_id') || !opener.document.getElementById(which+'_edit_icon') )
	{
		return;
	}

	if(opener.document.getElementById(which+'_id').value != '' && opener.document.getElementById(which+'_id').value != 'show_all' && opener.document.getElementById(which+'_id').value != 'show_recent' && opener.document.getElementById(which+'_id').value != 'add_new' && opener.document.getElementById(which+'_id').value != 'spacer')
	{
		opener.document.getElementById(which+'_edit_icon').style.visibility = 'visible';
		opener.document.getElementById(which+'_edit_icon').style.position = 'relative';
	} else {
		opener.document.getElementById(which+'_edit_icon').style.visibility = 'hidden';
		opener.document.getElementById(which+'_edit_icon').style.position = 'absolute';
	}
}

function quickRedirect(which,name,id,postid)
{
	if(!postid)
	{
		var element = opener.document.getElementById(which+'_id');
		element.options[element.options.length] = new Option(name,id);
		element.selectedIndex = element.options.length - 1;
		openerShowEditIcon(which);

		if(opener.document.getElementById(getWhichChild(which)+'_id'))
		{
			opener.document.getElementById(getWhichChild(which)+'_id').options.length = 0;
		}
	}

	window.close();
}

function getWhichChild(which)
{
	if(which == 'organization')
	{
		return 'project';
	}
	else if(which == 'project')
	{
		return 'task';
	}
}

function toggleMenu(forceClose)
{
	var c = getCookie('menu');
	var menu = document.getElementById('menu_container');
	var menu_button = document.getElementById('menu_button');
	var forceClose = forceClose ? true:false;

	if(c == 'hidden' && forceClose == false)
	{
		//new Effect.Appear(menu);
		menu.style.visibility = 'visible';
		menu.style.position = 'relative';

		menu_button.className = 'menu_button_hover';

		setCookie('menu','showing');
	} else {
		//new Effect.Fold(menu);
		menu.style.visibility = 'hidden';
		menu.style.position = 'absolute';

		menu_button.className = 'menu_show_button_hover';

		setCookie('menu','hidden');
	}

	menu_button.style.visibility = 'visible';
	menu_button.style.position = 'absolute';
	menu_button.style.zIndex = 1;
}

function menuButtonHover()
{
	var c = getCookie('menu');
	var menu_button = document.getElementById('menu_button');

	if(c == 'hidden')
	{
		menu_button.className = 'menu_show_button_hover';
	} else {
		menu_button.className = 'menu_button_hover';
	}
}

function menuButtonMouseOut()
{
	var c = getCookie('menu');
	var menu_button = document.getElementById('menu_button');

	if(c == 'hidden')
	{
		menu_button.className = 'menu_show_button';
	} else {
		menu_button.className = 'menu_button';
	}
}

function showHoverBox(id)
{
	document.getElementById(id).style.visibility = 'visible';
}

function hideHoverBox(id)
{
	document.getElementById(id).style.visibility = 'hidden';
}

function checkTimeEntryCheckbox(form,time_entry_id)
{
	for(i = 0; i < form.elements.length; i++)
	{
		if(form.elements[i].id == "checked_time_entry" && form.elements[i].value == time_entry_id)
		{
			form.elements[i].disabled = false;
			form.elements[i].checked = true;
			break;
		}
	}
}

function checkTimeSheetCheckbox(form,time_sheet_id)
{
	for(i = 0; i < form.elements.length; i++)
	{
		if(form.elements[i].id == "checked_time_sheet" && form.elements[i].value == time_sheet_id)
		{
			form.elements[i].disabled = false;
			form.elements[i].checked = true;
			break;
		}
	}
}

function urlAppend(currentURL, stringToAppend)
{
	if( currentURL.match(/\?/) )
	{
		return currentURL + '&' + stringToAppend;
	} else {
		return currentURL + '?' + stringToAppend;
	}
}

function reloadListSearch(searchForm, listID)
{
	var searchURL = buildGetURL(searchForm);
	
	if( searchForm && searchForm.search )
	{
		searchForm.search.disabled = true;
	}
	
	replaceListContents(searchURL, listID, searchForm);
}

function buildGetURL(searchForm)
{
	var baseURL = searchForm.action;

	var queryString = "";

	for(i = 0; i < searchForm.elements.length; i++)
	{
		if(searchForm.elements[i].type != 'checkbox')
		{
			value = searchForm.elements[i].value;
		} else {
			if(searchForm.elements[i].checked == true)
			{
				value = searchForm.elements[i].value;
			} else {
				value = "";
			}
		}

		queryString = queryString + searchForm.elements[i].name + '='+ value +'&';
	}

	url = urlAppend(baseURL, queryString);

	return url;
}

function stripFromURL(url, param)
{
	var newParam = param.replace('[', '\\[');
	newParam = newParam.replace(']', '\\]');

	var regex = new RegExp('[&]' + newParam + "=[^&]+");
	var url = url.replace(regex, "");

	var regex = new RegExp('[?]' + newParam + "=[^&]+");
	var url = url.replace(regex, "?");

	return url;
}

function reloadListPage(currentURL,listID,pageNumber)
{
	var currentURL = stripFromURL(currentURL, 'page[' + listID + ']');

	var url = urlAppend(currentURL, 'page['+listID+']=' + pageNumber);

	replaceListContents(url,listID);
}

function reloadListNewSort(currentURL,listID,sortBy, sortOrder)
{
	var currentURL = stripFromURL(currentURL, 'page[' + listID + ']');
	var currentURL = stripFromURL(currentURL, 'sortby[' + listID + ']');
	var currentURL = stripFromURL(currentURL, 'order[' + listID + ']');

	var url = urlAppend(currentURL, 'sortby['+listID+']=' + sortBy + '&order['+listID+']=' + sortOrder);
	
	replaceListContents(url,listID);
}

function replaceListContents(url, listID, searchForm)
{
	var url = urlAppend(url, 'reload_list_content=1&list_to_reload=' + listID);
	
	new Ajax.Updater(listID, url, { evalScripts: true, onCreate: function() { preReplaceListContents(); }, onSuccess: function() { postReplaceListContents(searchForm); } });
}

function preReplaceListContents()
{
	ajaxLoadingScreen();
}

function postReplaceListContents(searchForm)
{
	hideAjaxLoadingScreen();
	
	if( searchForm && searchForm.search )
	{
		searchForm.search.disabled = false;
	}
}

function ajaxLoadingScreen(msg)
{
	var msg = 'Loading...';
	
	document.getElementById('ajax_loading_div').style.visibility = 'visible';
	document.getElementById('ajax_loading_div').innerHTML = msg;
}

function hideAjaxLoadingScreen()
{
	document.getElementById('ajax_loading_div').style.visibility = 'hidden';
}

function addPageResponse(type,message)
{
	if(type == 'msg')
	{
		func = 'displayMessageBox';
	} else {
		func = 'displayErrorBox';
	}

	x_phpFunc(func,message,'100%',renderPageResponse);
}

function renderPageResponse(result)
{
	document.getElementById('page_response_box').innerHTML = result;
}

function x_phpFunc()
{
	var args = new Array();
	var j = 0;
	var functionName = x_phpFunc.arguments[0];

	for(var i = 0; i < x_phpFunc.arguments.length; i++)
	{
		if (i > 0)
		{
			args[j] = x_phpFunc.arguments[i];
			j++;
		}
	}

	sajax_do_call(functionName, args);
}

function numbersOnly(myfield, e, dec)
{
	var key;
	var keychar;
	
	if (window.event)
		 key = window.event.keyCode;
	else if (e)
		 key = e.which;
	else
		 return true;
	keychar = String.fromCharCode(key);

	// control keys
	if ((key==null) || (key==0) || (key==8) ||
			(key==9) || (key==13) || (key==27) )
		 return true;

	// numbers
	else if ((("0123456789").indexOf(keychar) > -1))
		 return true;

	// decimal point jump
	else if (dec && (keychar == "."))
		 {
		 myfield.form.elements[dec].focus();
		 return false;
		 }
	else
		 return false;
}

function expandCollapseAllAppElements()
{
	var test = document.getElementsByTagName('div');

	for(var i = 0; i < test.length; i++)
	{
		var node = test[i];
		var theId = node.id;

		if(theId.match('holder'))
		{
			ecDiv(theId,'','expanded');
		}
	}
}

function selectTimeEntryOrganization(thisis, archived)
{
	if( thisis.form.project_id && !thisis.form.project_id.type.match('select') )
	{
		return false;
	}
	
	if( thisis.value == '' || thisis.value == 0 )
	{
		if( thisis.form.project_id )
		{
			thisis.form.project_id.options.length = 0;
			thisis.form.project_id.selectedIndex = 0;
		}

		if( thisis.form.task_id )
		{
			thisis.form.task_id.options.length = 0;
			thisis.form.task_id.selectedIndex = 0;
		}

		return;
	}

	if( thisis.value != 'show_all' && thisis.value != 'show_recent' && thisis.value != 'add_new' && thisis.value != 'spacer' )
	{
		loadTimeEntryOptions(thisis, thisis.value, 'project', thisis.form.organization_status.value, archived, 0);
	}
	else if( thisis.value == 'show_all' || thisis.value == 'show_recent' )
	{
		loadTimeEntryOptions(thisis, 0, 'organization', thisis.value, archived, 0);
		thisis.form.organization_status.value = thisis.value;
	}
	else if( thisis.value == 'add_new' )
	{
		window.open('organizations.php?action=edit&quick=1','','width=900,height=600,scrollbars=yes');
	}
	else
	{
		return;
	}
}

function selectTimeEntryProject(thisis, archived)
{
	if( thisis.form.task_id && !thisis.form.task_id.type.match('select') )
	{
		return false;
	}
	
	if( thisis.value == '' || thisis.value == 0 )
	{
		if( thisis.form.task_id )
		{
			thisis.form.task_id.options.length = 0;
			thisis.form.task_id.selectedIndex = 0;
		}

		return;
	}

	if( thisis.value != 'show_all' && thisis.value != 'show_recent' && thisis.value != 'add_new' && thisis.value != 'spacer' )
	{
		loadTimeEntryOptions(thisis, thisis.value, 'task', thisis.form.project_status.value, archived, 0);
	}
	else if( thisis.value == 'show_all' || thisis.value == 'show_recent' )
	{
		loadTimeEntryOptions(thisis, thisis.form.organization_id.value, 'project', thisis.value, archived);
		thisis.form.project_status.value = thisis.value;
	}
	else if( thisis.value == 'add_new' )
	{
		window.open('projects.php?action=edit&quick=1&organization_id='+thisis.form.organization_id.value,'','width=900,height=600,scrollbars=yes');
	}
	else
	{
		return;
	}
}

function selectTimeEntryTask(thisis, archived)
{
	if( thisis.value != 'show_all' && thisis.value != 'show_recent' && thisis.value != 'add_new' && thisis.value != 'spacer' )
	{

	}
	else if( thisis.value == 'show_all' || thisis.value == 'show_recent' )
	{
		loadTimeEntryOptions(thisis, thisis.form.project_id.value, 'task', thisis.value, archived, 0);
		thisis.form.task_status.value = thisis.value;
	}
	else if( thisis.value == 'add_new' )
	{
		window.open('tasks.php?action=edit&quick=1&project_id='+thisis.form.project_id.value,'','width=900,height=600,scrollbars=yes');
	}
	else
	{
		return;
	}
}

function selectUser(thisis)
{
	if( thisis.value != 'show_all' && thisis.value != 'show_active' && thisis.value != 'show_inactive' && thisis.value != 'spacer' )
	{

	}
	else if( thisis.value == 'show_all' || thisis.value == 'show_active' || thisis.value == 'show_inactive' )
	{
		loadUserOptions(thisis);
		thisis.form.user_status.value = thisis.value;
	}
	else
	{
		return;
	}
}

function loadReportWizardGroupByColumnOptions(thisis)
{
	var groupBy = thisis.value;
}

/*
 * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
 * Digest Algorithm, as defined in RFC 1321.
 * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 * Distributed under the BSD License
 * See http://pajhome.org.uk/crypt/md5 for more info.
 */

/*
 * Configurable variables. You may need to tweak these to be compatible with
 * the server-side, but the defaults work in most cases.
 */
var hexcase = 0;  /* hex output format. 0 - lowercase; 1 - uppercase        */
var b64pad  = ""; /* base-64 pad character. "=" for strict RFC compliance   */
var chrsz   = 8;  /* bits per input character. 8 - ASCII; 16 - Unicode      */

/*
 * These are the functions you'll usually want to call
 * They take string arguments and return either hex or base-64 encoded strings
 */
function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}
function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));}
function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));}
function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }
function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }
function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); }

/*
 * Perform a simple self-test to see if the VM is working
 */
function md5_vm_test()
{
  return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
}

/*
 * Calculate the MD5 of an array of little-endian words, and a bit length
 */
function core_md5(x, len)
{
  /* append padding */
  x[len >> 5] |= 0x80 << ((len) % 32);
  x[(((len + 64) >>> 9) << 4) + 14] = len;

  var a =  1732584193;
  var b = -271733879;
  var c = -1732584194;
  var d =  271733878;

  for(var i = 0; i < x.length; i += 16)
  {
    var olda = a;
    var oldb = b;
    var oldc = c;
    var oldd = d;

    a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
    d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
    c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);
    b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
    a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
    d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);
    c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
    b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
    a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
    d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
    c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
    b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
    a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);
    d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
    c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
    b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);

    a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
    d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
    c = md5_gg(c, d, a, b, x[i+11], 14,  643717713);
    b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
    a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
    d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);
    c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
    b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
    a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
    d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
    c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
    b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);
    a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
    d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
    c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);
    b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);

    a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
    d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
    c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562);
    b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
    a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
    d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);
    c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
    b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
    a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);
    d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
    c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
    b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
    a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
    d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
    c = md5_hh(c, d, a, b, x[i+15], 16,  530742520);
    b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);

    a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
    d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);
    c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
    b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
    a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);
    d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
    c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
    b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
    a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
    d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
    c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
    b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649);
    a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
    d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
    c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);
    b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);

    a = safe_add(a, olda);
    b = safe_add(b, oldb);
    c = safe_add(c, oldc);
    d = safe_add(d, oldd);
  }
  return Array(a, b, c, d);

}

/*
 * These functions implement the four basic operations the algorithm uses.
 */
function md5_cmn(q, a, b, x, s, t)
{
  return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
}
function md5_ff(a, b, c, d, x, s, t)
{
  return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
function md5_gg(a, b, c, d, x, s, t)
{
  return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
function md5_hh(a, b, c, d, x, s, t)
{
  return md5_cmn(b ^ c ^ d, a, b, x, s, t);
}
function md5_ii(a, b, c, d, x, s, t)
{
  return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
}

/*
 * Calculate the HMAC-MD5, of a key and some data
 */
function core_hmac_md5(key, data)
{
  var bkey = str2binl(key);
  if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz);

  var ipad = Array(16), opad = Array(16);
  for(var i = 0; i < 16; i++)
  {
    ipad[i] = bkey[i] ^ 0x36363636;
    opad[i] = bkey[i] ^ 0x5C5C5C5C;
  }

  var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
  return core_md5(opad.concat(hash), 512 + 128);
}

/*
 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
 * to work around bugs in some JS interpreters.
 */
function safe_add(x, y)
{
  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
  return (msw << 16) | (lsw & 0xFFFF);
}

/*
 * Bitwise rotate a 32-bit number to the left.
 */
function bit_rol(num, cnt)
{
  return (num << cnt) | (num >>> (32 - cnt));
}

/*
 * Convert a string to an array of little-endian words
 * If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
 */
function str2binl(str)
{
  var bin = Array();
  var mask = (1 << chrsz) - 1;
  for(var i = 0; i < str.length * chrsz; i += chrsz)
    bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
  return bin;
}

/*
 * Convert an array of little-endian words to a string
 */
function binl2str(bin)
{
  var str = "";
  var mask = (1 << chrsz) - 1;
  for(var i = 0; i < bin.length * 32; i += chrsz)
    str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
  return str;
}

/*
 * Convert an array of little-endian words to a hex string.
 */
function binl2hex(binarray)
{
  var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
  var str = "";
  for(var i = 0; i < binarray.length * 4; i++)
  {
    str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
           hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF);
  }
  return str;
}

/*
 * Convert an array of little-endian words to a base-64 string
 */
function binl2b64(binarray)
{
  var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  var str = "";
  for(var i = 0; i < binarray.length * 4; i += 3)
  {
    var triplet = (((binarray[i   >> 2] >> 8 * ( i   %4)) & 0xFF) << 16)
                | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )
                |  ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
    for(var j = 0; j < 4; j++)
    {
      if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
      else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
    }
  }
  return str;
}

function clickTimeEntryListSortBy()
{
	var box = document.getElementById('sort_by_box');
	
	if( box.style.visibility == 'hidden' || box.style.visibility == '' )
	{
		box.style.visibility = 'visible';
	} else {
		box.style.visibility = 'hidden';
	}
}

function toggleTimeEntryListDetail(time_entry_id, forceHide)
{
	if( !time_entry_id )
	{
		return;
	}
	
	forceHide = forceHide ? true:false;
	
	var detailDiv = document.getElementById(time_entry_id + '_time_entry_details');
	var toggleIcon = document.getElementById(time_entry_id + '_toggle_icon');
	var src = new String(toggleIcon.src);
	var detailsRow = document.getElementById(time_entry_id + '_time_entry_details_row');
	
	if( !detailDiv || !toggleIcon || !src || !detailsRow )
	{
		return;
	}
	
	if( src.match(/collapse/) || forceHide )
	{
		src = src.replace(/collapse/, 'expand');
		detailDiv.style.display = 'none';
		detailsRow.style.display = 'none';
		
		document.getElementById('current_expanded').value = '';
	} else {
		src = src.replace(/expand/, 'collapse');
		detailDiv.style.display = 'block';
		
		// fix me: this is for ie/firefox...ie does not support table-row
		// use if ie condition, don't know how to do that now
		try {
			detailsRow.style.display = 'table-row';
		} catch (e) {
			detailsRow.style.display = 'block';
		}
		
		if( detailDiv.innerHTML == '' )
		{	
    		x_phpFunc('timeEntryListDetails', time_entry_id, function (html) { document.getElementById(time_entry_id + '_time_entry_details').innerHTML = html; });
		}
		
		var currentExpanded = document.getElementById('current_expanded').value;
		
		if( currentExpanded > 0 && currentExpanded != time_entry_id )
		{
			toggleTimeEntryListDetail(currentExpanded);
		}
		
		document.getElementById('current_expanded').value = time_entry_id;
		document.getElementById('checked_time_entry_' + time_entry_id).disabled = false;
		
		location.href = '#time_entry_anchor_' + time_entry_id;
	}
	
	toggleIcon.src = src;
}

function getKeyPressed(e)
{
	if( !e )
	{
		//if the browser did not pass the event information to the
		//function, we will have to obtain it from the event register
		if( window.event )
		{
		  //Internet Explorer
		  e = window.event;
		} else {
		  //total failure, we have no way of referencing the event
		  return;
		}
	}
	
	if( typeof( e.keyCode ) == 'number'  )
	{
		//DOM
		e = e.keyCode;
	}
	else if( typeof( e.which ) == 'number' )
	{
		//NS 4 compatible
		e = e.which;
	}
	else if( typeof( e.charCode ) == 'number'  )
	{
		//also NS 6+, Mozilla 0.9+
		e = e.charCode;
	}
	else
	{
	//total failure, we have no way of obtaining the key code
	return;
	}
	
	return String.fromCharCode(e);
}

function navigateTimeEntries(e)
{
	var keyPressed = getKeyPressed(e);
	
	var currentExpanded = document.getElementById('current_expanded');
	var currentExpandedId = currentExpanded.value;
	
	// down
	if( keyPressed == 'K' )
	{
		var newId = getPreviousId(currentExpandedId);
		
		if( newId && currentExpandedId != newId )
		{
			toggleTimeEntryListDetail(newId);
		}
	}
	// up
	else if( keyPressed == 'J' )
	{
		var newId = getNextId(currentExpandedId);
		
		if( newId && currentExpandedId != newId )
		{
			toggleTimeEntryListDetail(newId);
		}
	}
	else if( keyPressed == 'C' )
	{
		if( currentExpandedId )
		{
			document.getElementById('checked_time_entry_' + currentExpandedId).checked = !document.getElementById('checked_time_entry_' + currentExpandedId).checked;
		}
	}
	
	var currentExpanded = document.getElementById('current_expanded');
	var currentExpandedId = currentExpanded.value;
	
	document.getElementById('checked_time_entry_' + currentExpandedId).disabled = false;
}

function hideTimeEntryDetail(time_entry_id)
{
	toggleTimeEntryListDetail(time_entry_id, true);
}

function getTimeEntryListTimeEntryIds()
{
	var timeEntryIds = new Array();
	var checkboxes = document.getElementsByClassName('time_entry_list_checkbox');
	
	j = 0;
	for(i = 0; i < checkboxes.length; i++)
	{
		j++;
		
		var checkbox = checkboxes[i];
		var time_entry_id = checkbox.id.replace('checked_time_entry_', '');
		
		timeEntryIds[j] = time_entry_id;
	}
	
	return timeEntryIds;
}

function getNextId(currentId)
{
	var timeEntryIds = getTimeEntryListTimeEntryIds();
	var currentIdKey = getCurrentIdKey(currentId);
	
	if( currentIdKey > 0 )
	{
		var nextIdKey = currentIdKey + 1;
	} else {
		var nextIdKey = 1;
	}
	
	return timeEntryIds[nextIdKey];
}

function getPreviousId(currentId)
{
	var timeEntryIds = getTimeEntryListTimeEntryIds();
	var currentIdKey = getCurrentIdKey(currentId);
	
	if( currentIdKey > 1 )
	{
		var prevIdKey = currentIdKey - 1;
	} else {
		var prevIdKey = 1;
	}
	
	return timeEntryIds[prevIdKey];
}

function getCurrentIdKey(currentId)
{
	var timeEntryIds = getTimeEntryListTimeEntryIds();
	for(i = 0; i < timeEntryIds.length; i++)
	{
		if( timeEntryIds[i] == currentId )
		{
			return Number(i);
		}
	}
}