var is_IE = navigator.userAgent.toLowerCase().indexOf("msie") != -1;
var useAJAXSuburbs = false;
var FieldTypes = new Object();
var ValidationMap = new Object();
var FieldNames = new Object();
var HelpMap = new Object();
var SuburbMap = new Object();  // Add CPostcode objects
var Events = undefined; // The old Event model should not be used with the new one

var CurrentSuburb;
var SuburbList;
var CanCloseSuburb = false;
var setTabIndexes = true;  // Change this in custom.js. This sets whether InitFields controls the tab order, or the HTML document flow.


ValidationMap.Date = ValidateDate;
ValidationMap.Suburb = ValidateSuburbField;
ValidationMap.Time = ValidateTime;
ValidationMap.Time24 = ValidateTime24;
ValidationMap.TimeSplit = ValidateTimeSplit;
ValidationMap.Money = function(field) { return ValidateCurrency(field,1); };
ValidationMap.Float = function(field) { return ValidateFloat(field.value); };
ValidationMap.Integer = function(field) { return ValidateInt(field.value); };
ValidationMap.ABN = function(field) { return ValidateABN(field.value); };
ValidationMap.DateTime = ValidateDateTime;
ValidationMap.Phone = function (field) { return ValidatePhone(field.value); };

function InitFields()
{
	useAJAXSuburbs = !is_IE;
	
	var form;
	if (is_IE)
		form = document.forms(0);
	else
		form = document.forms[0];
	var fields = form.elements;
	for (var i = 0; i < fields.length; i++)
	{
		var field = fields[i];
		if (field.nodeName == 'INPUT')
		{
			if (field.type == "text")
				AttachFieldEvent(field,"change",OnFieldChange);
			else
				AttachFieldEvent(field,"click",OnFieldChange);
			AttachFieldEvent(field,"focus",OnFieldFocus);
			var className = field.className.split(' ');
			FieldTypes[field.id] = className[0];
		}
		else if ((field.nodeName == 'TEXTAREA') || (field.nodeName == 'SELECT'))
		{
			AttachFieldEvent(field,"change",OnFieldChange);
			AttachFieldEvent(field,"focus",OnFieldFocus);
		}
		// Move the field to the front of the tab order ahead of the navigation menu
		if (setTabIndexes && field.tabIndex == 0) // leave negative tab indexes out of tab order
			field.tabIndex = i+1;
		if ((field.disabled || (field.readOnly != undefined && field.readOnly)) && (field.nodeName == 'INPUT' || field.nodeName == 'SELECT' || field.nodeName == 'TEXTAREA'))
			EnableField(field, false, false);			
	}
	
	var labels = document.getElementsByTagName('LABEL');
	for (var i = 0; i < labels.length; i++)
	{
		labels[i].id = labels[i].htmlFor + ':label';
		var name = labels[i].innerText || labels[i].textContent; //innerText isn't W3C
		if (name.length > 0 && name.charAt(name.length-1) == ':')
		{
			name = name.substr(0,name.length-1);
		}
		FieldNames[labels[i].htmlFor] = name;
		
	}

	for (var i = 0; i < ErrorMessages.length; i++)
	{
		var id = ErrorMessages[i].id;
		if (id != undefined && id.length > 0)
		{
			var label = document.getElementById(id + ':label');
			if (label != undefined)
				label.style.color = 'red';
			else
			{
				var field = document.getElementById(id);
				if (field != undefined)
					field.style.borderColor = 'red';
			}
		}
	}
	
	for (var i = 0; i < ErrorMessages.length; i++)
	{
		var msg = ErrorMessages[i].msg;
		var id = ErrorMessages[i].id;
		if (msg != undefined && msg.length > 0)
		{
			if (id != undefined && id.length > 0 && msg.indexOf("<name>") >= 0)
				msg = msg.replace("<name>",FieldNames[ErrorMessages[i].id]);
			alert(msg);
		}
	}
	
	
	if(!setTabIndexes) // Tab indexes have not been set, so skip the nav links by setting focus on the first form element
	{
		for(var i=0; i< fields.length; i++)
		{
			if(fields[i].type != 'hidden' && fields[i].disabled != true && fields[i].tabIndex >= 0)
			{
				// This try-catch statement is to handle the situation when the current element is nested
				// somewhere within a hidden element... Yup, it's dodgy...
				try
				{
					fields[i].focus(); 
					break;
				}
				catch(e)
				{
					continue;
				}
			}
		}
	}
}

