
function TaHilite(fld,onoff) {
	fld.style.backgroundColor = (onoff?'#FFFF9C':'transparent');
}

function tackOn(fldName,suffix) {
	if (fldName.substr(fldName.length-1)==']')
		return fldName.substr(0,fldName.length-1)+suffix+"]";
	else 
		return fldName+"_"+suffix;
}

var lastTaBegin = new Array();
var levelInProgress = false;

function commitTaInFlight() {
	if (lastTaBegin.length>=7)	{
		commitTaEdit(lastTaBegin.shift(),lastTaBegin.shift(),lastTaBegin.shift(),lastTaBegin.shift(),lastTaBegin.shift(),lastTaBegin.shift(),lastTaBegin.shift(),currentActionMonitorId);
	}
}
function cancelTaInFlight() {
	while (lastTaBegin.length)
		var eat=lastTaBegin.shift();
}

function beginTaEdit(frm,fldName,tbl,tblPk,tblPkId,tblFld,postFunc) {
	//postFunc - function to run text through upon commit
	if (levelInProgress)return;	/* to prevent a 'row drop' activity from triggering a field edit */
	commitTaInFlight();
	if (tableDnD) tableDnD.setRowsDragMode(false);
	if (tableDnDAgenda) tableDnDAgenda.setRowsDragMode(false);

	lastTaBegin.push(frm,fldName,tbl,tblPk,tblPkId,tblFld,postFunc);
	// show '$fldName_taInDiv' and hide '$fldName_taOutDiv'
	var fldType = document.forms[frm].elements[tackOn(fldName,'_taInFld')].type;
	if (fldType == 'checkbox') {
		document.forms[frm].elements[tackOn(fldName,'_taInFld')].checked = document.forms[frm].elements[fldName].value == 'Y';
	} else if (fldType.indexOf('select')!=-1) {
		var elem = document.forms[frm].elements[tackOn(fldName,'_taInFld')];
		document.forms[frm].elements[tackOn(fldName,'_taInFld')].value = elem[elem.selectedIndex].value;
	} else {
		document.forms[frm].elements[tackOn(fldName,'_taInFld')].value = unescape(document.forms[frm].elements[fldName].value);
		resizeTextarea(document.forms[frm].elements[tackOn(fldName,'_taInFld')]);
	}
	showHideContent(tackOn(fldName,'_taInDiv'),'show');
	showHideContent(tackOn(fldName,'_taOutDiv'),'hide');
	
	document.forms[frm].elements[tackOn(fldName,'_taInFld')].focus();
}

function commitTaEdit(frm,fldName,tbl,tblPk,tblPkId,tblFld,postFunc,actionmonitorId) {
	// move '$fldName_taInFld'.value to '$fldName'.value and '$fldName_taOutFld'.innerHTML
	// hide '$fldName_taInDiv' and show '$fldName_taOutDiv'
	var fldIn  = document.forms[frm].elements[tackOn(fldName,'_taInFld')];
	var fldOut = document.forms[frm].elements[tackOn(fldName,'_taOutFld')]
	if (fldIn.type == 'checkbox') {
		var textCommit = fldIn.checked?'Y':'N';
		fldOut.checked = textCommit=='Y';
		var textDisplay = textCommit;
	} else if (fldIn.type.indexOf('select')!=-1) {
		var textCommit = fldIn.value;
		var textDisplay = fldIn[fldIn.selectedIndex].text;
	} else {
		var textCommit = fldIn.value;
		var textDisplay = textCommit;
	}
	//textCommit = textCommit.replace(/<br>/ig,"\n");
	
	/* if post processing function fails, cancel this edit */
	if (postFunc && !postFunc(textCommit)) {
		cancelTaEdit(frm,fldName);
		alert('Sorry, but '+textCommit+' is not in the proper time format.')
		return;
	}
	
	document.forms[frm].elements[fldName].value = textCommit;
	showHideContent(tackOn(fldName,'_taInDiv'),'hide');
	showHideContent(tackOn(fldName,'_taOutDiv'),'show');
	var fldType = document.forms[frm].elements[tackOn(fldName,'_taInFld')].type;
	if (fldIn.type != 'checkbox' ) {
		var elem = _getElement(tackOn(fldName,'_taOutFld'));
		if(!elem.firstChild) {
			var tn = document.createTextNode("");
			elem.appendChild(tn);
		} 
		while (elem.firstChild) {
		    elem.removeChild(elem.firstChild);
		}
		elem.appendChild(convert2Dom(textDisplay),elem.firstChild);
	}
	if (postFunc)
		textCommit=postFunc(textCommit);
	
	singleFldUpdate(tbl,tblPk,tblPkId,tblFld,textCommit,actionmonitorId);
	if (tableDnD) tableDnD.setRowsDragMode(true);
	if (tableDnDAgenda) tableDnDAgenda.setRowsDragMode(true);
}

