/*==============================================================================
  Created by Peter Mason peter@acpm.info (except where stated otherwise).
  copyright: (C) Copyright 2006 ACPM PTY LTD (ACN: 097 7669 595). All Rights 
  Reserved for all portions of this software created by Peter Mason (ACPM). 
  This source code is protected by copyright law and international treaties.
  Unauthorized reproduction, distrubution or alteration of this source code, 
  or any portion of it, is illegal.
  ==============================================================================
  Synopsys: the purpose of this file is to provide (utility) functions that are 
  commonly used within ACPM-developed HTML pages. 
  NB: ** This code DEPENDS UPON the existence of the following js libraries:
     + jQuery.js + jQuery.tablesorter.js + jQuery.form.js + jQuery.field.js
  ==============================================================================*/
///////////////////////////////////////////////////////////////////////////////
var sitePath='./';
///////////////////////////////////////////////////////////////////////////////
// WINDOW-RELATED SECTION: The following functions are used to manage windows.
///////////////////////////////////////////////////////////////////////////////
var sW=screen.width; var sH=screen.height;
var wW, wH, wX, wY, urlPop, wLoading, wT, wCopyright, wTerms, wHelp;
var wList_Misc = new Array();
function closeAllPops() {
	if( wCopyright != null && typeof wCopyright.close != 'undefined' ) wCopyright.close();
	if( wTerms != null && typeof wTerms.close != 'undefined' ) wTerms.close();
	if( wHelp != null && typeof wHelp.close != 'undefined' ) wHelp.close();
	if( wList_Misc.length > 0) for(var i in wList_Misc) 
		if( wList_Misc[i] != null && typeof wList_Misc[i].close != 'undefined' ) wList_Misc[i].close();
}
function getWinCoord(winObj,which) {
//  Allocate a number to winType var according to which reference format is required.
	if (typeof winObj == 'undefined' || !winObj) return -1;
	if (typeof which != 'string') return -1;
	var X = which.substr(0,1).toUpperCase(); // normalize to just the first char.
	var wType = (typeof self.screenLeft != 'undefined')? 2: (typeof self.screenX != 'undefined')? 1:0; // 2=(IE 5+/Windows); 1=(Navigator 4+); 0=others
	if (wType==2) var docObj = (document.compatMode && document.compatMode != "BackCompat")? winObj.document.body.parentElement: winObj.document.body;
	var coordV = -1;
	if (X=='L') coordV = (wType==2? winObj.screenLeft: wType==1? winObj.screenX: winObj.left);
	else if (X=='T') coordV = (wType==2? winObj.screenTop: wType==1? winObj.screenY: winObj.top);
	else if (X=='W') {
		if (winObj.outerWidth) coordV = winObj.outerWidth;
		else if (winObj.document && winObj.document.clientWidth) coordV = winObj.document.clientWidth;
		else if (winObj.document.body && winObj.document.body.clientWidth) coordV = winObj.document.body.clientWidth;
		else if (winObj.document.documentElement && winObj.document.documentElement.clientWidth) coordV = winObj.document.documentElement.clientWidth;
		else coordV = winObj.width;
	} else if (X=='H') {
		if (winObj.outerHeight) coordV = winObj.outerHeight;
		else if (winObj.document && winObj.document.clientHeight) coordV = winObj.document.clientHeight;
		else if (winObj.document.body && winObj.document.body.clientHeight) coordV = winObj.document.body.clientHeight;
		else if (winObj.document.documentElement && winObj.document.documentElement.clientHeight) coordV = winObj.document.documentElement.clientHeight;
		else coordV = winObj.height;
	}
	return (Math.max(0,coordV));
}
function getDocHeight(docObj) {
	var docH = 0, sh, oh;
	if (docObj.height) {
		docH = docObj.height;
	} else if (docObj.body) {
		if (docObj.body.scrollHeight) docH = sh = docObj.body.scrollHeight;
		if (docObj.body.offsetHeight) docH = oh = docObj.body.offsetHeight;
		if (sh && oh) docH = Math.max(sh, oh);
	}
	return docH;
}
function getDocWidth(docObj) {
	var docW = 0, sw, ow;
	if (docObj.Width) {
		docW = docObj.Width;
	} else if (docObj.body) {
		if (docObj.body.scrollWidth) docW = sw = docObj.body.scrollWidth;
		if (docObj.body.offsetWidth) docW = ow = docObj.body.offsetWidth;
		if (sw && ow) docW = Math.max(sw, ow);
	}
	return docW;
}
function endSession() {
	closeAllPops();
	if(typeof preEndSessionProc != 'undefined') preEndSessionProc();
	loadFXContent('/FX/fEndSession.php','yes','yes');
}
function checkProgress_wLoading() {
	if (typeof wLoading.loadFXContent != 'undefined') {
		if (wLoading.setupTimeout) wLoading.clearTimeout(setupTimeout);
		setTimeout("wLoading.loadFXContent(urlPop,'yes','no')", 150);
	} else setTimeout('checkProgress_wLoading()', 250);
}
function loadPopURLwProgress(winObj) {
	if( typeof urlPop != 'undefined' && winObj && !winObj.closed ) {
		if (typeof winObj.loadFXContent != 'undefined') {
			winObj.loadFXContent(urlPop,'yes','no');
		} else {
			var msgHTML = getProgressMsgHTML('start');
			var docHTML = "<html><head>";
			docHTML += "<title>Waiting for Remote Server</title>";
			docHTML += "<link rel=\"stylesheet\" href=\"/FX/f_Styles.css\" type=\"text/css\" title=\"fxStyles\"/>";
			docHTML += "<script type=\"text/javascript\">";
			docHTML += "if (document.images) {var loadingImg = new Image();loadingImg.src = '"+loadingImgSrc+"';}";
			docHTML += "</script>";
			docHTML += "</script>";
			docHTML += "</head><body>";
			docHTML += msgHTML;
			docHTML += "</body></html>";
			winObj.document.write(docHTML);
			winObj.document.close();
			docRef = getDocRef(winObj);
			docRef.location.href=urlPop;
		}
		urlPop = null;
	}
}
function openMiscPopWin(urlStr,isNoProg,wW,wH) {
	if (typeof urlStr != 'string' || urlStr == '') return;
	if(!wW) wW = Math.min(800,getWinCoord(top,'width')); //NB: keep window's width close to A4 page width.
	if(!wH) wH = getWinCoord(top,'height');
	var size = "width="+wW+","+"height="+wH;
	// NB: previous is still required, as prefix of below, for browsers that don't support 'outer' feature within 'open()'.
	if (window.outerHeight) size += ",outerWidth="+wW+","+"outerHeight="+wH;
	size += ',top=0';
	var i = wList_Misc.length;
	var wT = (this.name)? this.name+'_':''; //NB: this is necessary to keep window names unique when opening pop-ups from existing pop-up windows.
	wT += 'LIST_'+i;
	wList_Misc[i] = window.open("",wT,"dependent=yes,status=yes,scrollbars=yes,fullscreen=no,resizable=yes,"+size+"\"");
	if (isNoProg) {
		docRef = getDocRef(wList_Misc[i]);
		docRef.location.href=urlStr;
	} else {
		urlPop = urlStr;
		loadPopURLwProgress(wList_Misc[i]);
	}
	if (self.screenX) wList_Misc[i].moveTo(getWinCoord(wList_Misc[i],'left'),0); //because feature 'top' is ignored in above for this
	return (wList_Misc[i]);
}
function open_Help(urlPop) {
	if (!urlPop) urlPop = sitePath+"help/";
	if( wHelp == null || wHelp.closed || (wHelp.opener != self) ) { //NB: opener has to be self because values passed back to opener.
		var wW = 700;
		var wH = Math.min((sH-30),700);
		var wT = (this.name)? this.name+'_':''; //NB: this is necessary to keep window names unique when opening pop-ups from existing pop-up windows.
		wT += "wHelp";
		var size = "width="+wW+","+"height="+wH;
		if (window.outerHeight) size += ",outerWidth="+wW+","+"outerHeight="+wH;
		size += ',top=0';
		wHelp = window.open(urlPop,wT,"dependent=yes,status=yes,scrollbars=yes,fullscreen=no,resizable=yes,"+size+"\"");
		loadPopURLwProgress(wHelp);
	} else {
	//  NB: don't reload this window's content.
		if (wHelp.location != urlPop) wHelp.location = urlPop;
		if (wHelp.focus) wHelp.focus();
	}
}
function openTerms() {
	if( wTerms == null || wTerms.closed ) {
		var wW = 700;
		var wH = 700;
		var wT = (this.name)? this.name+'_':''; //NB: this is necessary to keep window names unique when opening pop-ups from existing pop-up windows.
		wT += "Terms_of_Business";
		var urlPop = baseURL+"pop_Terms";
		var size = "width="+wW+","+"height="+wH;
		if (window.outerHeight) size += ",outerWidth="+wW+","+"outerHeight="+wH;
		size += ',top=0';
		wTerms = window.open(urlPop,wT,"dependent=yes,status=yes,scrollbars=no,fullscreen=no,resizable=yes,"+size+"\"");
	} else {
		if (wTerms.focus) wTerms.focus();
	}
}
function openCopyright() {
	if( wCopyright == null || wCopyright.closed ) {
//		var wX = 40;
//		var wY = 0;
//		var size = "top="+wY+","+"left="+wX+","+"width="+wW+","+"height="+wH;
		var wW = 700;
		var wH = 300;
		var wT = (this.name)? this.name+'_':''; //NB: this is necessary to keep window names unique when opening pop-ups from existing pop-up windows.
		wT += "Copyright_Notice";
		var urlPop = baseURL+"pop_Copyright";
		var size = "width="+wW+","+"height="+wH;
		if (window.outerHeight) size += ",outerWidth="+wW+","+"outerHeight="+wH;
		size += ',top=0';
		wCopyright = window.open(urlPop,wT,"dependent=yes,status=no,scrollbars=yes,fullscreen=no,resizable=yes,"+size+"\"");
	} else {
		if (wCopyright.focus) wCopyright.focus();
	}
}