function AttachFieldEvent(field, eventtype, handler)
{
	var origField = field;
	if (field.constructor == String)
	{
		field = document.getElementById(field);
		if (!field)
		{
			alert("ERROR: Can't attached event to missing field "+origField);
			return;
		}			
	}
	if (is_IE)
		field.attachEvent("on" + eventtype, handler);
	else
		field.addEventListener(eventtype, handler, false);
}

function GetSender(e, f)
{
	if (e == undefined)
		e = window.event;
	var field = e.srcElement;
	if (field == undefined)
		field = f;
	return field;
}

function OnFieldChange(e)
{
	if (e == undefined)
		e = window.event;
	var field = e.srcElement;
	if (field == undefined)
		field = this;
	var bValid = ValidateField(field);
	if (!bValid)
	{
		if (e.preventDefault == undefined)
			e.returnValue = false;
		else
			e.preventDefault();
	}
	return bValid;
}

function OnFieldFocus(e)
{
	if (e == undefined)
		e = window.event;
	var field = e.srcElement;
	if (field == undefined)
		field = this;
	var helpid = HelpMap[field.id];
	if (helpid != undefined)
	{
		ShowInfo(helpid);
	}
}

function EnableField(field, enable, clear, mandatory)
{		
	if (field.constructor == String)
		field = document.getElementById(field);
		
	var bMandatoryClass = false;
	if (mandatory != undefined)
		bMandatoryClass = mandatory;
    else if (field.className.indexOf('Mandatory') != -1) //If parameter left off, preserve mandatory state
        bMandatoryClass = true;

	if (field.type == 'text' || field.nodeName == 'SELECT' || field.nodeName == 'TEXTAREA')
	{
		if (enable)
		{
			var type = FieldTypes[field.id];
			if (type == undefined)
				type = 'Freetext';
			if (bMandatoryClass)
				type += ' Mandatory';
			field.className = type;
		}
		else
		{
		    var type = (field.nodeName != 'TEXTAREA') ? 'DisabledField' : 'DisabledText';
		    if (bMandatoryClass)
				type += ' Mandatory';
			field.className = type;
        }
	}
	if ((field.nodeName == 'INPUT' && (field.type == 'text' || field.type == 'password')) || (field.nodeName == 'TEXTAREA'))
	{
		field.readOnly = !enable;
		var className = field.className.split(' ');
		if(className[0] == 'Date' || className[0] == 'DisabledField')
		{
		    var calCont = document.getElementById(field.id + 'CAL');
		    if(calCont != undefined)
		       calCont.style.display =  enable? '' : 'none';
		}
    }
	else
		field.disabled = !enable;
	if (clear == undefined || clear)
	{
		if (field.nodeName == 'SELECT')
			field.selectedIndex = -1;
		else if (field.nodeName == 'TEXTAREA')
		{
			if (is_IE)
				field.innerText  = "";
			else
				field.textContent = "";
		}
		else if (field.nodeName == 'INPUT' && (field.type == 'radio' || field.type == 'checkbox'))
			field.checked = false;
		else
			field.value = "";
	}
	if (setTabIndexes)
	{
		if ((enable && field.tabIndex < 0) || (!enable && field.tabIndex > 0))
			field.tabIndex = -field.tabIndex;
	}
	else
	{
		if (!enable && field.tabIndex == 0)
			field.tabIndex = -1;
		else if (enable && field.tabIndex == -1)
			field.tabIndex = 0;
	}
}