function removeCurly(s) {
	if (s) {
		s=s.replace(/\"/g,"'");
		s=s.replace(/\xa0/g,"");
		s=s.replace(/\xa9/g,"\(c\)");
		s=s.replace(/\xae/g,"\(r\)");
		s=s.replace(/\xb7/g,"*");
		s=s.replace(/\u2018/g,"'");
		s=s.replace(/\u2019/g,"'");
		s=s.replace(/\u201c/g,'"');
		s=s.replace(/\u201d/g,'"');
		s=s.replace(/\u8220/g,"'");
		s=s.replace(/\u8221/g,"'");
		s=s.replace(/\u2026/g,"...");
		s=s.replace(/\u2002/g,"");
		s=s.replace(/\u2003/g,"");
		s=s.replace(/\u2009/g,"");
		s=s.replace(/\u2012/g,"--");
		s=s.replace(/\u2013/g,"--");
		s=s.replace(/\u2014/g,"--");
		s=s.replace(/\u2015/g,"--");
		s=s.replace(/\u2122/g,"\(tm\)");	
	}
	return s;
}

var ajax_process = new Array();

function get_ajax_process() {
	var nIdx=0;
	for(var nIdx=0; nIdx<ajax_process.length; nIdx++) {
		if (ajax_process[nIdx]==null)
			break;
	}
	ajax_process[nIdx] = new sack;
	return nIdx;
}

function free_ajax_process(idx) {
	ajax_process[idx] = null;
	return true;
}

var ajax_process = new Array();
function singleFldUpdate(tbl,tblPk,tblPkId,tblFld,textCommit,actionmonitorId) {
	if (tbl) {
		if (!actionmonitorId) actionmonitorId='';
		ajaxRunning = true;
		var aIdx = get_ajax_process();
		var textCommit = removeCurly(textCommit);
		ajax_process[aIdx].requestFile = 'actionmonitor.php?action=update_field&tbl='+tbl+'&tblPk='+tblPk+'&tblPkId='+tblPkId+'&tblFld='+tblFld+'&tblData='+escape(textCommit)+'&actionmonitor_id='+escape(actionmonitorId);
		ajax_process[aIdx].onCompletion = function() { 
			ajaxRunning = false;
			standbyAjaxMsg(false);
			checkFldUpdateCallback(tbl,tblFld,actionmonitorId,textCommit,ajax_process[aIdx].response);
			free_ajax_process(aIdx);
		 };
		standbyAjaxMsg(true);
		ajax_process[aIdx].runAJAX();	
	}
}

var fldUpdateCallbacks = new Array();
function registerFldUpdateCallback(tbl,tblFld,callback,flush) {
	if (flush)
		fldUpdateCallbacks = Array();
	fldUpdateCallbacks.push(new Array(tbl,tblFld,callback));
}

function checkFldUpdateCallback(tbl,tblFld,actionmonitorId,textCommit,response) {
	// -called after single field updates; comes in with table name, table field name and the response from the field update.
	// -execute the callback registered for the field (if any)
	for (var i = 0; i < fldUpdateCallbacks.length; i++ ) {
		if (fldUpdateCallbacks[i][0] == tbl && fldUpdateCallbacks[i][1]==tblFld )
			fldUpdateCallbacks[i][2](actionmonitorId,textCommit,response);	//execute the callback passing the response from the field update
	}
}

function convert2Dom(text) {
	var ret = document.createElement("span");
	if (text.length) {
		for (var i = 0; i < text.length; i++ ) {
			if (text.substr(i,1)=='\n')
				ret.appendChild(document.createElement("br"));
			else
				ret.appendChild(document.createTextNode(text.substr(i,1)));
		}
	} else {
		ret.appendChild(document.createTextNode('\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0'));
	}
	return ret;
//	elem.appendChild(document.createElement("br"));
}

function cancelTaEdit(frm,fldName) {
	// restore '$fldName'.value to '$fldName_taInFld'.value
	// hide '$fldName_taInDiv' and show '$fldName_taOutDiv'
	cancelTaInFlight();
	document.forms[frm].elements[tackOn(fldName,'_taInFld')].value = document.forms[frm].elements[fldName].value;
	showHideContent(tackOn(fldName,'_taInDiv'),'hide');
	showHideContent(tackOn(fldName,'_taOutDiv'),'show');
	if (tableDnD) tableDnD.setRowsDragMode(true);
	if (tableDnDAgenda) tableDnDAgenda.setRowsDragMode(true);	
}

function toggleEditable()
{
	var links = document.getElementsByTagName('span');
	var new_mode = '';
   
	commitTaInFlight();   // if we are exiting edit mode, commit any open field edit

	for(i=0; i <links.length;i++)
	{
		if(links[i].className == 'editable') {
			links[i].className = 'noteditable';
			new_mode = 'edit';
		} else {
			if(links[i].className == 'noteditable') {
				links[i].className = 'editable';
				new_mode = 'end edit';
			}
		}
	}
	var links = document.getElementsByTagName('a');
	for(i=0; i <links.length;i++)
	{
		if(links[i].className.search('editable') != -1) {
			if(links[i].className.search('hidelink') != -1) {
				links[i].className='editable';
				new_mode = 'end edit';
			} else {
				links[i].className='editable hidelink';
	        	new_mode = 'edit';
	    	}
		}
	}
   
	var radios = document.getElementsByTagName('input');
	for(i=0; i <radios.length;i++)
	{
		if(radios[i].className == 'attend')
			radios[i].disabled = !radios[i].disabled;
	}
   
   	document.getElementById("toggle_edit_text").innerHTML=new_mode
	if (tableDnD)
   		tableDnD.setRowsDragMode(new_mode=="end edit");
	if (tableDnDAgenda)
   		tableDnDAgenda.setRowsDragMode(new_mode=="end edit");
   
	return new_mode;
}

function inEditMode() {
   	var new_mode = document.getElementById("toggle_edit_text").innerHTML;
   	return (new_mode=="end edit");
}

function nl2br(text) {
	if (!text) return "";
	var result = replaceAll(text, "\n", "<br />");
	return result;
}
function br2nl(text) {
	if (!text) return "";
	var result = replaceAll(text, "<br />", "\n");
	return result;
}

function replaceAll( str, from, to ) {
    var idx = str.indexOf( from );

    while ( idx > -1 ) {
        str = str.replace( from, to );
        idx = str.indexOf( from );
    }

    return str;
}

var lastActionMonitorTimestamp = "";
var currentActionMonitorId = "";
var currentPersonId = "";
var currentPersonName = "";
var monitorInst;

function resetMonitorTimestamp() {
	lastActionMonitorTimestamp = "";
}

function monitorUpdate(actionmonitorId,personId,personName) {
	if (monitorInst)
		clearTimeout(monitorInst);
	monitorProcess = "";
	if (actionmonitorId)
		currentActionMonitorId = actionmonitorId;
	if (personId)
		currentPersonId = personId;
	if (personName)
		currentPersonName = personName;
		
	ajaxRunning = true;
	var aIdx = get_ajax_process();
	ajax_process[aIdx].requestFile = 'actionmonitor.php?action=get_timestamp&actionmonitor_id='+currentActionMonitorId;
	ajax_process[aIdx].onCompletion = 	function() {
								if (ajax_process[aIdx].response) {
									var personId = ajax_process[aIdx].response.split(",")[0];
									var timeStamp = ajax_process[aIdx].response.split(",")[1];
									var personName = ajax_process[aIdx].response.split(",")[2];
									if (lastActionMonitorTimestamp != timeStamp && lastActionMonitorTimestamp != "" && personId != currentPersonId) 
										lightRefreshLight(true,'last updated by '+personName+' on \n'+timeStamp);
									else 
										lightRefreshLight(false,'last updated by '+personName+' on \n'+timeStamp);
									if (!lastActionMonitorTimestamp)
										lastActionMonitorTimestamp = timeStamp;
								}
								free_ajax_process(aIdx);
	};
	ajax_process[aIdx].runAJAX();	
	monitorInst = setTimeout('monitorUpdate()',30000);
}

function lightRefreshLight(onOff,msg) {
	var elem = _getElement('refresh_link');
	if (elem) {
		if (onOff) {
			elem.style.backgroundColor = "#FFFF00";
		} else {
			elem.style.backgroundColor = "#FFFFFF";
		}
		if (msg) {
			elem.title=msg;
		}
	} 
	/* else 
	alert('no elem');
	*/
}

var ajaxAM;
var targetElem;
var targetMoveX;
			
function moveRajax( el, targetx )
{
	// t=table node (parent of TR)
	var t = el.parentNode;
	t.replaceChild(t.removeChild(el), t.insertRow(targetx));
}


function moveR( el, actionmonitor_id, item_id, x )
{
	commitTaInFlight();
	// find first TR above the current node
	while ( el.parentNode && 'tr' != el.nodeName.toLowerCase() ){
		el = el.parentNode;
	}	
	targetElem = el;

	// t=table node (parent of TR)
	var t = el.parentNode;

	if (el.rowIndex==1 && x==-1)
		x=-2;
	if (el.rowIndex==(t.rows.length-1) && x==1)
		x=2;
	targetMoveX = (el.rowIndex + +x)% t.rows.length;
	ajaxRunning = true;
	var aIdx = get_ajax_process();

	ajaxAM.requestFile = 'actionmonitor.php?action=move_actionitem&actionmonitor_id='+actionmonitor_id+'&item_id='+item_id+'&seq='+(targetMoveX<0?targetMoveX+t.rows.length:targetMoveX);
	ajax_process[aIdx].onCompletion = function() {
									moveRajax(targetElem,targetMoveX ); 
									standbyAjaxMsg(false); 
									ajaxRunning = false; 
									free_ajax_process(aIdx);
	};
	standbyAjaxMsg(true);
	ajax_process[aIdx].runAJAX();	
}

function moveToRow( actionmonitor_id, item_id, targetrowno )
{
	commitTaInFlight();
	ajaxRunning = true;
	var aIdx = get_ajax_process();
	ajax_process[aIdx].requestFile = 'actionmonitor.php?action=move_actionitem&actionmonitor_id='+actionmonitor_id+'&item_id='+item_id+'&seq='+targetrowno;
	ajax_process[aIdx].onCompletion = function() { 	
		ajaxRunning = false; 
	    refreshAgenda(actionmonitor_id);
	    free_ajax_process(aIdx);
	};
	standbyAjaxMsg(true);
	ajax_process[aIdx].runAJAX();	
}

function moveAgendaItemToRow( actionmonitor_id, item_id, targetrowno )
{
	commitTaInFlight();
	ajaxRunning = true;
	var aIdx = get_ajax_process();
	ajax_process[aIdx].requestFile = 'actionmonitor.php?action=move_agendaitem&actionmonitor_id='+actionmonitor_id+'&item_id='+item_id+'&seq='+targetrowno;
	ajax_process[aIdx].onCompletion = function() { 	
		ajaxRunning = false; 
		standbyAjaxMsg(false);
		free_ajax_process(aIdx);
	};
	standbyAjaxMsg(true);
	ajax_process[aIdx].runAJAX();	
}

function archiveR( el, actionmonitor_id, item_id )
{
	commitTaInFlight();
	// find first TR above the current node
	while ( el.parentNode && 'tr' != el.nodeName.toLowerCase() ){
		el = el.parentNode;
	}	
	var targetElem = el;

	var cells = targetElem.cells;
	var wasArchivedRow = false;
	for (i=0; i<cells.length; i++) {
		var oldBg = cells[i].style.backgroundColor;
		if (oldBg != 'rgb(255, 255, 255)' && oldBg != '#ffffff') {
			wasArchivedRow = true;
		}
	}
	
	// t=table node (parent of TR)
	var t = el.parentNode;
	if (wasArchivedRow)
		targetMoveX = 1;
	else
		targetMoveX = t.rows.length - 1;
	ajaxRunning = true;
	var aIdx = get_ajax_process();
	ajax_process[aIdx].requestFile = 'actionmonitor.php?action=move_actionitem&archive=yes&actionmonitor_id='+actionmonitor_id+'&item_id='+item_id+'&seq='+(targetMoveX);
	ajax_process[aIdx].onCompletion = 
			function() { 	
				moveRajax(targetElem,targetMoveX ); 
				var cells = targetElem.cells;
				var wasArchivedRow = false;
				for (i=0; i<cells.length; i++) {
					var oldBg = cells[i].style.backgroundColor;
					if (oldBg == 'rgb(255, 255, 255)' || oldBg == '#ffffff'|| oldBg == '') {
						cells[i].style.backgroundColor = '#cccccc';
					} else {
						wasArchivedRow = true;
						cells[i].style.backgroundColor = '#ffffff';
					}
					var iconimgs = cells[i].getElementsByTagName('img');
					for (j=0; j<iconimgs.length; j++) {
						if(iconimgs[j].src.indexOf('archive.png')!=-1) {
							iconimgs[j].src='pics/icons/am_'+(wasArchivedRow?'':'un')+'archive.png';
							iconimgs[j].title=(wasArchivedRow?'':'un')+'archive this item';
						}
					}
				}
				
				if (wasArchivedRow)
					alert('The item was unarchived and moved to the top of the item list');
				else
					alert('The item was archived and moved to the bottom of the item list');

				standbyAjaxMsg(false); 
				ajaxRunning = false;
				dtabRefreshTab("tasks");
			    refreshAgenda(actionmonitor_id);
			    free_ajax_process(aIdx);
	};
	standbyAjaxMsg(true);
	ajax_process[aIdx].runAJAX();	
}


function cloneR( el )
{
	// find first TR above the current node
	while ( el.parentNode && 'tr' != el.nodeName.toLowerCase() ){
		el = el.parentNode;
	}
	
	// t=table node (parent of TR)
	var t = el.parentNode;

	// insert a blank row above current row
	var i = (el.rowIndex)% t.rows.length;
	t.replaceChild(el.cloneNode(true), t.insertRow(i));
}

function deleteRajax( el )
{
	// find first TR above the current node
	while ( el.parentNode && 'tr' != el.nodeName.toLowerCase() ){
		el = el.parentNode;
	}
	// t=table node (parent of TR)
	var t = el.parentNode;
	r = t.removeChild(el);
}

function setLevelRajax( prefix, item_id, level )
{
	var tstlev = parseInt(level);
	document.getElementById(prefix+item_id).style.marginLeft = (tstlev*30)+"px";
}

function getLevelR( prefix, item_id )
{
	var marginLeft = document.getElementById(prefix+item_id).style.marginLeft.replace(/[^0-9]/g,'');  /* extract pixel amt as the numeric part of the margin-left spec  (ex: 123px) */
	//var marginLeft = getLevelRow(document.getElementById(prefix+item_id));
	
	return Math.floor(marginLeft / 30);
}

function getLevelRow( prefix, tr )
{
	return getLevelR(prefix,tr.id.replace(/[^0-9]/g,''));
}

function deleteR( el, actionmonitor_id, item_id )
{
	commitTaInFlight();
	ajaxRunning = true;
	var aIdx = get_ajax_process();
	targetElem = el;
	ajax_process[aIdx].requestFile = 'actionmonitor.php?action=delete_actionitem&actionmonitor_id='+actionmonitor_id+'&item_id='+item_id;
	ajax_process[aIdx].onCompletion = function() {
			deleteRajax(targetElem,ajax_process[aIdx].response); 
			standbyAjaxMsg(false); ajaxRunning = false;
			if (tableDnD) {
				var item_table = document.getElementById('item_table');
				tableDnD.init(item_table,1);		/* leave 1 row at top for heading */
				tableDnD.setRowsDragMode(true);
				refreshAgenda(actionmonitor_id);
			}
			free_ajax_process(aIdx);
	};
	standbyAjaxMsg(true);
	ajax_process[aIdx].runAJAX();	
}

function levelR( el, actionmonitor_id, item_id, level, prefix )
{
	commitTaInFlight();
	ajaxRunning = true;
	var aIdx = get_ajax_process();
	targetElem = el;
	levelInProgress = true;
	ajax_process[aIdx].requestFile = 'actionmonitor.php?action=level_actionitem&actionmonitor_id='+actionmonitor_id+'&item_id='+item_id+'&level='+level;
	ajax_process[aIdx].onCompletion = function() {
			setLevelRajax(prefix,item_id,ajax_process[aIdx].response); 
			standbyAjaxMsg(false); ajaxRunning = false;
			if (tableDnD) {
				var item_table = document.getElementById('item_table');
				tableDnD.init(item_table,1);		/* leave 1 row at top for heading */
				tableDnD.setRowsDragMode(true);
			}
			levelInProgress = false;
			free_ajax_process(aIdx);
	};
	standbyAjaxMsg(true);
	ajax_process[aIdx].runAJAX();	
}

function addRajax( el, seq, blank_item_row )
{
	// if seq=0, then add row to the end of table
	// find first TR above the current node
	while ( el.parentNode && 'tr' != el.nodeName.toLowerCase() ){
		el = el.parentNode;
	}
	
	// t=table node (parent of TR)
	var t = el.parentNode;

	// insert a blank row above current row
	var i = (el.rowIndex);
	if (seq==0)
		i = t.rows.length;
	newrow = t.insertRow(i);
	newrow.vAlign = 'top';
	//newrow.innerHTML = blank_item_row;
	
	/* find first DIV in row; extract numeric portion - its the item_id (ex: <div id="action_123"> finds 123)*/
	var divs = blank_item_row.match(/\s+<div.+?(\d+).*?>/);
	/* assigned item_id in the new row's id*/
	if (divs)
		newrow.id = 'actionitem_'+divs[1];
	
	pattern = /\s+<td.+?>/;
	var cols = blank_item_row.split(pattern);
	var colidx = 0;
	for (i=0; i<cols.length; i++) {
		var cell = cols[i].split('</td>');
		if (cell[0]!='') {
			newcell = newrow.insertCell(colidx);
			newcell.innerHTML = cell[0];
			colidx++;
		}
	}
}

function addR( el, actionmonitor_id, seq ) {
	// seq is the row number we want to insert at
	commitTaInFlight();
	ajaxRunning = true;
	var aIdx = get_ajax_process();
	targetElem = el;
	
	ajax_process[aIdx].requestFile = 'actionmonitor.php?action=insert_actionitem&actionmonitor_id='+actionmonitor_id+'&seq='+seq;
	ajax_process[aIdx].onCompletion = function() {
			addRajax(targetElem,seq,ajax_process[aIdx].response);
			if (tableDnD) {
				var item_table = document.getElementById('item_table');
				tableDnD.init(item_table,1);		/* leave 1 row at top for heading */
				tableDnD.setRowsDragMode(true);
			}
	 		standbyAjaxMsg(false);
	 		ajaxRunning = false;
			free_ajax_process(aIdx);	 		
	};
	standbyAjaxMsg(true);
	ajax_process[aIdx].runAJAX();
}

// ajax delete functions 
var ajaxDelete;
function deleteItemLink(id,item_id) {
	ajaxDelete = new sack();
	ajaxDelete.requestFile = 'actionmonitor.php?action=delete_link&link_id='+id;
	ajaxDelete.onCompletion = function() { 
								document.getElementById( "link_zone_"+item_id ).innerHTML = ajaxDelete.response; 
								standbyAjaxMsg(false); 
								ajaxDelete = false; 
								free_ajax_process(aIdx);
	};
	standbyAjaxMsg(true);
	ajaxDelete.runAJAX();	
}

function deleteItemTopicLink(id,item_id) {
	ajaxDelete = new sack();
	ajaxDelete.requestFile = 'actionmonitor.php?action=delete_topiclink&link_id='+id;
	ajaxDelete.onCompletion = function() { 
								document.getElementById( "topiclink_zone_"+item_id ).innerHTML = ajaxDelete.response; 
								standbyAjaxMsg(false); 
								ajaxDelete = false; 
								free_ajax_process(aIdx);
	};
	standbyAjaxMsg(true);
	ajaxDelete.runAJAX();	
}

function deleteItemAttachment(id,item_id) {
	ajaxDelete = new sack();
	ajaxDelete.requestFile = 'actionmonitor.php?action=delete_attachment&aid='+id;
	ajaxDelete.onCompletion = function() { 
								dtabRefreshTab("files");
								document.getElementById( "attachment_zone_"+item_id ).innerHTML = ajaxDelete.response; 
								standbyAjaxMsg(false); 
								ajaxDelete = false; 
								free_ajax_process(aIdx);
	};
	standbyAjaxMsg(true);
	ajaxDelete.runAJAX();	
}

function deleteItemTask(id,parent_id,parent_type) {
	ajaxDelete = new sack();
	ajaxDelete.requestFile = 'actionmonitor.php?action=delete_task&task_id='+id+'&parent_id='+parent_id+'&parent_type='+parent_type;
	ajaxDelete.onCompletion = function() { 
								dtabRefreshTab("tasks");
								if (document.getElementById( "task_zone_"+parent_id ))
									document.getElementById( "task_zone_"+parent_id ).innerHTML = ajaxDelete.response; 
								
								standbyAjaxMsg(false); 
								ajaxDelete = false; 
								free_ajax_process(aIdx);
	};
	standbyAjaxMsg(true);
	ajaxDelete.runAJAX();	
}

<!-- save a copy of the current action monitor -->
function saveCopy(actionmonitor_id,comment,sendemail) {
	ajaxRunning = true;
	var aIdx = get_ajax_process();
	ajax_process[aIdx].requestFile = 'actionmonitor.php?action=save_copy&actionmonitor_id='+actionmonitor_id+'&comment='+escape(comment)+'&sendemail='+escape(sendemail);
	ajax_process[aIdx].onCompletion = function() {
							ajaxRunning = false; 
							document.getElementById( "copy_select_zone" ).innerHTML = ajax_process[aIdx].response;
							standbyAjaxMsg(false); 
							free_ajax_process(aIdx);
							alert('Monitor saved'+(sendemail==true?' & emailed.':''));
						  };
	standbyAjaxMsg(true);
	ajax_process[aIdx].runAJAX();
	return false;
}
<!-- delete the selected copy of the action monitor -->
function deleteCopy(actionmonitor_id,parent_actionmonitor_id) {
	ajaxRunning = true;
	var aIdx = get_ajax_process();
	ajax_process[aIdx].requestFile = 'actionmonitor.php?action=delete_copy&actionmonitor_id='+actionmonitor_id+'&parent_actionmonitor_id='+parent_actionmonitor_id;
	ajax_process[aIdx].onCompletion = function() {
							standbyAjaxMsg(false); 
							ajaxRunning = false; 
							document.getElementById( "copy_select_zone" ).innerHTML = ajax_process[aIdx].response;
							free_ajax_process(aIdx);
							alert('Copy deleted.');
						  };
	standbyAjaxMsg(true);
	ajax_process[aIdx].runAJAX();
	return false;
}
<!-- email a copy of the current action monitor -->
function confirmEmailPopup(promp,width,height,purpose,actionmonitor_id,alreadypreview) {
	promp += '<br><br>Proceed to send email?<br><br>';
	promp += '<input type=button onclick="emailCopy('+actionmonitor_id+',\''+purpose+'\');closePopup()" value="Send Email">&nbsp;';
	if (alreadypreview!=true)
		promp += '<input type=button onclick="emailCopy('+actionmonitor_id+',\''+purpose+'\',\'true\');closePopup()" value=Preview>&nbsp;&nbsp;';
	promp += '<input type=button onclick="closePopup()" value=Cancel>';
	displayPopupStatic(promp,width,height);
}

function emailCopy(actionmonitor_id,purpose,preview,alreadypreview) {
	if(preview=="") preview='false';
	ajaxRunning = true;
	var aIdx = get_ajax_process();
	ajax_process[aIdx].requestFile = 'actionmonitor.php?action=email_copy&actionmonitor_id='+actionmonitor_id+'&purpose='+purpose+'&preview='+preview;
	ajax_process[aIdx].onCompletion = function() {
							standbyAjaxMsg(false); 
							ajaxRunning = false; 
							if (preview) {
								var purp_msg = '';
								if (purpose=='meeting') purp_msg = 'You are requesting to email an announcement of the next meeting.';
								if (purpose=='update') purp_msg = 'You are requesting to email a request to review tasks.';
								if (purpose=='alert') purp_msg = 'You are requesting to email a copy of the latest action monitor.';
								
								confirmEmailPopup('<b>CONFIRMATION OF EMAIL</b><br><br>'+purp_msg+'<br><br>'+nl2br(participantsmsg)+'<br><br><fieldset style="padding: 3;"><legend><b>Email Preview</b></legend><div class=scrollingbox style="height: 350px">'+ajax_process[aIdx].response+'</div></fieldset>',850,600,purpose,actionmonitor_id,true); 
							} else {
								alert('Monitor emailed.');
							}
							free_ajax_process(aIdx);
						  };
	standbyAjaxMsg(true);
	ajax_process[aIdx].runAJAX();
	return false;
}

function confirmEmailTaskPopup(promp,width,height,task_id,alreadypreview) {
	promp += '<br><br>Proceed to send email?<br><br>';
	promp += '<input type=button onclick="emailTaskCopy('+task_id+');closePopup()" value="Send Email">&nbsp;';
	if (alreadypreview!=true)
		promp += '<input type=button onclick="emailTaskCopy('+task_id+',\'true\');closePopup()" value=Preview>&nbsp;&nbsp;';
	promp += '<input type=button onclick="closePopup()" value=Cancel>';
	displayPopupStatic(promp,width,height);
}

function emailTaskCopy(task_id,preview,alreadypreview) {
	if(preview=="") preview='false';
	ajaxRunning = true;
	var aIdx = get_ajax_process();
	ajax_process[aIdx].requestFile = 'actionmonitor.php?action=email_task&task_id='+task_id+'&preview='+preview;
	ajax_process[aIdx].onCompletion = function() {
							standbyAjaxMsg(false); 
							ajaxRunning = false; 
							if (preview) {
								var msg = 'You are requesting to email the status of this task.';
								confirmEmailTaskPopup('<b>CONFIRMATION OF EMAIL</b><br><br>'+msg+'<br><br>'+nl2br(participantsmsg)+'<br><br><fieldset style="padding: 3;"><legend><b>Email Preview</b></legend><div class=scrollingbox style="height: 300px">'+ajax_process[aIdx].response+'</div></fieldset>',850,550,task_id,true); 
							} else {
								alert('Task status emailed.');
							}
							free_ajax_process(aIdx);
						  };
	standbyAjaxMsg(true);
	ajax_process[aIdx].runAJAX();
	return false;
}

/**
 * Encapsulate table Drag and Drop in a class. Singleton, so we don't get scoping problems.
 
 To use, put this in the document.onload event (table-1 is the table getting the drag functionality):
		var table = document.getElementById('table-1');
		var tableDnD = new TableDnD();
		tableDnD.init(table);

.. and this to add logic to the 'dropped' event:

    this.onDrop = function(table, droppedRow) {
        // Do nothing for now
    }
    
    --- another example:
	tableDnD.onDrop = function(table, row) {
    	var rows = this.table.tBodies[0].rows;
	    var debugStr = "rows now: ";
	    for (var i=0; i<rows.length; i++) {
	        debugStr += rows[i].id+" ";
	    }
	    document.getElementById('debug').innerHTML = 'row['+row.id+'] dropped<br>'+debugStr;
	}

 */
function TableDnD() {
    /** Keep hold of the current drag object if any */
    this.dragObject = null;
    /** The current mouse offset */
    this.mouseOffset = null;
    /** The current table */
    this.table = null;
    /** Remember the old values of X & Y so that we don't do too much processing */
    this.oldX = 0;
    this.oldY = 0;
    /** the row number (0=first row) of the first draggable row (to leave room for heading row(s) */
    this.startRow = 0;
    /* row number where row was last dropped */
    this.droppedRowNo = 0;
    /* X offset from start of drag in pixels where row was last dropped - horizontal position*/
    this.droppedXOffset = 0;

    this.lastMouseXpos = 0;
    this.lastMouseYpos = 0;
    
    /** Initialise the drag and drop by capturing mouse move events */
    this.init = function(table,startRow) {
        this.table = table;
        if (!this.table) return;
        if (startRow)
        	this.startRow = startRow;
        //this.setRowsDragMode(onoff);
        var self = this;
        // Now make the onmousemove method in the context of "self" so that we can get back to tableDnD
        
        this.table.onmousemove = function(ev){
            ev   = ev || window.event;
            var mousePos = self.mouseCoords(ev);
            self.lastMouseXpos = mousePos.x;
            self.lastMouseYpos = mousePos.y;
            if (self.dragObject) {
				//commitTaInFlight();
                var x = mousePos.x - self.mouseOffset.x;
                var y = mousePos.y - self.mouseOffset.y;
                if (y != self.oldY) {
                    // work out if we're going up or down...
                    var movingDown = y > self.oldY;
                    // update the old value
                    self.oldY = y;
                    // update the style to show we're dragging
                    self.dragObject.className = 'tablerowDragStyle';

                    // If we're over a row then move the dragged row to there so that the user sees the
                    // effect dynamically
                    var currentRow = self.findDropTargetRow(y);

                    if (currentRow) {
                        if (movingDown && self.dragObject != currentRow) {
                            self.dragObject.parentNode.insertBefore(self.dragObject, currentRow.nextSibling);
                            self.droppedRowNo = self.findRowPosition(self.dragObject);
                        } else if (! movingDown && self.dragObject != currentRow) {
                            self.dragObject.parentNode.insertBefore(self.dragObject, currentRow);
                            self.droppedRowNo = self.findRowPosition(self.dragObject);
                        }
                    }

                    if (1==2 && currentRow) {
                        if (movingDown && self.dragObject != currentRow) {
                        	var testNode = self.dragObject;
                        	var prefix = 'action_item_rowA_';
                        	var rootLevel = getLevelRow( prefix, testNode );
							var levelDepth = 0;
                        	
                        	while (testNode.nextSibling && 'tr' == testNode.nextSibling.nodeName.toLowerCase()) {
                        		if (rootLevel < getLevelRow( prefix, testNode.nextSibling)) {
                        			 levelDepth++;
                        		}
								testNode=testNode.nextSibling;
                        	}
                        	window.status=levelDepth;
	//                            testNode.parentNode.insertBefore(testNode, currentRow.nextSibling);
//	                            self.droppedRowNo = self.findRowPosition(self.dragObject);
                        } else if (! movingDown && self.dragObject != currentRow) {
                            self.dragObject.parentNode.insertBefore(self.dragObject, currentRow);
                            self.droppedRowNo = self.findRowPosition(self.dragObject);
                        }
                    }

                }

                if (x != self.oldX) {
                    self.droppedXOffset = x;
                    self.oldX = x;
                }
				self.onMove(self.table, self.dragObject, self.droppedXOffset);
                return false;
            }
        };

        // Similarly for the mouseup
        this.table.onmouseup   = function(ev){
            if (self.dragObject != null) {
                var droppedRow = self.dragObject;
                // If we have a dragObject, then we need to release it,
                // The row will already have been moved to the right place so we just reset stuff
                droppedRow.className = '';
                self.dragObject   = null;
                // And then call the onDrop method in case anyone wants to do any post processing
                self.onDrop(self.table, droppedRow, self.droppedXOffset);
                self.droppedRowNo = 0;
                self.droppedXOffset = 0;
            }
        };
    }

    /** This function is called when you drop a row, so redefine it in your code
        to do whatever you want, for example use Ajax to update the server */
    this.onDrop = function(table, droppedRow) {
        // Do nothing for now
    }

    /** This function is called when you move a row, so redefine it in your code
        to do whatever you want, for example use Ajax to update the server */
    this.onMove = function(table, currentRow, currentXOffset) {
        // Do nothing for now
    }

    /** This function is called when you start to drag a row, so redefine it in your code
        to do whatever you want, for example use Ajax to update the server */
    this.onDown = function(currentRow) {
        // Do nothing for now
    }

	/* return the row number within 'table' of currentRow */
    this.findRowPosition = function(currentRow) {
        var rows = this.table.tBodies[0].rows;
        for (var i=this.startRow; i<rows.length; i++) {
            if (rows[i].id == currentRow.id)
            	return i;
        }
        return null;
    }
    
	/** Get the position of an element by going up the DOM tree and adding up all the offsets */
    this.getPosition = function(e){
        var left = 0;
        var top  = 0;
		/** Safari fix -- thanks to Luis Chato for this! */
		if (e.offsetHeight == 0) {
			/** Safari 2 doesn't correctly grab the offsetTop of a table row
			    this is detailed here:
			    http://jacob.peargrove.com/blog/2006/technical/table-row-offsettop-bug-in-safari/
			    the solution is likewise noted there, grab the offset of a table cell in the row - the firstChild.
			    note that firefox will return a text node as a first child, so designing a more thorough
			    solution may need to take that into account, for now this seems to work in firefox, safari, ie */
			e = e.firstChild; // a table cell
		}

        while (e.offsetParent){
            left += e.offsetLeft;
            top  += e.offsetTop;
            e     = e.offsetParent;
        }

        left += e.offsetLeft;
        top  += e.offsetTop;

        return {x:left, y:top};
    }
    
    this.setRowsDragMode = function(onoff) {
    	if (!this.table) return;
    	var rows = this.table.tBodies[0].rows; //getElementsByTagName("tr")
        for (var i=this.startRow; i<rows.length; i++) {
        	if (onoff)
            	this.makeDraggable(rows[i]);
            else
            	this.makeUnDraggable(rows[i]);
        }
    }

	/** Get the mouse coordinates from the event (allowing for browser differences) */
    this.mouseCoords = function(ev){
        if(ev.pageX || ev.pageY){
            return {x:ev.pageX, y:ev.pageY};
        }
        return {
            x:ev.clientX + document.body.scrollLeft - document.body.clientLeft,
            y:ev.clientY + document.body.scrollTop  - document.body.clientTop
        };
    }

	/** Given a target element and a mouse event, get the mouse offset from that element.
		To do this we need the element's position and the mouse position */
    this.getMouseOffset = function(target, ev){
        ev = ev || window.event;

        var docPos    = this.getPosition(target);
        var mousePos  = this.mouseCoords(ev);
        return {x:mousePos.x - docPos.x, y:mousePos.y - docPos.y};
    }

	/** Take an item and add an onmousedown method so that we can make it draggable */
    this.makeDraggable = function(item){
        if(!item) return;
        var self = this; // Keep the context of the TableDnd inside the function
        item.onmousedown = function(ev){
            self.dragObject  = this;
            self.mouseOffset = self.getMouseOffset(this, ev);

            /* force starting X position to be same as mouse position, not x offset from 'ev' */
            self.mouseOffset.x = self.lastMouseXpos;
            
			//alert('itemid='+this.id.replace(/[^0-9]/g,''));
			self.onDown(self.dragObject);
            
            return false;
        }
        item.style.cursor = "move";
    }

    this.makeUnDraggable = function(item){
        if(!item) return;
        item.onmousedown = null;
        item.style.cursor = "auto";
    }
    
    /** We're only worried about the y position really, because we can only move rows up and down */
    this.findDropTargetRow = function(y) {
        var rows = this.table.tBodies[0].rows;
        for (var i=this.startRow; i<rows.length; i++) {
            var row = rows[i];
            var rowY    = this.getPosition(row).y;
            var rowHeight = parseInt(row.offsetHeight)/2;
			if (row.offsetHeight == 0) {
				rowY = this.getPosition(row.firstChild).y;
				rowHeight = parseInt(row.firstChild.offsetHeight)/2;
			}
            // Because we always have to insert before, we need to offset the height a bit
            if ((y > rowY - rowHeight) && (y < (rowY + rowHeight))) {
                // that's the row we're over
                return row;
            }
        }
        return null;
    }

    this.findDropTargetLevel = function(x) {
        var rows = this.table.tBodies[0].rows;
        for (var i=this.startRow; i<rows.length; i++) {
            var row = rows[i];
            var rowY    = this.getPosition(row).y;
            var rowHeight = parseInt(row.offsetHeight)/2;
			if (row.offsetHeight == 0) {
				rowY = this.getPosition(row.firstChild).y;
				rowHeight = parseInt(row.firstChild.offsetHeight)/2;
			}
            // Because we always have to insert before, we need to offset the height a bit
            if ((y > rowY - rowHeight) && (y < (rowY + rowHeight))) {
                // that's the row we're over
                return row;
            }
        }
        return null;
    }

}			
function expandCompressContentItem(item_id,show,txtLinkId,txtShow,txtHide,size) {
	if (levelInProgress)return;	/* to prevent a 'row drop' activity from triggering a field edit */
	var elem;
	var txtElem = _getElement(txtLinkId);
	var resize;
	
	if (!size) size = '14px';
	if (!show) show = 'toggle';
	if(show=='show') {
		resize = '';
		_getElement(txtLinkId).innerHTML = txtHide;
	} else if (show=='hide') {
		resize = size;
		_getElement(txtLinkId).innerHTML = txtShow;
	} else if (show=='toggle') {
		var hgt = _getElement('action_item_rowA_'+item_id).style.height;
		resize = (hgt==size?'':size);
		_getElement(txtLinkId).innerHTML = (hgt==size?txtHide:txtShow);
	}
	resizeItemLine(item_id,resize);
}

function resizeItemLine(item_id,resize) {
	_getElement('action_item_rowA_'+item_id).style.height = resize;
	_getElement('action_item_rowB_'+item_id).style.height = resize;
	_getElement('action_item_rowC_'+item_id).style.height = resize;
	_getElement('action_item_rowD_'+item_id).style.height = resize;
	_getElement('action_item_rowE_'+item_id).style.height = resize;
}	

				
				
/* Date/Time Format v0.1
By Steven Levithan <http://stevenlevithan.com>
MIT-style license */
/*
Examples:
	var date = new Date();
	var date1 = date.format("m/dd/yy"); 
	// Returns, e.g., 6/09/07
	var date2 = date.format("Today is dddd, mmmm d, yyyy, at h:MM:ss TT Z"); 
	// Returns, e.g., Today is Saturday, June 9, 2007, at 5:46:21 PM EST

Mask  	Description
d 		Day of the month as digits; no leading zero for single-digit days.
dd 		Day of the month as digits; leading zero for single-digit days.
ddd 	Day of the week as a three-letter abbreviation.
dddd 	Day of the week as its full name.
m 		Month as digits; no leading zero for single-digit months.
mm 		Month as digits; leading zero for single-digit months.
mmm 	Month as a three-letter abbreviation.
mmmm 	Month as its full name.
yy 		Year as last two digits; leading zero for years less than 10.
yyyy 	Year represented by four digits.
h 		Hours; no leading zero for single-digit hours (12-hour clock).
hh 		Hours; leading zero for single-digit hours (12-hour clock).
H 		Hours; no leading zero for single-digit hours (24-hour clock).
HH 		Hours; leading zero for single-digit hours (24-hour clock).
M 		Minutes; no leading zero for single-digit minutes.
		Uppercase M unlike CF timeFormat's lowercase m to avoid conflict with months.
MM 		Minutes; leading zero for single-digit minutes.
		Uppercase MM unlike CF timeFormat's lowercase mm to avoid conflict with months.
s 		Seconds; no leading zero for single-digit seconds.
ss 		Seconds; leading zero for single-digit seconds.
		l or L 	Milliseconds. l gives 3 digits. L gives 2 digits.
tt 		Lowercase time marker string: am or pm.
		No equivalent metasequence in CF.
TT 		Uppercase time marker string: AM or PM.
		Uppercase TT unlike CF timeFormat's lowercase tt to allow for user-specified casing, which is not available in CF.
Z 		Timezone abbreviation; e.g., EST, MDT …
'…' or "…"
		Literal character sequence. Surrounding quotes are removed. Not necessary when using mask characters as part of larger words.
*/
Date.prototype.format = function(mask) {
	var d = this; // Needed for the replace() closure
	
	// If preferred, zeroise() can be moved out of the format() method for performance and reuse purposes
	var zeroize = function (value, length) {
		if (!length) length = 2;
		value = String(value);
		for (var i = 0, zeros = ''; i < (length - value.length); i++) {
			zeros += '0';
		}
		return zeros + value;
	};
	
	return mask.replace(/"[^"]*"|'[^']*'|\b(?:d{1,4}|m{1,4}|yy(?:yy)?|([hHMstT])\1?|[lLZ])\b/g, function($0) {
		switch($0) {
			case 'd':	return d.getDate();
			case 'dd':	return zeroize(d.getDate());
			case 'ddd':	return ['Sun','Mon','Tue','Wed','Thr','Fri','Sat'][d.getDay()];
			case 'dddd':	return ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'][d.getDay()];
			case 'm':	return d.getMonth() + 1;
			case 'mm':	return zeroize(d.getMonth() + 1);
			case 'mmm':	return ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'][d.getMonth()];
			case 'mmmm':	return ['January','February','March','April','May','June','July','August','September','October','November','December'][d.getMonth()];
			case 'yy':	return String(d.getFullYear()).substr(2);
			case 'yyyy':	return d.getFullYear();
			case 'h':	return d.getHours() % 12 || 12;
			case 'hh':	return zeroize(d.getHours() % 12 || 12);
			case 'H':	return d.getHours();
			case 'HH':	return zeroize(d.getHours());
			case 'M':	return d.getMinutes();
			case 'MM':	return zeroize(d.getMinutes());
			case 's':	return d.getSeconds();
			case 'ss':	return zeroize(d.getSeconds());
			case 'l':	return zeroize(d.getMilliseconds(), 3);
			case 'L':	var m = d.getMilliseconds();
					if (m > 99) m = Math.round(m / 10);
					return zeroize(m);
			case 'tt':	return d.getHours() < 12 ? 'am' : 'pm';
			case 'TT':	return d.getHours() < 12 ? 'AM' : 'PM';
			case 'Z':	return d.toUTCString().match(/[A-Z]+$/);
			// Return quoted strings with the surrounding quotes removed
			default:	return $0.substr(1, $0.length - 2);
		}
	});
};