/*==============================================================================*/
// NB: The following have been extracted from the 'dateparse.js' file but has 
// some modification by Peter Mason. The dateparse.js file owner details are:
// Created by: Simon Willison - http://simon.incutio.com
// Website: http://datebox.inimit.com
// License: GNU Lesser General Public License version 2.1 or above
/////////////////////////////////////////////////////////////////////////////////////
var configDateType = 'aus'; // Configuration options: Available date types (us|aus|iso)
var configAutoRollOver = false; // Dates such as 29/2/2005 to rollover to 1/3/2005
//////////////////////////////////////////////////////////////////
function keyListener(e) {
	if(!e) e = (window.event)? window.event:null; // for IE
	switch (e.keyCode) {
		case 10: // return
		case 13: // enter
			// perform the update
			magicDate('dateField');
			return false;
		default:
			return true;
	}
}
switch (configDateType) {
	case 'us':
		var calendarIfFormat = '%m/%d/%Y';
		var calendarFormatString = 'mm/dd/yyyy';
		break;
	case 'aus':
		var calendarIfFormat = '%d/%m/%Y';
		var calendarFormatString = 'dd/mm/yyyy';
		break;
	case 'iso':
	default:
		var calendarIfFormat = '%Y-%m-%d';
		var calendarFormatString = 'yyyy-mm-dd';
		break;
}
// arrays for month and weekday names
var monthNames = "January February March April May June July August September October November December".split(" ");
var weekdayNames = "Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" ");
/* Takes a string, returns the index of the month matching that string, throws
   an error if 0 or more than 1 matches. */