function EnableFieldsInGroup(groupid, enable, clear)
{
	var group = document.getElementById(groupid);
	var controls = group.getElementsByTagName('INPUT');
	for (var i = 0; i < controls.length; i++)
		EnableField(controls[i], enable, clear);
	controls = group.getElementsByTagName('SELECT');
	for (var i = 0; i < controls.length; i++)
		EnableField(controls[i], enable, clear);
	controls = group.getElementsByTagName('TEXTAREA');
	for (var i = 0; i < controls.length; i++)
		EnableField(controls[i], enable, clear);
	controls = group.getElementsByTagName('A');
	for (var i = 0; i < controls.length; i++)
		EnableField(controls[i], enable, clear);
}

function SetFieldValue(field, value)
{
	if (field.constructor == String)
		field = document.getElementById(field);
	if (field.nodeName == 'SELECT')
	{
		field.selectedIndex = -1;
		for (var i = 0; i < field.options.length; i++)
		{
			if (field.options[i].value == value)
			{
				field.selectedIndex = i;
				return;
			}
		}
	}
	else if (field.nodeName == 'INPUT' && (field.type == 'radio' || field.type == 'checkbox'))
		field.checked = value;
	else
		field.value = value;
}

function GetFieldValue(field)
{
	if (field.constructor == String)
		field = document.getElementById(field);
	if (field.nodeName == 'SELECT')
	{
		if (field.selectedIndex >= 0)
			return field.options[field.selectedIndex].value;
		else
			return "";
	}
	else if (field.nodeName == 'INPUT' && (field.type == 'radio' || field.type == 'checkbox'))
		return field.checked;
	else
		return field.value;
}

function CheckTextLength(e, field, length)
{
	if (e == undefined)
		e = window.event;
	if (field.value.length >= length && e.keyCode != 8 && e.keyCode != 127)
	{
		if (e.preventDefault == undefined)
		{
			e.returnValue = false;
			field.value = field.value.substr(0,length);
		}
		else
			field.value = field.value.substr(0,length-1);
		
		return false;
	}
	return true;
}

function CheckTextCount(e, field, maxlimit)
{
	var str = field.value;
	var str2;
	str = str.replace(/\r/g,'');
	var length = str.length;
	var upperlimit = maxlimit+10000;
	if(length>upperlimit)//upper limit reached.. taking steps to avoid system instability
	{
		alert('Far too many characters were entered in this field. It will be shortened.');	
		field.value = field.value.substring(0,maxlimit); 
		return false;
	}
	if (length  > maxlimit)
	{
		alert('Too many characters were entered in this field. The limit is '+maxlimit+' and you have entered '+length+' characters. Only the first '+maxlimit+' characters will be saved.');	
		return false;
	}
	
	return true;
}

function RemoveAllCodes(field)
{
	if (field.constructor == String)
		field = document.getElementById(field);
	while(field.options.length > 0)
		field.removeChild(field.options[0]);
}

var ErrorHeaderText = "An error occurred while requesting data from the server.  The details of the error are shown below:\n\n";