function _getInt(str,i,minlength,maxlength){for(var x=maxlength;x>=minlength;x--){var token=str.substring(i,i+x);if(token.length < minlength){return null;}if(_isInteger(token)){return token;}}return null;}
function _isInteger(val){var digits="1234567890";for(var i=0;i < val.length;i++){if(digits.indexOf(val.charAt(i))==-1){return false;}}return true;}
// ------------------------------------------------------------------
// getDateFromFormat( date_string , format_string )
//
// This function takes a date string and a format string. It matches
// If the date string matches the format string, it returns the 
// getTime() of the date. If it does not match, it returns 0.
// ------------------------------------------------------------------
function getDateFromFormat(val,format) {
	val=val+"";
	format=format+"";
	var i_val=0;
	var i_format=0;
	var c="";
	var token="";
	var token2="";
	var x,y;
	var now=new Date();
	var year=now.getYear();
	var month=now.getMonth()+1;
	var date=1;
	var hh=now.getHours();
	var mm=now.getMinutes();
	var ss=now.getSeconds();
	var ampm="";
	var MONTH_NAMES=new Array('January','February','March','April','May','June','July','August','September','October','November','December','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');var DAY_NAMES=new Array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sun','Mon','Tue','Wed','Thu','Fri','Sat');
	
	while (i_format < format.length) {
		// Get next token from format string
		c=format.charAt(i_format);
		token="";
		while ((format.charAt(i_format)==c) && (i_format < format.length)) {
			token += format.charAt(i_format++);
			}
		// Extract contents of value based on format token
		if (token=="yyyy" || token=="yy" || token=="y") {
			if (token=="yyyy") { x=4;y=4; }
			if (token=="yy")   { x=2;y=2; }
			if (token=="y")    { x=2;y=4; }
			year=_getInt(val,i_val,x,y);
			if (year==null) { return 0; }
			i_val += year.length;
			if (year.length==2) {
				if (year > 70) { year=1900+(year-0); }
				else { year=2000+(year-0); }
				}
			}
		else if (token=="MMM"||token=="NNN"){
			month=0;
			for (var i=0; i<MONTH_NAMES.length; i++) {
				var month_name=MONTH_NAMES[i];
				if (val.substring(i_val,i_val+month_name.length).toLowerCase()==month_name.toLowerCase()) {
					if (token=="MMM"||(token=="NNN"&&i>11)) {
						month=i+1;
						if (month>12) { month -= 12; }
						i_val += month_name.length;
						break;
						}
					}
				}
			if ((month < 1)||(month>12)){return 0;}
			}
		else if (token=="EE"||token=="E"){
			for (var i=0; i<DAY_NAMES.length; i++) {
				var day_name=DAY_NAMES[i];
				if (val.substring(i_val,i_val+day_name.length).toLowerCase()==day_name.toLowerCase()) {
					i_val += day_name.length;
					break;
					}
				}
			}
		else if (token=="MM"||token=="M") {
			month=_getInt(val,i_val,token.length,2);
			if(month==null||(month<1)||(month>12)){return 0;}
			i_val+=month.length;}
		else if (token=="dd"||token=="d") {
			date=_getInt(val,i_val,token.length,2);
			if(date==null||(date<1)||(date>31)){return 0;}
			i_val+=date.length;}
		else if (token=="hh"||token=="h") {
			hh=_getInt(val,i_val,token.length,2);
			if(hh==null||(hh<1)||(hh>12)){return 0;}
			i_val+=hh.length;}
		else if (token=="HH"||token=="H") {
			hh=_getInt(val,i_val,token.length,2);
			if(hh==null||(hh<0)||(hh>23)){return 0;}
			i_val+=hh.length;}
		else if (token=="KK"||token=="K") {
			hh=_getInt(val,i_val,token.length,2);
			if(hh==null||(hh<0)||(hh>11)){return 0;}
			i_val+=hh.length;}
		else if (token=="kk"||token=="k") {
			hh=_getInt(val,i_val,token.length,2);
			if(hh==null||(hh<1)||(hh>24)){return 0;}
			i_val+=hh.length;hh--;}
		else if (token=="mm"||token=="m") {
			mm=_getInt(val,i_val,token.length,2);
			if(mm==null||(mm<0)||(mm>59)){return 0;}
			i_val+=mm.length;}
		else if (token=="ss"||token=="s") {
			ss=_getInt(val,i_val,token.length,2);
			if(ss==null||(ss<0)||(ss>59)){return 0;}
			i_val+=ss.length;}
		else if (token=="a") {
			if (val.substring(i_val,i_val+2).toLowerCase()=="am") {ampm="AM";}
			else if (val.substring(i_val,i_val+2).toLowerCase()=="pm") {ampm="PM";}
			else {return 0;}
			i_val+=2;}
		else {
			if (val.substring(i_val,i_val+token.length)!=token) {return 0;}
			else {i_val+=token.length;}
			}
		}
	// If there are any trailing characters left in the value, it doesn't match
	if (i_val != val.length) { return 0; }
	// Is date valid for month?
	if (month==2) {
		// Check for leap year
		if ( ( (year%4==0)&&(year%100 != 0) ) || (year%400==0) ) { // leap year
			if (date > 29){ return 0; }
			}
		else { if (date > 28) { return 0; } }
		}
	if ((month==4)||(month==6)||(month==9)||(month==11)) {
		if (date > 30) { return 0; }
		}
	// Correct hours value
	if (hh<12 && ampm=="PM") { hh=hh-0+12; }
	else if (hh>11 && ampm=="AM") { hh-=12; }
	var newdate=new Date(year,month-1,date,hh,mm,ss);
	return newdate.getTime();
	}