function parseMonth(month) {
	var matches = monthNames.filter(function(item) { 
		return new RegExp("^" + month, "i").test(item);
	});
	if (matches.length == 0) {
		throw new Error("Invalid month string");
	}
	if (matches.length < 1) {
		throw new Error("Ambiguous month");
	}
	return monthNames.indexOf(matches[0]);
}
/* Same as parseMonth but for days of the week */
function parseWeekday(weekday) {
	var matches = weekdayNames.filter(function(item) {
		return new RegExp("^" + weekday, "i").test(item);
	});
	if (matches.length == 0) {
		throw new Error("Invalid day string");
	}
	if (matches.length < 1) {
		throw new Error("Ambiguous weekday");
	}
	return weekdayNames.indexOf(matches[0]);
}
function DateInRange( yyyy, mm, dd ) {
//  if month out of range
	if ( mm < 0 || mm > 11 )
		throw new Error('Invalid month value.  Valid months values are 1 to 12');
	if (!configAutoRollOver) {
	//  get last day in month
	 	var d = (11 == mm) ? new Date(yyyy + 1, 0, 0) : new Date(yyyy, mm + 1, 0);
	//  if date out of range
		if ( dd < 1 || dd > d.getDate() )
			throw new Error('Invalid date value.  Valid date values for ' + monthNames[mm] + ' are 1 to ' + d.getDate().toString());
	}
	return true;
}
function getDateObj(yyyy, mm, dd) {
	var obj = new Date();
	obj.setDate(1); //NB: MUST set date to first day for when month is set!!! Because if today's date is a day greater than the last day of mm then will error!
	obj.setYear(yyyy);
	obj.setMonth(mm);
	obj.setDate(dd); //NB: MUST set date AFTER the month!!! Because if today's date is a month that doesn't have ≥ the dd value then will error!
	return obj;
}
/* Array of objects, each has 're', a regular expression and 'handler', a 
   function for creating a date from something that matches the regular 
   expression. Handlers may throw errors if string is unparseable. */