function PopulateCodes(field, codetype, aggregate, AssociateType, AssociateValue, sortmode, activeonly)
{
	if (field.constructor == String)
		field = document.getElementById(field);
	RemoveAllCodes(field);
	if ((aggregate != undefined && aggregate == "") || (AssociateValue != undefined && AssociateValue == ""))
		return 0;

	var url = 'codes.asp?codetype=' + codetype;
	if (aggregate != undefined && aggregate != '')
		url += '&aggregate=' + aggregate;
	if (AssociateType != undefined && AssociateType != '')
		url += '&AssociateType=' + AssociateType;
	if (AssociateValue != undefined && AssociateValue != '')
		url += '&AssociateValue=' + AssociateValue;
	if (sortmode != undefined && sortmode != '')
		url += '&sortmode=' + sortmode;
	if (activeonly != undefined && activeonly != '')
		url += '&activeonly=' + activeonly;

	var req = NewXMLHttpRequest();
	req.open('GET',url,false);
	req.send(null);
	if (req.status != 200)
	{
		alert(ErrorHeaderText + 'Date/Time: ' + new Date() + '\nHTTP status = ' + req.status + '\nError: ' + req.statusText + '\nURL: ' + url);
		return 0;
	}
	if (req.responseText.substring(0,6) == "Error:")
	{
		alert(ErrorHeaderText + req.responseText);
		return 0;
	}
	
	var option = document.createElement("OPTION");
	option.text = "";
	option.value = "";
	if (is_IE)
		field.options.add(option);
	else
		field.appendChild(option);

	var count = 0;
	var xml = req.responseXML;
	var child = xml.documentElement.firstChild;
	for (var child = xml.documentElement.firstChild; child != null; child = child.nextSibling)
	{
		if (child.nodeType==1) // Element
		{
			var option = document.createElement("OPTION");
			option.text = child.firstChild.nodeValue;
			option.value = child.getAttribute('value');
			if (is_IE)
				field.options.add(option);
			else
				field.appendChild(option);
			count++;
		}
	}	
	//alert(req.responseXML.xml);
	return count;
}

function PopulateQuery(field, query, id, querystring)
{
	if (field.constructor == String)
		field = document.getElementById(field);
	RemoveAllCodes(field);

	var url = 'dbcombo.asp?query=' + query + '&id=' + id;
	if (querystring != undefined && querystring != '')
		url += '&' + querystring;
	var req = NewXMLHttpRequest();
	req.open('GET',url,false);
	req.send(null);
	if (req.status != 200)
	{
		alert(ErrorHeaderText + 'Date/Time: ' + new Date() + '\nHTTP status = ' + req.status + '\nError: ' + req.statusText + '\nURL: ' + url);
		return 0;
	}
	if (req.responseText.substring(0,6) == "Error:")
	{
		alert(ErrorHeaderText + req.responseText);
		return 0;
	}
	
	var option = document.createElement("OPTION");
	option.text = "";
	option.value = "";
	if (is_IE)
		field.options.add(option);
	else
		field.appendChild(option);

	var count = 0;
	var xml = req.responseXML;
	var child = xml.documentElement.firstChild;
	for (var child = xml.documentElement.firstChild; child != null; child = child.nextSibling)
	{
		if (child.nodeType==1) // Element
		{
			var option = document.createElement("OPTION");
			option.text = child.firstChild.nodeValue;
			option.value = child.getAttribute('value');
			if (is_IE)
				field.options.add(option);
			else
				field.appendChild(option);
			count++;
		}
	}	

	return count;
}

function RequestXML(url)
{
	var req = NewXMLHttpRequest();
	req.open('GET',url,false);
	req.send(null);
	if (req.status != 200)
	{
		alert(ErrorHeaderText + 'Date/Time: ' + new Date() + '\nHTTP status = ' + req.status + '\nError: ' + req.statusText + '\nURL: ' + url);
		return 0;
	}
	if (req.responseText.substring(0,6) == "Error:")
	{
		alert(ErrorHeaderText + req.responseText);
		return 0;
	}
	
	return req.responseXML;
}

function AggregateCodes(destination, source, codetype, assoctype)
{
	if (destination.constructor == String)
		destination = document.getElementById(destination);
	if (source.constructor == String)
		source = document.getElementById(source);
	var code = "";
	if (source.selectedIndex >= 0)
		code = source.options[source.selectedIndex].value;
	PopulateCodes(destination, codetype, code, assoctype);
}

function CSuburb(suburb, state, postcode)
{
	this.suburb = suburb;
	this.state = state;
	this.postcode = postcode;
}

function CPostcode(state, postcode)
{
	this.state = state;
	this.postcode = postcode;
}

function ValidateField(field)
{
	var className = field.className.split(' ');
	var validator = ValidationMap[className[0]];
	if (validator != undefined && (field.value.length > 0 || className[0] == 'Suburb'))
		return validator(field);
	return true;
}