// ------------------------------------------------------------------
// parseDate( date_string [, prefer_euro_format] )
//
// This function takes a date string and tries to match it to a
// number of possible date formats to get the value. It will try to
// match against the following international formats, in this order:
// y-M-d   MMM d, y   MMM d,y   y-MMM-d   d-MMM-y  MMM d
// M/d/y   M-d-y      M.d.y     MMM-d     M/d      M-d
// d/M/y   d-M-y      d.M.y     d-MMM     d/M      d-M
// A second argument may be passed to instruct the method to search
// for formats like d/M/y (european format) before M/d/y (American).
// Returns a Date object or null if no patterns match.
// ------------------------------------------------------------------
function parseDate(val) {
	var preferEuro=(arguments.length==2)?arguments[1]:false;
	generalFormats=new Array('M/d/y h:mma','M/d/y h:mm a','MM/dd/yyyy hh:mm','MM/dd/yyyy hh:mm a','y-M-d','MMM d, y','MMM d,y','y-MMM-d','d-MMM-y','MMM d');
	monthFirst=new Array('M/d/y','M-d-y','M.d.y','MMM-d','M/d','M-d');
	dateFirst =new Array('d/M/y','d-M-y','d.M.y','d-MMM','d/M','d-M');
	var checkList=new Array('generalFormats',preferEuro?'dateFirst':'monthFirst',preferEuro?'monthFirst':'dateFirst');
	var d=null;
	for (var i=0; i<checkList.length; i++) {
		var l=window[checkList[i]];
		for (var j=0; j<l.length; j++) {
			d=getDateFromFormat(val,l[j]);
			if (d!=0) { return new Date(d); }
			}
		}
	return null;
	}

// ------------------------------------------------------------------
// parseMySqlDate( date_string )
//
// This function takes a date string and tries to convert it to a MySQL db date format 
function parseMySqlDate(val) {
	var newDate = parseDate(val);
	if (newDate)
		return newDate.format("yyyy-mm-dd H:MM");
	else
		return null;
}