var dateParsePatterns = [
	// Today
	{   re: /^tod/i,
		handler: function() {
			return new Date();} 
	},
	// Tomorrow
	{   re: /^tom/i,
		handler: function() {
			var d = new Date(); 
			d.setDate(d.getDate() + 1); 
			return d;
		}
	},
	// Yesterday
	{   re: /^yes/i,
		handler: function() {
			var d = new Date();
			d.setDate(d.getDate() - 1);
			return d;
		}
	},
	// 4th
	{   re: /^(\d{1,2})(st|nd|rd|th)?$/i, 
		handler: function(bits) {
			var d = new Date();
			var yyyy = d.getFullYear();
			var dd = parseInt(bits[1], 10);
			var mm = d.getMonth();
			if ( DateInRange( yyyy, mm, dd ) )
			 	return getDateObj(yyyy, mm, dd);
		}
	},
	// 4th Jan
	{   re: /^(\d{1,2})(?:st|nd|rd|th)? (?:of )?(\w+)$/i, 
		handler: function(bits) {
			var d = new Date();
			var yyyy = d.getFullYear();
			var dd = parseInt(bits[1], 10);
			var mm = parseMonth(bits[2]);
			if ( DateInRange( yyyy, mm, dd ) )
				return getDateObj(yyyy, mm, dd);
		}
	},
	// 4th Jan 2003
	{   re: /^(\d{1,2})(?:st|nd|rd|th)? (?:of )?(\w+),? (\d{4})$/i,
		handler: function(bits) {
			var d = new Date();
			d.setDate(parseInt(bits[1], 10));
			d.setMonth(parseMonth(bits[2]));
			d.setYear(bits[3]);
			return d;
		}
	},
	// Jan 4th
	{   re: /^(\w+) (\d{1,2})(?:st|nd|rd|th)?$/i, 
		handler: function(bits) {
			var d = new Date();
			var yyyy = d.getFullYear(); 
			var dd = parseInt(bits[2], 10);
			var mm = parseMonth(bits[1]);
			if ( DateInRange( yyyy, mm, dd ) )
				return getDateObj(yyyy, mm, dd);
		}
	},
	// Jan 4th 2003
	{   re: /^(\w+) (\d{1,2})(?:st|nd|rd|th)?,? (\d{4})$/i,
		handler: function(bits) {
			var yyyy = parseInt(bits[3], 10); 
			var dd = parseInt(bits[2], 10);
			var mm = parseMonth(bits[1]);
			if ( DateInRange( yyyy, mm, dd ) )
				return getDateObj(yyyy, mm, dd);
		}
	},
	// next Tuesday - this is suspect due to weird meaning of "next"
	{   re: /^next (\w+)$/i,
		handler: function(bits) {
			var d = new Date();
			var day = d.getDay();
			var newDay = parseWeekday(bits[1]);
			var addDays = newDay - day;
			if (newDay <= day) {
				addDays += 7;
			}
			d.setDate(d.getDate() + addDays);
			return d;
		}
	},
	// last Tuesday
	{   re: /^last (\w+)$/i,
		handler: function(bits) {
			var d = new Date();
			var wd = d.getDay();
			var nwd = parseWeekday(bits[1]);
			// determine the number of days to subtract to get last weekday
			var addDays = (-1 * (wd + 7 - nwd)) % 7;
			// above calculate 0 if weekdays are the same so we have to change this to 7
			if (0 == addDays)
				addDays = -7;
			// adjust date and return
			d.setDate(d.getDate() + addDays);
			return d;
		}
	},
	// mm/dd/yyyy
	{   re: /(\d{1,2})\/(\d{1,2})\/(\d{4})/,
		handler: function(bits) {
			var yyyy = parseInt(bits[3], 10);
			var mm = (configDateType == 'us')? parseInt(bits[1], 10) - 1: parseInt(bits[2], 10) - 1;
			var dd = (configDateType == 'us')? parseInt(bits[2], 10): parseInt(bits[1], 10);
			if ( DateInRange( yyyy, mm, dd ) )
				return getDateObj(yyyy, mm, dd);
		}
	},
	// mm/dd/yy short year
	{   re: /(\d{1,2})\/(\d{1,2})\/(\d{1,2})/,
		handler: function(bits) {
			var d = new Date();
			var yyyy = d.getFullYear() - (d.getFullYear() % 100) + parseInt(bits[3], 10);
			var mm = (configDateType == 'us')? parseInt(bits[1], 10) - 1: parseInt(bits[2], 10) - 1;
			var dd = (configDateType == 'us')? parseInt(bits[2], 10): parseInt(bits[1], 10);
			if ( DateInRange(yyyy, mm, dd) )
				return getDateObj(yyyy, mm, dd);
		}
	},
	// mm/dd omitted year
	{   re: /(\d{1,2})\/(\d{1,2})/,
		handler: function(bits) {
			var d = new Date();
			var yyyy = d.getFullYear();
			var mm = (configDateType == 'us')? parseInt(bits[1], 10) - 1: parseInt(bits[2], 10) - 1;
			var dd = (configDateType == 'us')? parseInt(bits[2], 10): parseInt(bits[1], 10);
			if ( DateInRange(yyyy, mm, dd) )
				return getDateObj(yyyy, mm, dd);
		}
	},
	// yyyy-mm-dd (ISO style)
	{   re: /(\d{4})-(\d{1,2})-(\d{1,2})/,
		handler: function(bits) {
			var yyyy = parseInt(bits[1], 10);
			var dd = parseInt(bits[3], 10);
			var mm = parseInt(bits[2], 10) - 1;
			if ( DateInRange( yyyy, mm, dd ) )
				return getDateObj(yyyy, mm, dd);
		}
	},
	// yy-mm-dd (ISO style) short year
	{   re: /(\d{1,2})-(\d{1,2})-(\d{1,2})/,
		handler: function(bits) {
			var d = new Date();
			var yyyy = d.getFullYear() - (d.getFullYear() % 100) + parseInt(bits[1], 10);
			var dd = parseInt(bits[3], 10);
			var mm = parseInt(bits[2], 10) - 1;
			if ( DateInRange( yyyy, mm, dd ) )
				return getDateObj(yyyy, mm, dd);
		}
	},
	// mm-dd (ISO style) omitted year
	{   re: /(\d{1,2})-(\d{1,2})/,
		handler: function(bits) {
			var d = new Date();
			var yyyy = d.getFullYear();
			var dd = parseInt(bits[2], 10);
			var mm = parseInt(bits[1], 10) - 1;
			if ( DateInRange( yyyy, mm, dd ) )
				return getDateObj(yyyy, mm, dd);
		}
	},
];
function parseDateString(s) {
	for (var i = 0; i < dateParsePatterns.length; i++) {
		var re = dateParsePatterns[i].re;
		var handler = dateParsePatterns[i].handler;
		var bits = re.exec(s);
		if (bits) {
			return handler(bits);
		}
	}
	throw new Error("Invalid date string");
}
function magicDate(elObj,dateType) {
	if(!dateType) dateType=configDateType;
	 try {
		var re = /\./g;
		var d = parseDateString(elObj.value.replace(re,'/'));
		switch (dateType) {
			case 'us':
				elObj.value = (d.getMonth() + 1) + '/' + d.getDate() + '/' + d.getFullYear();
				break;
			case 'aus':
				elObj.value = d.getDate() + '/' + (d.getMonth() + 1) + '/' + d.getFullYear();
				break;
			case 'iso':
			default:
				elObj.value = d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate();
				break;
		}
	}
	catch (e) {
		var message = e.message;
		// Fix for IE6 bug
		if (message.indexOf('is null or not an object') > -1) {
			message = 'Invalid date string';
		}
		alert(message);
	}
}
// END of Date/Calendar-related Section.
/*==============================================================================*/