function ValidateSuburbField(field)
{
	if (is_IE && !useAJAXSuburbs)
		return ValidateSuburb(field.id + '|' + SuburbMap[field.id].state + '|' + SuburbMap[field.id].postcode, field);
	CurrentSuburb = field;
	var value = field.value.toUpperCase();
	value = value.replace(/%/g,'%25');
	if(value == '')
	{
		//wipe state and suburb
		TabToNextField(field);
		var postcode = SuburbMap[field.id];
		if (postcode != null)
		{
			var st = document.getElementById(postcode.state);
			var pc = document.getElementById(postcode.postcode);
			if (st != undefined)
			{
				if(st.length != undefined)
				{
					for (var i = 0; i < st.length; i++)
						SetFieldValue(st[i], '');
				}
				else
					SetFieldValue(st, '');
				if (is_IE)
				    st.fireEvent('onchange');
				else
				{
				    var changeEvent = window.document.createEvent("HTMLEvents");
				    changeEvent.initEvent("change", false, true);
				    st.dispatchEvent(changeEvent);
                }
			}
			if (pc != undefined)
			{
				if(pc.length != undefined)
				{
					for (var i = 0; i < pc.length; i++)
						SetFieldValue(pc[i], '');
				}
				else
					SetFieldValue(pc, '');
				if (is_IE)				
				    pc.fireEvent('onchange');
                else
                {
                    var changeEvent = window.document.createEvent("HTMLEvents");
				    changeEvent.initEvent("change", false, true);
				    pc.dispatchEvent(changeEvent);
                }
			}
		}	
		return true;
	}
	var req = NewXMLHttpRequest();
	var url = 'suburbs.asp?suburb='+value;
	req.open('GET',url,false);
	req.send(null);
	if (req.status != 200)
	{
		alert(ErrorHeaderText + 'Date/Time: ' + new Date() + '\nHTTP status = ' + req.status + '\nError: ' + req.statusText + '\nURL: ' + url);
		return true;
	}
	if (req.responseText.substring(0,6) == "Error:")
	{
		alert(ErrorHeaderText + req.responseText);
		return true;
	}
	
	var xml = req.responseXML;
	var child = xml.documentElement.firstChild;
	var matches = new Array();
	for (var child = xml.documentElement.firstChild; child != null; child = child.nextSibling)
	{
		if (child.nodeType==1) // Element
			matches.push(new CSuburb(child.getAttribute('name'), child.getAttribute('state'), child.getAttribute('postcode')));
	}
	if (matches.length == 0)
	{
        alert(  'There are no suburbs with the name "'+field.value+'"\n'+
				'\n'+
				'If you are unsure of the name or spelling of the suburb you can '+
				'use one or more wildcards (%) when entering the suburb name. '+
				'Any suburbs that match with the wildcards will then be displayed.\n'+
                '\n'+
				'For example entering "CASTLE%" into the suburb field will return '+
                'both "CASTLEMAINE" and "CASTLETOWN".');
		return false;
	}
	if (matches.length == 1)
	{
		field.value = matches[0].suburb;
		TabToNextField(field);
		var postcode = SuburbMap[field.id];
		if (postcode != null)
		{
			var st = document.getElementById(postcode.state);
			var pc = document.getElementById(postcode.postcode);
			if (st != undefined)
			{
				st.value = matches[0].state;
				if (is_IE)
				    st.fireEvent('onchange');
				else
				{
				    var changeEvent = window.document.createEvent("HTMLEvents");
				    changeEvent.initEvent("change", false, true);
				    st.dispatchEvent(changeEvent);
                }
			}
			if (pc != undefined)
			{
				pc.value = matches[0].postcode;
				if (is_IE)				
				    pc.fireEvent('onchange');
                else
                {
                    var changeEvent = window.document.createEvent("HTMLEvents");
				    changeEvent.initEvent("change", false, true);
				    pc.dispatchEvent(changeEvent);
                }
			}
		}
		return true;
	}
	SuburbList = document.createElement("SELECT");
	SuburbList.size = (matches.length > 10?10:matches.length);
	SuburbList.className = 'SuburbList'; //Make sure this is width:auto in CSS
	SuburbList.onclick = UpdateSuburb;
	SuburbList.onblur = UpdateSuburb;
	SuburbList.onkeypress = CheckSuburbKey;

	for (var i = 0; i < matches.length; i++)
	{
		var option = document.createElement("OPTION");
		option.text = matches[i].suburb + ' - ' + matches[i].state + ' - ' + matches[i].postcode;
		option.value = matches[i].suburb + '|' +  matches[i].state + '|' + matches[i].postcode;
		if (is_IE)
			SuburbList.options.add(option);
		else
			SuburbList.appendChild(option);
	}
    document.body.appendChild(SuburbList);
	SuburbList.style.position = 'absolute';
	SuburbList.style.top = '' + SumProperty(field, 'offsetTop') + 'px';
	SuburbList.style.left = '' + SumProperty(field, 'offsetLeft') + 'px';
	if (SuburbList.clientWidth < field.offsetWidth)
		SuburbList.style.width = '' + field.offsetWidth + 'px';
	CanCloseSuburb = false;
	SuburbList.focus();
	window.setTimeout('CanCloseSuburb = true', 100);
	return true;
}

function UpdateSuburb(e)
{
	if (!CanCloseSuburb || SuburbList == undefined)
		return;
	if (CurrentSuburb && SuburbList.selectedIndex >= 0)
	{
		var data;
		if (is_IE)
			data = SuburbList.options(SuburbList.selectedIndex).value;
		else
			data = SuburbList.options[SuburbList.selectedIndex].value;
		var fields = data.split('|');
		CurrentSuburb.value = fields[0];
		TabToNextField(CurrentSuburb);
		var postcode = SuburbMap[CurrentSuburb.id];
		if (postcode != null)
		{
			var st = document.getElementById(postcode.state);
			var pc = document.getElementById(postcode.postcode);
			if (st != undefined)
			{
				st.value = fields[1];
				if (is_IE)
				    st.fireEvent('onchange');
				else
				{
				    var changeEvent = window.document.createEvent("HTMLEvents");
				    changeEvent.initEvent("change", false, true);
				    st.dispatchEvent(changeEvent);
                }
			}
			if (pc != undefined)
			{
				pc.value = fields[2];
				if (is_IE)				
				    pc.fireEvent('onchange');
                else
                {
                    var changeEvent = window.document.createEvent("HTMLEvents");
				    changeEvent.initEvent("change", false, true);
				    pc.dispatchEvent(changeEvent);
                }
			}
		}
	}
	if (SuburbList != undefined)
	{
		SuburbList.style.display = 'none';
		document.body.removeChild(SuburbList);
	}
	SuburbList = undefined;
	CanCloseSuburb = false;
}

function CheckSuburbKey(e)
{
	if (e == undefined)
		e = window.event;
	if (e.keyCode == 13 && SuburbList.selectedIndex >= 0)
		UpdateSuburb(e);
}

function GetGridKey(field)
{
	var id;
	if (field.constructor == String)
		id = field;
	else 
		id = field.id;
	var parts = id.split(':');
	return parts[0] + ':' + parts[1] + ':'
}

function TabToNextField(field)
{
	var form;
	if (is_IE)
		form = document.forms(0);
	else
		form = document.forms[0];
	var fields = form.elements;
	var found = false;
	
	for (var i = 0; i < fields.length; i++)
	{
		if (found)
		{
			if (fields[i].disabled != true && fields[i].tabIndex >= 0)
			{
				fields[i].focus();
				return;
			}
		}
		else if (fields[i] == field)
			found = true;
	}
	field.focus();
}

function SumProperty(object, property)
{
	if (object == null || object == undefined)
		return 0;
	var val = eval('object.' + property);
	if (val == undefined)
		return SumProperty(object.offsetParent, property);
	return eval('object.' + property) + SumProperty(object.offsetParent, property);
}