//--------------------------------
// popup windows - lookup 
//--------------------------------

function field_key_down(e,field)
{
	// make sure that field is validated early for a tab press
	var key = get_code(e);
	if (key == 9)
		validate_field(field);
}
function field_key_up(e,field)
{
	//always validate field when changed
	var key = get_code(e);
	// validate if text added or character deleted
	if (key == 9) return;
	if (key < 31 && key != 8) return;
	if (key >= 35 && key <= 40) return;
	validate_field(field, true);
}

var DISABLED_TEXT = 'disabled';

function null_text_value()
{
	var url = get_url('1');
	if (GetPageName(url) == 'search')
		return '[all]';
	else
		return '[unspecified]';
}

function OTO_tab_change(cid,id)
{
	var df = elementFromid('data_form_' + cid);
	var cid = get_cid(df);

	if (validate(cid,true))
	{
		df.action = ReplaceQs(df.action,add_cid(cid,'oto_tab'),id);
		reload_post();
	}
}
function reload_post()
{
	var df = elementFromid('data_form_1');
	df.nosave.value = 'True';
	df.submit();
}
//--------------------------------
// popups 
//--------------------------------

// lookup foreign
var fNoShow = false;
function lookup_open(e,field_but,dependees)
{
	var df = field_but.form;
	var cid = get_cid(df);
	var id = field_but.id.substring(0,field_but.id.length - 4);
	var field = elementFromid(id);
	var url = get_url(cid);
	var div;
	var depends;

	if (dependees == undefined)
	{
		//new way - json object holds dependees
		depends = get_depend_values(field);
	}
	else
	{
		depends = add_depends(dependees,get_trailing_number(field.name));
	}

	elementFromid(id + '_d').value = depends;

	if (!fNoShow)
	{
		div = elementFromid(id + '_div');
		if (div.style.visibility == "visible")
		{
			set_popup(null);
			return;
		}

		var row = get_trailing_number(field.name);
		var key = row_key(row);
		if (key == '[var]') 
			key = elementFromid(add_cid(cid,'sample_key')).value;

		key = AppendQs('key',key);
			
		var pagesize = elementFromid('pagesize_o' + cid);
		if (pagesize == null)
			pagesize = '';
		else
			pagesize = '&pagesize=' + pagesize.value;
			
		var field_name = get_stem(field.name);
		var src = AppPath + '/generic/pages/lookup.aspx?table=' + get_table(url)
			+ AppendQs('mode',get_mode(url))
			+ AddQs(add_cid(cid,'oto_tab'),url)
			+ key
			+ '&field=' + field_name + '&field_id=' + id
			+ GetWhere(url,false)
			+ '&window=' + GetQs(url,'window')
			+ depends
			+ pagesize;
			
		src = add_preserve(src);
	
		var iframe = elementFromid(id + '_ifr');
		var win;
		win = iframe.contentWindow;
		win.opener = self;

		set_popup("hide_popup('" + id + "')");
		div_show(div);
		
		var current_src =  RemoveQs(iframe.src,'value')
		if (current_src != src)
		{
			src = src + '&value=' + get_field_value(field);
			iframe.src = src;
		}
		else
		{
			if (win.do_load) win.do_load();
		}
	}
	if (e != null)
		cancel_bubble(e);
	return false;
}

var postcode_index = new Object();
function postcode_open(field_but)
{
	var df = field_but.form;
	var cid = get_cid(df);
	var id = field_but.id.substring(0,field_but.id.length - 4);

	var field = elementFromid(id);
	var qs = get_qs(cid);

	var country_field = field_value_from_id(field.id.replace(/postcode_zip/,'country_id'));
	if (country_field != null)
	{
		if (country_field != 'gb')
		{
			alert('Postcode lookup is only available for addresses in the uk');
			return;
		}
	}

	var div;

	div = elementFromid(id + '_div');
	if (div.style.visibility == "visible")
	{
		set_popup(null);
		return;
	}

	var src = AppPath + '/generic/pages/postcode.aspx?field_id=' + id
		+ '&window=' + GetQs(qs,'window')
		+ '&value=' + field.value;

	var iframe = elementFromid(id + '_ifr');
	var win;
	win = iframe.contentWindow;
	win.opener = self;

	set_popup("hide_popup('" + id + "')");
	div_show(div);

	var current_src =  iframe.src;
	if (current_src != src)
	{
		iframe.src = src;
	}
	else
	{
		if (win.do_load) win.do_load();
	}
}
function person_open(field_but, postcode_field_name)
{
	var df = field_but.form;
	var cid = get_cid(df);
	var id = field_but.id.substring(0,field_but.id.length - 4);

	var field = elementFromid(id);
	var qs = get_qs(cid);

	var postcode_field_id = related_field_id(field,postcode_field_name);
	var index = postcode_index[postcode_field_id];
	if (index == undefined || index == null)
	{
			alert('Postcode must be looked up');
			return;
	}
	
	/*todo - make work using index above
	clear index if postcode manually changed after lookup
	make page respond to index passed as "value" - currently passing actual postcode 
	check works on old postcode anywhere 
	make old postcode anywhere 1) not lookup if no changes - 2) correctly process \r's
	change order of fields*/
	
	var div;

	div = elementFromid(id + '_div');
	if (div.style.visibility == "visible")
	{
		set_popup(null);
		return;
	}

	var src = AppPath + '/generic/pages/postcode-person.aspx?field_id=' + id
		+ '&window=' + GetQs(qs,'window')
		+ '&value=' + index;

	var iframe = elementFromid(id + '_ifr');
	var win;
	win = iframe.contentWindow;
	win.opener = self;

	set_popup("hide_popup('" + id + "')");
	div_show(div);

	var current_src =  iframe.src;
	if (current_src != src)
	{
		iframe.src = src;
	}
	else
	{
		if (win.do_load) win.do_load();
	}
}

function image_open(field_but)
{
	var df = field_but.form;
	var cid = get_cid(df);
	var id = field_but.id.substring(0,field_but.id.length - 4);
	var field = elementFromid(id);
	var url = get_url(cid);
	var row = get_trailing_number(field.name);
	var key = row_key(row);
	var mode = get_mode(url);

	open_url_generic('upload.aspx?table=' + get_table(url)
		+ '&key=' + key
		+ '&field_id=' + field.id
		+ '&mode=' + mode
		+ AddQs('parent',url)
		+ '&window=' + GetQs(url,'window')
		+ '&oto_tab=' + GetQs(url,add_cid(cid,'oto_tab')),
		true, 530,480,300,120);
}


function multi_delete(id)
{
	var field = elementFromid(id);
	var sel = elementFromid(id + '_sel');
	for(var i = sel.options.length - 1; i >= 0; i--)
	{
		if (sel.options[i].selected)
		{
			sel.options[i] = null;
		}
	}
	if ( sel.options.length == 0)
		sel.size = 1;
	else
		sel.size = sel.options.length;
		
	var value = get_multi_select_value(sel,true);
	if (value == '') value = NULL_VALUE;
	field.value = value;
}

function image_content_change(field)
{
	var data = elementFromid('data_form_1');
	data.nosave.value = 'True';
	data.submit();
}

// position above or below field depending on window space
function position_dd(id,largest_div)
{
	var iframe = elementFromid(id + '_ifr');
	var field_div = elementFromid(id);
	field_div = field_div.parentNode;

	//make dd wide enough for content
	var dd_width;
	if (largest_div == undefined)
		dd_width = iframe.contentWindow.document.body.scrollWidth;
	else
		dd_width = largest_div.scrollWidth + 10;

	if (dd_width > number_from_px(iframe.parentNode.style.width)) 
	{
		iframe.style.width = dd_width + 'px';	
		iframe.parentNode.style.width = dd_width + 'px';
	}
	
	var getFFVersion = navigator.userAgent.substring(navigator.userAgent.indexOf("Firefox")).split("/")[1];
	var FFextraHeight = parseFloat(getFFVersion)>=0.1 ? 16 : 0; //extra height in px to add to iframe in FireFox 1.0+ browsers
	var height = 0;
	if (iframe.contentDocument && iframe.contentDocument.body.offsetHeight) //ns6 syntax
		height = iframe.contentDocument.body.offsetHeight + FFextraHeight;
	else if (iframe.Document && iframe.Document.body.scrollHeight) //ie5+ syntax
		height = iframe.Document.body.scrollHeight;
	else
		return;
	if (iframe.style.height != height + 'px')
	{
		iframe.style.height = height + 'px';
	}
	else
	{
		return;
	}
	
	//amount of space above showing on screen
	//above_height = above_height - get_scroll_top();
	// amount of space from top of doc down to the top of this field less the top scroll posn = space above
	var above_height = size_from(null,field_div,'Top') - get_scroll_top();
	var div_height = 22;
	// total space below = window height - space_above - height of input field
	var below_height =  window_height() - above_height - div_height;
	

	var right_side = size_from(null,field_div,'Left') + dd_width;
	var dd = elementFromid(id + '_div');
	if (right_side > window_width())
		dd.style.left = (window_width() - right_side) + 'px';
		
	//move to above if not enough room below
	
	var dd_height = parseInt(number_from_px(iframe.style.height));
	dd.style.height = dd_height + 'px';
	if (dd_height > below_height && above_height >= dd_height)
	{
		var text_box = elementFromid(id + '_txt');
		dd.style.top = - (dd_height + div_height) + 'px';		
	}
	else
		dd.style.top = '0px';
	
	return;
}

function hide_popup(id)
{
	var div = elementFromid(id + '_div');
	//alert(id);
	div_hide(div);
}

function ParentSetPostcodeValue(id,value,index)
{
	var address = value.split('|');
	var field = elementFromid(id);
	var iframe = elementFromid(id + '_ifr');
	iframe.src = BLANK_SRC;
	var start = id.substring(0,id.indexOf('postcode_zip'));
	set_postcode_field(field,start + 'addr', address[0]);
	set_postcode_field(field,start + 'town_city', address[1]);
	set_postcode_field(field,start + 'county_state', address[2]);
	set_postcode_field(field,start + 'postcode_zip', address[3]);
	postcode_index[id] = index;
	ParentLookupClose(id);
}
function ParentSetPersonValue(id,value)
{
	var person = value.split('|');
	var field = elementFromid(id);
	var iframe = elementFromid(id + '_ifr');
	iframe.src = BLANK_SRC;

	var start = id.substring(0,id.indexOf('surname'));
	set_postcode_field(field, start + 'first_name', person[0]);
	set_postcode_field(field, start + 'surname', person[1]);
	ParentLookupClose(id);
}

function set_postcode_field(field,name,value)
{
	set_field_value(related_field(field,name), value);
}


function auto_lookup_choose()
{
	var cid = '1';
	var df = elementFromid('data_form_' + cid);
	if (df == null) return;
	if (df.auto_save.value == 'y')
	{
		if ((df.row.options.length == 1 || df.row.options.length == 2 && df.row.options[0].value == NULL_VALUE) &&
			GetQs(document.location.href,'value') != df.row.options[df.row.options.length - 1].value)
		{
			df.auto_save.value = '';
			df.row.selectedIndex = df.row.options.length - 1;
			lookup_choose();
		}
	}
}

function lookup_choose()
{
	var df = elementFromid('data_form_1');
	
	if (df.row.value == '[more]')
	{
		alert('The list contains too many values, enter part of the name to filter');
		set_focus(elementFromid('filter'));
	}	
	else
	{
		var row = df.row;
		var value = get_select_value(row);
		
		if (value != '')
		{
			var text = get_select_text(row);
			parent.ParentSetLookupValue(GetQs(df.action,"field_id"),value,text);
		}
	}
	return false;
}


var dd_search = new Object();
function lookup_popup(id, table, mode, restricts,width,height,dependees)
{
	var field = elementFromid(id);

	fNoShow = true;
	//var but = elementFromid(id + '_but');
	//if (but != null) but.onclick();
	fNoShow = false;
	
	var value;
	
	if (dependees == undefined)
	{
		//new way - json object holds dependees
		depends = get_depend_values(field);
	}
	else
	{
		depends = add_depends(dependees,get_trailing_number(field.name));
	}

	elementFromid(id + '_d').value = depends;
	
	var src = '';
	if (mode == 'edit')
	{
		var field_type = get_field_type(field);
		
		if (field_type == 'multi')
		{
			var sel = elementFromid(id + '_sel');
			value = get_multi_first_select_value(sel);
		}
		else
			value = field.value;

 		if (value == NULL_VALUE)
		{
			alert('You must select the entry you wish to edit.');
			return;
		}
		src = '&key=' + value;
	}
	if (mode == 'add')
	{
		if (dd_search[id] != undefined)
		{
			src += AppendQs('search',dd_search[id]);
		}
	}
	var df = field.form;
	var cid = get_cid(df);
	var url = get_url(cid);
	var qs = get_qs(cid);
	src = 'record.aspx?popup=y&table=' + table + '&mode=' + mode 
		+ '&field_id=' + id
		+ '&from_table=' + get_table(url)
		+ '&window=' + GetQs(qs,'window') + '1'
		+ src;
		
	if (restricts != '') src = src + restricts
		
	open_url_generic(src,true,height,width);
}



//old way - can be removed once code migrated
function add_depends(depends,row)
{
	var src = '';
	var name;
	
	if (depends != undefined)
	{
		for (var i = 0; i < depends.length; i++)
		{
			name = depends[i];
			src = src + '&ff_' + name + '=' + field_value_from_id(name + '_' + row); 
		}
	}
	return src;
}

// new way - json object holds dependencies

var oLookupDependees = new Object();
function get_depend_values(field)
{
	var df = field.form;
	var cid = get_cid(df);

	var depends = oLookupDependees[name_and_cid(field)];

	var src = '';
	var name;
	
	if (depends != undefined)
	{
		for (var i = 0; i < depends.length; i++)
		{
			name = depends[i];
			src = src + '&ff_' + name + '=' + field_value_from_id(related_field_id(field, name));
		}
	}
	return src;
}


function ParentSetLookupValue(id,value,text)
{
	var field = elementFromid(id);
	set_field_value(field,value, text);
	ParentLookupClose(id);
}
function add_lookup_value(id,value,text)
{
	var field = elementFromid(id);
	var iframe = elementFromid(id + '_ifr');
	
	if (iframe != null)
		iframe.src = BLANK_SRC;

	if (!update_text_value(field,value, text))
	{
		set_field_value(field, value, text);
	}

	set_field_focus(field);
}
function update_text_value(field, value, text)
{
	var field_type = get_field_type(field);
	var value_field;
	var sel;
	var option;
	var i;
	var fFound = false;

	if (field_type == 'multi' || field_type == 'dropdown')
	{
		if (field_type == 'multi')
			sel = elementFromid(field.id + '_sel');
		else
			sel = field;
		option = option_from_value(sel.options, value);
		if (option != null)
		{
			option.text = text;
			fFound = true;
		}
	}
	else if (field_type == 'ajax')
	{
		sel = elementFromid(field.id + '_sel');
		//var iStart = cmb_sel_getstart(sel);
		option = option_from_value(sel.options, value,0);
		if (option != null)
		{
			option.text = text;
			fFound = true;
		}
		option = option_from_value(sel.options, value);
		if (option != null)
		{
			option.text = text;
			fFound = true;
		}
		if (get_field_value(field) == value)
		{
			value_field = elementFromid(field.id + '_ajx');
			value_field.value = text;
		}
	}
	else if (get_field_value(field) == value)
	{
		value_field = elementFromid(field.id + '_txt');
		value_field.value = text;
		fFound = true;
	}
	return fFound;
}
function image_delete()
{
	//var df = elementFromid('data_form_1');
	//elementFromid('file_0').value = '';
	//df.submit();
	window.opener.add_image_value(GetQs(document.location.href,'field_id'),null,'',NULL_VALUE,'',0,0);
	window.close();
}
function add_image_value(id,file_id,fImage,name,value,content_type,width,height)
{
	var field = elementFromid(id);
	var df = field.form;
	var cid = get_cid(df);

	//var qs = get_qs(cid);
	//var row = get_trailing_number(id);
	var src;
	var img = elementFromid(id + '_img');

	src = AppPath 
	if (name == '') 
	{
		elementFromid(id + '_content_type').value = NULL_VALUE;
		src += "/generic/images/unknown.gif";
		img.alt = null_text_value();
		img.width = 16;
		img.height = 16;
		img.src = src;
	}
	else
	{	
		elementFromid(id + '_content_type').value = content_type;

		var datDate = new Date();
		src += '/generic/pages/image.aspx?file_id=' + file_id + '&now=' + datDate.valueOf();
		//if (value != NULL_VALUE) src += '&file_id=' + value;
		img.alt = name;
		img.src = src;
		img.width = width;
		img.height = height;
	}
	elementFromid(id).value =  name;
	
	validate_field(field);
	set_field_focus(field);
}

function set_enabled(field,fEnable,sReason,fHideAllowed)
{
	var field_type = get_field_type(field);
	var fDisabled = null;
	var control = null;
	if (field_type == 'html')
	{
		var error_field = elementFromid(field.id + '_err');
		if (error_field.innerHTML.startsWith(DISABLED_TEXT))
		{
			if (fEnable) 
			{
				fDisabled = false;
				clear_field_error(field);
			}
		}
		else
		{
			if (!fEnable) fDisabled = true;
		}
	}
	else
	{
		control = focus_control(field);
		if (fEnable && control.disabled)
			fDisabled = false;
		else if (!fEnable && !control.disabled)
			fDisabled = true;
	}
	
	if (!fEnable)
	{
		if (sReason == undefined)
			sReason = '';
		else
			sReason = ' - ' + sReason;
		sReason = DISABLED_TEXT + sReason
		set_field_error(field,sReason);
	}
	
	set_field_visible(field, fEnable || !fHideAllowed);

	if (fDisabled != null)
	{
			
		//disable input control
		if (control != null) control.disabled = fDisabled;
		if (field_type == 'ajax' || field_type == 'date' || field_type == 'dd_date' || field_type == 'file' || field_type == 'text')
		{
			control = elementFromid(field.id + '_but');
			if (control != null)
				control.disabled = fDisabled;
		}
		if (field_type == 'multi')
		{
			control = elementFromid(field.id + '_sel');
			if (control != null) control.disabled = fDisabled;
			control = elementFromid(field.id + '_del');
			if (control != null) control.disabled = fDisabled;
		}
		if (field_type == 'ajax' || field_type == 'multi' || field_type == 'list' || field_type == 'dropdown')
		{
			field.disabled = fDisabled;
			control = elementFromid(field.id + '_new');
			if (control != null) control.disabled = fDisabled;
			control = elementFromid(field.id + '_edt');
			if (control != null) control.disabled = fDisabled;
		}
		
		if (field_type == 'dd_date')
		{
			var format_field = elementFromid(field.id + '_format');
			var dd_value = format_field.value;
			if (elementFromid(field.id + '_xx') != null)
				dd_value = dd_value.replace('MM/yyyy','xx');
			var oFields = dd_value.split_any(' /:');
			var dd_field,i;
			for(i=0; i < oFields.length; i++)
			{
				dd_field = elementFromid(field.id + '_' + oFields[i]);
				dd_field.disabled = fDisabled;
			}
		}
		if (fEnable)
			validate_field(field);
		else
			process_depends(field);
	}
}

function set_field_visible(field,fVisible)
{
	//var cid = get_cid(field.form);
	//var url = get_url(cid);

	var div;
	var table;
	var df = field.form;
	var cid = get_cid(df);
	var row_count = elementFromid('rows_' + cid).value;
	div = elementFromid(field.id + '_title_vis');

	if (div != null)
	{
		set_td_visibility(div, fVisible);
	}


	div = elementFromid(field.id + '_vis');
	if (div != null) 
	{
		set_td_visibility(div, fVisible);

		var url = get_url(cid);
		var mode = get_mode(url);
		if (mode != 'search')
			if (row_count == 1) table = div.parentNode.parentNode.parentNode.parentNode;
	}
	
	//if all fields in a group are invisible, hide the whole table
	if (table != null)
	{
		if (fVisible)
		{
			set_td_visibility(table,true);
		}
		else
		{
			if (table.style.visibility != 'hidden')
			{
				var td,fSomeShowing = false;
				for(var i = 0; i < table.rows.length; i++)
				{
					td = table.rows[i].cells[0];
					if (td.className != 'heading')
					{
						div = td.firstChild;
						if (div.style.visibility != 'hidden')
						{
							fSomeShowing = true;
							break;
						}
					}
				}
				if (!fSomeShowing)
				{
					set_td_visibility(table,false);
				}
			}
		}
	}
}

function check_search_refresh(field)
{
	var fRefresh = true;
	if (field != undefined)
	{
		var old_value = elementFromid(field.id + '_compare_o').value;
		var new_value = elementFromid(field.id + '_compare').value;

		//var fDepend = window['field_depend_' + name_and_cid(field)];
		//if (fDepend != undefined && (elementFromid(depend_field.id + '_d').value; old_value == 'eq' || new_value == 'eq'))

		if (get_search_type_cat(old_value,field) == get_search_type_cat(new_value,field))
		{
			fRefresh = false;
		}
		else
			set_enabled(field,false);
			//set_field_value(field,NULL_VALUE);	
	}

	if (fRefresh)
	{
		search_refresh();
	}
}
function search_mode_change(cid,mode)
{
	var df = elementFromid('data_form_' + cid);
	var url = get_url(cid);
	var url = BasePath + '/pages/' + get_table(url) + '/search.aspx'
		+ '?type=' + mode + AddQs('id',url) + AddQs('from',url);
	replace_url(url);
}

function search_refresh()
{
	var data = elementFromid('data_form_1');
	data.nosave.value = 'True';

	data.submit();
}

function get_search_type_cat(compare_type,field)
{
	switch(compare_type)
	{
		case 'be':
			return 'be';
		case 'co':
		case 'st':
		case 'en':
			return 'co';
		case 'nn':
			return 'nn';
		case 'in':
		case 'ni':
			return 'in';
		case 'ma':
			return 'ma';
		case 'ne':
			return 'ne';
		default:
			return 'eq';
	}
}

//FIELDS
function ParentLookupClose(id)
{
	var iframe = elementFromid(id + '_ifr');
	set_popup(null);
	var field = elementFromid(id);
	set_field_focus(field);
}

var current_popup = null;
function set_popup(hide_cmd)
{
	if (current_popup != null) 
	{
		eval(current_popup);
	}
	current_popup = hide_cmd;
}

var last_field = null;
function validate_last_field(field)
{
	var base_field = get_base_field(field);
	if (field != null && base_field != null)
	{
		var field_type = get_field_type(base_field);
		if (field_type == 'ajax')
			cmb_txt_validate(field);
	}
			
	if (last_field != base_field)
	{
		set_popup(null);

		if (last_field != null)
		{
			field_change(last_field);
		}
		last_field = base_field;
	}
}

function get_base_field(field)
{
	if (field != null && field.id != '')
	{
		var base_field = null;
		if (field.form != undefined)
		{
			base_field = field.form[BaseFieldName(field)];
			if (base_field != null && base_field.length == undefined)
			{
				if (get_field_type(base_field) != null)
				{
					return base_field;
				}
			}
		}
	}
	return null;
}

function all_fields(cid,func, fNoExit)
{
	var field;
	var fReturn = false;
	var fld_ary = window[add_cid(cid, 'field_array')];
	if (fld_ary != undefined && fld_ary.length > 0)
	{
		var row_count = elementFromid('rows_' + cid).value;
	
		var fFunc;
		var df;
		fFunc = window[func];
		df = elementFromid('data_form_' + cid);
		if (df != null)
		{
			for(var j = 0; j < row_count;j++)
			{
				for (var i = 0; i < fld_ary.length; i++)
				{
					field = get_form_field(df,fld_ary[i] + '_' + j);
					if (field != null)
					{
						if (fFunc(field))
						{
							fReturn = true;
							if (!fNoExit) break;
						}
					}
				}	
			}
		}
	}
	return fReturn;
}
function get_form_field(df, name)
{
	var field = df.elements[name];
	if (field == undefined)
		return null;
	if (field.type != undefined)
		return field;
	else if (field.length != undefined)
		return field[0];
	else
		return null;
}
function validate(cid, fNoChangeCheck)
{
	if (last_field != null) validate_last_field(null);

	var df = elementFromid('data_form_' + cid);
	var url = get_url(cid);
	if (df.nosave != undefined)
		if (df.nosave.value == 'True')
			return true;

	var fValid = true;	

	//clear main error
	set_error('',cid);
		
	// on edit fields, something must change
	if (!fNoChangeCheck)
	{
		var mode = get_mode(url);
		if (mode == 'edit')
		{
			var fld_ary = window[add_cid(cid,'field_array')];
			if (fld_ary.length > 0 && !all_fields(cid,'check_field_changed'))
			{
				fValid = false;
				set_error('No values changed',cid);
			}
		}
	}
	if (fValid)
	{
		fValid = !all_fields(cid,'validate_field')
		if (!fValid) 
		{
			all_fields(cid,'first_field_error');
			set_field_focus(first_field);
		}
	}
	return fValid;
}
function validate_submit(df,fNoChangeCheck)
{
	if (fOpening) 
	{
		alert('Page load already in progress.');
		return false;
	}
	if (last_field != null) validate_last_field(null);

	var cid = get_cid(df);
	var url = get_url(cid);
	var fValid = validate(cid,fNoChangeCheck);
	if (fValid)
	{
		var mode = get_mode(url);
		if (mode == 'edit')
		{
			var key_count = get_key_count(cid);
			if (key_count > 1)
				fValid = confirm('Are you sure you wish to save these ' + key_count + ' ' + get_title(cid,key_count) + '?');
		}
	}
	
	if (fValid) fOpening = true;
	return fValid;
}
var nbsp = String.fromCharCode(160);

function set_error(msg,cid)
{
	if (msg == '') msg = nbsp;
	elementFromid(add_cid(cid,'error')).innerHTML = msg;
	if (msg != nbsp) 
		alert(msg);
}
function clear_field_error(field)
{
	var error_field = elementFromid(field.id + '_err');
	if (error_field != null)
		if (!is_error_blank(error_field,false))
			error_field.innerHTML = nbsp;
}

function set_field_error(field, error)
{
	var df = field.form;
	var cid = get_cid(df);
	var div = elementFromid(field.id + '_err');
	if (div == null) 
	{
		div = elementFromid(add_cid(cid,'error'));
		var title = get_field_title2(field);
		if (title != '') 
		{
			error += ' on field ' + title;
			div.innerHTML = error;
		}
	}
	else
	{
		if (error.substring(0,DISABLED_TEXT.length) == DISABLED_TEXT)
			div.className = 'disabled';
		else
			div.className = 'error';
		div.innerHTML = error;
	}
}

function related_field(field, name)
{
	var df = field.form;
//	var cid = get_cid(df);
	name += '_' + get_trailing_number(field.name);
	var field = df[name];
	if (field.type == undefined && field.length != undefined)
		return field[0];
	else
		return field;
		
//	if (cid != '1') name += '_' + cid;
//	return name;
}

function related_field_id(field, name)
{
	var df = field.form;
	var cid = get_cid(df);
	name += '_' + get_trailing_number(field.name);
	if (cid != '1') name += '_' + cid;
	return name;
}
function name_and_cid(field)
{
	var df = field.form;
	var cid = get_cid(df);
	return add_cid(cid,get_stem(field.name));
}

function field_value_from_id(id)
{
	var field = elementFromid(id);
	var value = null;

	if (field == null) field = elementFromid(id + '_o');
	if (field != null) value = get_field_value(field,false);
	return value;
}

//called when a field changes
function check_dependent(field,name,depend_type)
{
	var depend_field = related_field(field,name);
	var parent_value;
	var child_value;


	process_disabled(depend_field);
	switch(depend_type)
	{
		//field value has changed so clear all dependents
		case 'P':
			//compare depend field base value and current value to decide if it needs to be cleared
			
			//if child field is null, no need to bother
			//if child field is original value and parent is original value, no need to bother
			//if child field has been changed, see if parent value is same


			child_value = get_field_value(depend_field);

			if (child_value != NULL_VALUE)
			{
				if (check_field_changed(field)) 
				{
					parent_value = get_field_value(field);
									
					var child_depends = elementFromid(depend_field.id + '_d').value;
					if (child_depends == '')
						child_value = get_original_field(field).value;
					else
						child_value = GetQs(child_depends, 'ff_' + get_stem(field.name));
					if (child_value != parent_value)
					{
						set_field_value(depend_field,NULL_VALUE);
						child_value = NULL_VALUE;
					}
				}
			}
			break;
		case 'S':
			if (check_field_changed(field))
			{
				parent_value = get_field_value(field);

				var child_depends = elementFromid(depend_field.id + '_d');
				if (child_depends != undefined) 
				{
					child_depends = child_depends.value;
					if (child_depends == '')
						child_value = get_original_field(field).value;
					else
						child_value = GetQs(child_depends, 'ff_' + get_stem(field.name));

					if (child_value != parent_value)
					{
						set_field_value(depend_field,NULL_VALUE);
						child_value = NULL_VALUE;
					}
				}
			} 
			break;
		case 'E':
			break;			
	}

	var depend_field_type = get_field_type(depend_field);
	if (depend_field_type == 'ajax')
	{
		var id = depend_field.id;
		if (IsEnabled(depend_field,depend_field_type) 
			&& child_value == NULL_VALUE 
			&& !dd_isnullable[id])
		{
			cmb_load_newrequest(id);
		}
	}
}


function check_field_changed(field, fFirstTime)
{
	if (field == null) return false;
	
	var fSame;
	var df = field.form;
	var cid;
	if (df == null)
		cid = '1';
	else
		cid = get_cid(df);

	var id = field.id;
	var url = get_url(cid);
	var mode = get_mode(url);

	// new fields have always 'changed'	
	if (!fFirstTime && (mode == 'add' || mode == 'search'))
		return true;
	else
	{
		var original = null;
		
		//on initialise, compare value to "last post value" when page was first loaded
		//if the same then nothing has changed since page was first shown
		if (fFirstTime)
		{
			original = elementFromid(field.id + '_v');
			//no last post value, use actual original
			if (original != null && original.value == '[unset]')
				original = null;
		}
		
		if (original == null) 
			original = get_original_field(field);
			
		//no original so always "changed" - will be validated
		if (original == null) return true;
	
		var old_value = get_field_value(original);
		var new_value = get_field_value(field);
		if (old_value == '[empty]') old_value = NULL_VALUE;
		fSame = (old_value == new_value);
		return !fSame;
	}
}
function get_field_error(field)
{
	var error_field = elementFromid(field.id + '_err');
	if (error_field == null)
		return null;
	
	if (!is_error_blank(error_field,true)) 
	{
		return error_field.innerHTML;
	}
	else
		return null;
}

function is_error_blank(error_field,fCountDisabledBlank)
{
	var msg = error_field.innerHTML;
	var nbsp_text = "&nbsp;";
	if (msg == '' || msg == nbsp_text || msg == nbsp 
		|| (fCountDisabledBlank && msg.substring(0,DISABLED_TEXT.length) == DISABLED_TEXT) )
			return true;
	return false;
}

// find first field error and raise alert
var first_field = null;
function first_field_error(field)
{
	var msg = get_field_error(field);
	if (msg != null)
	{
		alert(get_field_title2(field) + ' ' + msg);
		first_field = field;
		return true;
	}
	else
		return false;
}
function get_field_type(field)
{
	
	var format_field = elementFromid(field.id + '_format');
	if (field.type == 'hidden')
	{
			
		if (format_field != null)
			return 'dd_date';

		var text_field = elementFromid(field.id + '_txt');
		if (text_field != null)
			return 'list';

		var text_field = elementFromid(field.id + '_ajx');
		if (text_field != null)
			return 'ajax';

		var sel = elementFromid(field.id + '_sel');
		if (sel != null)
			return 'multi';

		var text_field = elementFromid(field.id + '_but');
		if (text_field != null)
			return 'file';
	}
	else
	{
		//if (field.length != undefined)
		//	return 'status';
		var check = elementFromid(field.id + '_content_type');
		if (check != null) return 'file';
		
		if (field.className == 'tinymce')
			return 'html';
		if (format_field != null)
			return 'date';
		if (field.type == 'text' || field.type == 'textarea' || field.type == 'password' || field.type == 'file' )
			return 'text';
		if (field.type == 'select-one' || field.type == 'select-multiple')
			return 'dropdown';
		if (field.name != '' && field.form[field.name].length != undefined)
			return 'status';
	}			
	return null;
}
function field_change_refresh(field)
{
	reload_post();
}
function field_change(field,dd)
{
	//create date field value from dd fields ?
	var format, oFields, dd_field, dd_value, i, sValue;
	
	if (get_field_type(field) == 'dd_date' && dd != undefined)
	{
		format = elementFromid(field.id + '_format').value;
		dd_value = format;
		if (elementFromid(field.id + '_xx') != null)
			dd_value = dd_value.replace('MM/yyyy','xx');
		oFields = dd_value.split_any(' /:');
		
		if (dd.value == NULL_VALUE) dd_value = NULL_VALUE;
		
		//If dd was changed to "non-null", set any nulls
		//if ff was changed to "null", set clear all nulls
		// see if any of dd fields are null
		for(i=0; i < oFields.length; i++)
		{
			dd_field = elementFromid(field.id + '_' + oFields[i]);
			if (dd.value == NULL_VALUE && dd_field.value != NULL_VALUE)
			{
				if (dd_field != dd)	dd_field.value = NULL_VALUE;
			}
			if (dd.value != NULL_VALUE)
			{
				if (dd_field != dd && dd_field.value == NULL_VALUE)	
				{
					//use current date time but make sure it's within the defaults
					var datDefault = new Date();

					var range_field, range_value;
					range_field = elementFromid(field.id + '_min');
					
					if (range_field != null)
					{
						range_date = date_from_mask(range_field.value, format);
						if (datDefault < range_date) datDefault = range_date;
					}
					
					range_field = elementFromid(field.id + '_max');
					if (range_field != null)
					{
						range_date = date_from_mask(range_field.value, format);
						if (datDefault > range_date) datDefault = range_date;
					}
					
					var date_part = get_trailing_number(dd_field.id);
					var sDefault = text_from_date(datDefault, format);
					if (date_part == 'xx')
					{
						sValue = datepart_from_mask(sDefault, format, 'MM') + '/' + datepart_from_mask(sDefault, format, 'yyyy');
					}
					else
						sValue = datepart_from_mask(sDefault, format, date_part);
						
					dd_field.value = sValue;
					//set_field_value(field, );
				}
				sValue = dd_field.value;
				if (oFields[i] != 'xx')
					sValue = format_number(dd_field.value,oFields[i].length)
				dd_value = dd_value.replace(oFields[i],sValue);
			}
		}
		field.value = dd_value;
	}

	//when field altered validate it
	validate_field(field);
	
}

function status_change(option,fSave)
{
	
	var df = option.form;
	var cid = get_cid(df);
	var qs = get_qs(cid);
	var id = option.name;
	var field_name = get_stem(id);
	var original = get_original_field(option);
	var new_value = option.value;
	var original_save;

	var save_value = GetQs(qs,'ff_' + field_name);
	
	if (save_value == '')
		save_value = original.value;

	//status has not changed
	if (save_value == new_value)
		return;

	// clear focus to avoid infinite loop for Onchange
	focus_field = null;

	//if status is moving backwards, no need to save
	//must warn if other changes however
	if (!fSave)
	{
		//make checkboxes look right
		option_from_value(df[id],save_value).checked = false;

		// temporarily set original value to same as current so status field
		// does not count as part of "changed" fields
		original_save = original.value;
		original.value = new_value;

		//fSave = all_fields('1','check_field_changed');
		fSave = confirm_exit();
		if (fSave)
		{
			replace_url(ReplaceQs(df.action, 'ff_' + field_name, new_value));
		}
		else
		{
			//undo new value
			option_from_value(df[id],new_value).checked = false;
			option_from_value(df[id],save_value).checked = true;
		}
		// restore original value
		original.value = original_save;
	}
	else
	{
		fSave = validate_submit(df,true);
		
		// uncheck the newly clicked status value so it doesn't count as part of changes
		option_from_value(df[id],new_value).checked = false;

		//could be that no fields have changed
		if (fSave)
		{
			
			if (!all_fields(cid,'check_field_changed'))
			{
				goto_page(ReplaceQs(df.action, 'ff_' + field_name, new_value));
			}
			else
			{
				//post changes
				df.action = ReplaceQs(df.action, 'reedit', field_name + ',' + new_value);
				df.submit();
			}
		}
	}
	
	if (!fSave)
	{
		fOpening = false;
		focus_field = option;
	}
}

function IsEnabled(field,field_type)
{
	if (field_type == 'html')
	{
		var error_field = elementFromid(field.id + '_err');
		return !error_field.innerHTML.startsWith(DISABLED_TEXT);
	}
	else
	{
		var focus_field = focus_control(field);
		if (focus_field == null) return false;
		return !focus_field.disabled;
	}
}

function validate_field_init(field)
{
	validate_field(field,false,true);
}

function validate_field(field, fNoTrim, fFirstTime, fChanged)
{
	// test if field has changed from original value
	// and process dependents if it has
	var field_type = get_field_type(field);
	var fError = false;
	var fEnabled = true;

	fEnabled = IsEnabled(field,field_type);
	
	if (fEnabled)
	{
		//validate field
		fError = do_validate(field, fNoTrim, fFirstTime, fChanged);
		
		//always process dependents even when an error
		//so that parent depends reset to blank
		process_depends(field);
	}
	else
	{
		field_highlight(field,false);
		if (fFirstTime) process_depends(field);
	}
	return fError;
}

function process_depends(field)
{
	var fDepend;
	fDepend = window['field_depend_' + name_and_cid(field)];
	if (fDepend != undefined) fDepend(field);
}

function process_disabled(field)
{
	if (window.oEnableConditions != undefined && oEnableConditions[name_and_cid(field)] != undefined)
	{
		return process_enable_conditions(field);
	}
	else
	{
		var fDisabled;
		fDisabled = window['field_disabled_' + name_and_cid(field)];
		if (fDisabled != undefined)
		{
			fDisabled(field);
			return true;
		}
		else
			return false;
	}
}
function process_enable_conditions(field)
{
	if (window.oEnableConditions == undefined) return;

	var result = { condition : null, allow_hide : false };

	result = check_enable_conditions(field, oEnableConditions[name_and_cid(field)].conditions, result)
	
	if (result.condition == null)
	{
		//enabled
		set_enabled(field, true);
		return false;
	}
	else
	{
		//disabled
		set_enabled(field,  false, result.condition.reason, result.allow_hide);
		//set_enabled(field,  false, result.condition.reason, false);
		return true;
	}
}	

// these are global for "eval"
var depend_field, depend_value, check_field;

function check_enable_conditions(field, oConditions, result, fProcessAll)
{
	var depend_field_type;
	var id = field.id;
	var fOk, fHide, fStop;
	for (var i = 0; i < oConditions.length; i++)
	{
		fOk = false;
		if (oConditions[i].length != undefined)
		{
			//process a bunch of or conditions, only 1 needs to be true
			// use a local result so as not to overwrite the main one with a failure
			// which is then corrected
			var or_result = { condition : null, allow_hide : false };
			result = check_enable_conditions(field,oConditions[i], or_result,true);
			if (or_result.condition != null)
			{
				//if a condition failed, return failing condition
				result = or_result;
			}
		}
		else
		{
			//assume condition will pass
			fOk = true;
			//will we hide the field if a condition fails?
			fHide = true;
			//will we stop if a condition fails?
			fStop = true;
			
			if (oConditions[i].type == 'field-done')
			{
				fOk = eval(oConditions[i].condition);
			}
			else
			{
				depend_field = related_field(field,oConditions[i].name);
				
				if (oConditions[i].type != 'tab' && oConditions[i].type != 'disabled-field')
				{
					depend_field_type = get_field_type(depend_field);
					//based on a field that is disabled
					if (!IsEnabled(depend_field, depend_field_type)) 
					{
						fOk = false;
						//keep trying to find a better reason to fail
						fStop = false;
					}
				}
				if (fOk)
				{
					fHide = true;
					depend_value = get_field_value(depend_field,true); 
					switch(oConditions[i].type)
					{
						case 'tab':
							fOk = depend_field.checked;
							fHide = false;
							break;
						case 'field':
						case 'disabled-field':
							check_field = field;
							fOk = eval(oConditions[i].condition);
							//don't hide (still disable) if the depend is required
							if (!fOk && !eval(oConditions[i].hide_condition))
							{
								fHide = false;
								//if we are not going to hide the field because of this failure, keep checking to
								//get a more definitive failure
								fStop = false;
							}
							break;
						case 'parent':
							fOk = (depend_value != NULL_VALUE);
							//don't hide (still disable) if the parent is required
							if (oConditions[i].is_required)
							{
								fHide = false;
								//if we are not going to hide the field because of this failure, keep checking to
								//get a more definitive failure
								fStop = false;
							}
							break;
					}
				}
			}
			if (!fOk) 
			{
				//Also if this is a bunch of "ors" then keep going (only 1 of them has to be true)
				if (fProcessAll) 
					fStop = false;
					
				//save or overwrite with this condition that has failed
				if (!result.allow_hide)
				{
					result.condition = oConditions[i];
					//field can be hidden based on this failure
					if (fHide) result.allow_hide = true;
				}
				
				//either stop or carry on
				if (fStop)
				{
					break;
				}			
			}
			else
			{
				if (fProcessAll) 
				{
					//one of the or conditions is ok, so clear the error found
					result.condition = null;
					break;
				}
			}
		}
	}
	return result;
}

function do_validate(field,fNoTrim,fFirstTime, fChanged)
{
	var fError = false;

	//if the field has not changed since the initial value at last post then preserve any error
	fChanged = check_field_changed(field,fFirstTime);
	if (fFirstTime)
	{
	
		if (!fChanged)
		{
			var post_value = elementFromid(field.id + '_v');
			if (post_value != undefined) post_value.value = '[unset]';
			if (get_field_error(field) != null)
				fError = true;
		}
	}
	
	//validate
	if (!fError)
	{
		var oValidate = window['field_val_' + name_and_cid(field)];
		if (oValidate != undefined)
			fError = oValidate(field,fNoTrim,fChanged);
	}
			
	//set correct field highlighting to indicate changes
	field_highlight(field,fChanged);

	// clear error field
	if (!fError)
	{
		clear_field_error(field);
		var clr_field = elementFromid(field.id + '_clr');
		if (clr_field != null) 	cp_colour_set(field.id, '#' + field.value);
	}
	return fError;
}
function field_highlight(field,fChanged)
{
	var highlight = null;
	switch (get_field_type(field))
	{
		case 'ajax':
			highlight = elementFromid(field.id + '_ajx');
			break;
		case 'multi':
			highlight = elementFromid(field.id + '_sel');
			break;
		case 'list':
			highlight = elementFromid(field.id + '_txt');
			break;
		case 'file':
			break;
		case 'dd_date','html':
			break;
		default:
			//'date';
			//'text';
			//'dropdown';
			highlight = field;
	}
	if (highlight == null) return

	var sClass = 'input_field';
	if (fChanged)
		highlight.className = sClass + '_changed';
	else
		highlight.className = sClass;
}
         
function IsRequired(depend)
{
	return elementFromid(depend.id + '_err').innerHTML.startsWith('must be entered');
}

function IsEntered(field)
{
	//var control = focus_control(field);
	//if (control != null && control.disabled)
	//	return false;

	var value = get_field_value(field);
	return value != '' && value != NULL_VALUE && value != null_text_value();
}

function get_field_title(name)
{
	var title = elementFromid(name + '_title');
	if (title != null)
	{
		if (title.type == 'hidden')
			return title.value;
		else
			return title.innerHTML;
	}
	return '';
}

function get_field_title2(field)
{
	var title = elementFromid(name_and_cid(field) + '_title');
	if (title != null)
	{
		if (title.type == 'hidden')
			return title.value;
		else
			return title.innerHTML;
	}
	return '';
}

function get_span_value(id)
{
	var span = elementFromid(id);
	if (span != undefined)
	{	
		return span.innerHTML;
	}
	return '';
}

//fCompare - return a value that is comparable
function get_field_value(field, fCompare)
{
	if (field.type == 'radio')
	{
		return get_checked_option(field.form[field.name]).value;
	}
	else if (field.type == 'checkbox')
	{
		if (field.form[field.name].length != undefined)
			return get_checked_option(field.form[field.name]).value;
		else if (field.checked)
			return "True";
		else
			return "False";
	}
	else if (field.value == '')
		return NULL_VALUE;
		
	var value = field.value;
	
	if (fCompare)
	{
		var field_type = get_field_type(field);	
		if (field_type == 'date')
		{
			var format = elementFromid(field.id + '_format').value;
			value = text_from_date(date_from_text(value, format),'yyyy-MM-dd hh:nn:ss');
		}
	}
	
	//else if (field.type == 'textarea')
	//	return field.value.replace(/\r/g,',').replace(/\n/g,'');

	//if (field_type == 'html')
	//	return tinyMCE.get(field.id).getContent();
	//else		
	return value;
}


//field value set by a dependee changing
function set_field_value(field,value,text_value)
{
	var fChanged = false;
	var id = field.id;
	if (field.type == 'checkbox')
	{
		if (field.checked && value != 'True')
		{
			if (value == 'True')
				field.checked = true;
			else
				field.checked = false;
			fChanged = true;
		}
	}
	else 
	{
		var field_type = get_field_type(field);
		if (field.value != value)
		{
			//set text field
			switch (field_type)
			{
				case 'ajax':
					
					var text_field = elementFromid(id + '_ajx');
					if (value == NULL_VALUE)
					{
						text_value = dd_null_text[id];	
					}
					else
					{
						var sel = elementFromid(id + '_sel');
						var i = locate_select_item(sel, value,text_value);
						if (i != -1)
						{
							//var new_option = add_select_option(field.options,i,value,text);
						
							// add value to options						
							add_option_to_group(sel, value, text_value, i, 0)
							sel.selectedIndex = i;	
						}							
						//mark json as invalid
						//dd_criteria[id] = '[force]';
						//cmb_sync(id);
						//dd_ismore[id] = true;
						//cmb_reset(id);
					}
					text_field.value = text_value;
					
					//store a copy of the last valid text set
					dd_valid_text[id] = text_value;

					break;
				case 'list':
					var text_field = elementFromid(id + '_txt');
					if (value == NULL_VALUE) text_value = null_text_value();
					text_field.value = text_value;

					break;
				case 'multi':
					var sel = elementFromid(id + '_sel');
					if (value == NULL_VALUE)
						multi_delete_all(sel);
					else
						add_select_items(sel,value,text_value);
					//rebuild hidden multi value
					value = get_multi_select_value(sel,true);
					if (value == '') value = NULL_VALUE;
					break;
				case 'dd_date':
					var dd_field;
					var DateParts = new Array();
					var strFormatMask = elementFromid(id + '_format').value;
					dateparts_from_mask(value, strFormatMask, DateParts);
					dd_field = elementFromid(id + '_dd');
					if (dd_field != null) dd_field.value = DateParts[2];
					dd_field = elementFromid(id + '_MM');
					if (dd_field != null) dd_field.value = DateParts[1];
					dd_field = elementFromid(id + '_yyyy');
					if (dd_field != null) dd_field.value = DateParts[0];
					dd_field = elementFromid(id + '_xx');
					if (dd_field != null) dd_field.value = DateParts[1] + '/' + DateParts[0];
					dd_field = elementFromid(id + '_HH');
					if (dd_field != null) dd_field.value = DateParts[3];
					dd_field = elementFromid(id + '_nn');
					if (dd_field != null) dd_field.value = DateParts[4];
					dd_field = elementFromid(id + '_ss');
					if (dd_field != null) dd_field.value = DateParts[5];
					field.value = value;
					break;
				case 'dropdown':
					//add new option
					add_select_item(field,value,text_value);
					break;
				case 'text':
				case 'date':
					if (value == NULL_VALUE) value = '';
					break;
			}
			field.value = value;
			fChanged = true;
		}
	}

	if (fChanged) 
	{
		//field value has changed, field could be disabled
		//needs to be validated, and so do all dependents	
		validate_field(field, false, false,true);
	}
}

function get_original_field(field)
{
	var id = field.id;

	if (field.type == 'radio' || field.type == 'checkbox' && get_field_type(field) == 'status')
		id = get_stem(field.id);
		
	return elementFromid(id + '_o');
}

// get focus control for a field
function focus_control(field)
{
	var focus_field;
	switch(get_field_type(field))
	{
		case 'dd_date':
			var format_field = elementFromid(field.id + '_format');
			focus_field = elementFromid(field.id + '_' + format_field.value.split_any('/ :')[0]);
			break;
		case 'file':
			if (field.type == 'hidden')
				focus_field = elementFromid(field.id + '_but');
			else
				focus_field = field;
			break;
		case 'multi':
		case 'list':
			focus_field = elementFromid(field.id + '_but');
			break;
		case 'ajax':
			focus_field = elementFromid(field.id + '_ajx');
			break;
		case 'html':
			return null;
			break;
		case 'dropdown':
			if (field.options.length == 1)
			{
				focus_field = elementFromid(field.id + '_new');
				if (focus_field == null)
					focus_field = elementFromid(field.id + '_edt');
				if (focus_field == null)
					focus_field = field;
			}
			else
				focus_field = field;
			break;
		case 'status':
			var options = field.form[field.name];
			
			for(var i = 0; i < options.length; i++)
			{
				if (options[i].defaultChecked)
				{
					if (i == options.length - 1)
					{
						if (i > 0)
							i -= 1;
						else
							return null;
					}
					i += 1;
					break;
				}
			}
			if (i < options.length)
				return options[i];
				//return elementFromid(options[i].id + '_label');
			break;
		default:
			focus_field = field;
	}
	return focus_field;
}



function BaseFieldName(field)
{
	var name = field.name;
	
	if (name.endsWith('_o')) 
	{
		name = name.removeEnd(2);
		return name;
	}
	switch(name.right(3))
	{
		case '_xx':
		case '_dd':
		case '_MM':
		case '_yy':
		case '_HH':
		case '_nn':
		case '_ss':
			name = name.removeEnd(3);
			return name;
			break;
	}

	switch(name.right(4))
	{
		case '_ifr':
		case '_ajx':
		case '_txt':
		case '_sel':
		case '_but':
		case '_new':
		case '_edt':
		case '_del':
			name = name.removeEnd(4);
			return name;
			break;
	}
	switch(name.right(5))
	{
		case '_type':
		case '_yyyy':
		case '_file':
			name = name.removeEnd(5);
			return name;
			break;
	}
	return name;
}
//function BaseFieldName(field)
//{
//	return get_stem(elementFromid(BaseFieldId(field.id)).name);
//}
//function BaseColumnName(field)
//{
//	var name = BaseFieldName(field);
//	return name.substring(3,20);
//}


//VALIDATION
function val_email(text) 
{
	var inString = new String(text.value);
	if (inString.length > 0)
	{
		if (text.type == 'textarea')
		{
			var email;
			var emails = inString.split('\n');
			for(var i=0; i < emails.length; i++)
			{
				email = emails[i].replace(/\r/,'')
				if (!val_single_email(text,email))
				{
					if (emails.length > 1)
					{
						var div = elementFromid(text.id + '_err');
						div.innerHTML += ' for email ' + email;
					}
					return false;
				}
			}
		}
		else
			return val_single_email(text,inString);
	}
	return true;
}
function val_single_email(text,email)
{
	var items,fValid;
	fValid = true;
	items = email.split('@');
	if (items.length != 2) fValid = false;
	if (fValid) fValid = val_domain(items[0]);
	if (fValid) fValid = val_domain(items[1],2);
	if (!fValid)
	{
		set_field_error(text,"invalid email address");
		return false;
	}
	return true;
}

function val_ip(text) 
{
	var inString = new String(text.value);
	if (inString.length > 0)
	{
		if (text.type == 'textarea')
		{
			var ip;
			var ips = inString.split('\n');
			for(var i=0; i < ips.length; i++)
			{
				ip = ips[i].replace(/\r/,'')
				if (!val_single_ip(text,ip))
				{
					if (ips.length > 1)
					{
						var div = elementFromid(text.id + '_err');
						div.innerHTML += ' for address ' + ip;
					}
					return false;
				}
			}
		}
		else
			return val_single_ip(text,inString);
	}
	return true;
}
function val_single_ip(text,ip)
{
	var items, fValid, error, value;

	items = ip.split('.');
	error = ''

	if (items.length != 4) 
	{
		error = "must have 4 bytes";
	}
	else
	{
		for (var i = 0; i < items.length; i++)
		{
			if (items[i] == '')
			{
				error = 'must be entered';
				break;
			}
			
			var error = is_numeric(items[i],0);
			
			if (error != '') break;

			value = parseInt(items[i]);
			if (value < 0 || value > 255)
			{
				error = "must be between 1 and 255";
				break;
			}
		}
		if (error !='') error = 'each byte ' + error;
	}
	if (error != '')
	{
		set_field_error(text,error);
		fValid = false;
	}
	else
	{
		fValid = true;
	}
	return fValid;
}

function val_password(text) 
{
	var pass;
	var text;
	if (text.id.indexOf('_confirm') != -1)
	{
		pass = text.form[text.id.replace(/_confirm/g,'')];
		conf = text;
	}
	else
	{
		conf = related_field(text,get_stem(text.name) + '_confirm');
		pass = text;
		//do_validate(conf);
		//return true;
	}	
			
	if (pass.value != conf.value)
	{
		set_field_error(conf, "passwords do not match");
		return false;
	}
	return true;
}
function val_domain(text,j)
{
	var items,i;
	items = text.split('.');
	if (j != undefined && items.length < j) return false;
	for(i=0; i < items.length; i++)
	{
		if (items[i].length == 0) return false;
		// can only be alphanumeric
		if (!/^[a-zA-Z0-9\-_]+$/.test(items[0])) return false;
		//can't start with _ or -
		if (/^[\-_]$/.test(items[0][0])) return false;
		if (/^[\-_]$/.test(items[0][items[0].length - 1])) return false;
	}
	return true;
}

function val_hex(text)
{
	var regexp = /^[a-fA-F0-9]*$/;
	if (!regexp.test(text.value))
	{
		set_field_error(text,"invalid hex value");
		return false;
	}
	return true;
}
function val_url(text) 
{
	var inString = new String(text.value);
	if (inString.length > 0)
	{
		var fValid;
		
		fValid = val_domain(inString,2);

		if (!fValid)
		{
			set_field_error(text,"invalid web address");
			return false;
		}
	}
	return true;
}
function val_tele(text) 
{
	var inString = new String(text.value);
	if (inString.length > 0)
	{
		var regexp = /^\+?[0-9\-() ]*$/;
		if (!regexp.test(inString))
		{
			set_field_error(text,"invalid telephone number");
			return false;
		}
	}
	return true;
}

function val_word(text) 
{
	var inString = new String(text.value);
	if (inString.length > 0)
	{
		for (var i = 0;i < inString.length;i++)
		{
			if (inString.charAt(i) == ' ')
			{
				set_field_error(text,"cannot contain spaces");
				return false;
			}
		}
	}
	return true;
}

function val_textarea_size(textarea,min_len,max_len)
{
		
	if (textarea.value.length > max_len)
	{
		//set_field_error(textarea,"may only contain " + max_len + " characters");
		textarea.value = textarea.value.substring(0, max_len);
		return false;
	}
	return true;
}

function val_ensure_filled(text)
{
	var inString = new String(text.value);

	if (inString.length != 0 && inString.length != text.maxLength)
	{
		set_field_error(text,"must contain " + text.maxLength + " characters");
		return false;
	}
	return true;
}
function trim_field(s, sub_type) 
{
	switch (sub_type)
	{
		case 'A':
		case 'C':
		case 'E':
		case 'L':
		case 'U':
		case 'M':
		case 'W':
		case 'X':
			s.value = s.value.replace(/ /,'');
		default:
			s.value = s.value.trim();
	}
}
function trim(s) 
{
	s.value = s.value.trim();
}
function val_text_entered(field)
{
	if (!IsEntered(field))
	{
		set_field_error(field,"must be entered");
		return false;
	}
	return true;
}

function val_number(text,MaxDecPlaces) 
{
	var inString = text.value;
  	var refString = "1234567890.";
	var boolDpFound = false;
	var DPlacesCount = 0;
	var strError;
	
	if (text.value != '')
	{
		strError = is_numeric(text.value,MaxDecPlaces);
		if (strError != '')
		{
			set_field_error(text, strError);
			return false;
		}
		
		var min = elementFromid(text.id + '_min');
		if (min != null)
		{
			if (Number(text.value) < Number(min.value))
			{
				set_field_error(text,"cannot be less than " + min.value);
				return false;
			}
		}
		
		var max = elementFromid(text.id + '_max');
		if (max != null)
		{
			if (Number(text.value) > Number(max.value))
			{
				set_field_error(text,"cannot be greater than " + max.value);
				return false;
			}		
		}
  	}

	return true;
}

function is_numeric(inString,MaxDecPlaces)
{
		
	var boolDpFound = false;
	var DPlacesCount = 0;
	var tempChar;
  	var refString = "-1234567890";

  	for(var count=0; count < inString.length; count++)
  	{
 		tempChar = inString.charAt(count);
	 	
	 	//minus sign can only be first character
	 	if (count == 1)
	 		refString = refString.substring(1);
		
	 		
		// once decimal point is past count up the number of decimal places	
		if (boolDpFound)
		{
			DPlacesCount += 1;
			
			// cannot exceed maximum
			if (DPlacesCount > MaxDecPlaces)
			{
				return "may only have " + MaxDecPlaces + " decimal places";
			}
		}

		//Note when decimal point found & make sure there is only one
 		if (tempChar == ".")
 		{
 			if (boolDpFound)
				return "has two decimal points";
				
			if (count == 0 || count == 1 && inString.substring(0,1) == '-')
				return "decimal points must be preceeded by a number";
	 	
			boolDpFound = true;
		}
		else
		{
			// must be numeric
			if(refString.indexOf(tempChar, 0) == -1)
			{
				return "must be numeric";
  			}
		}
	}
	if (boolDpFound && DPlacesCount == 0) 
		return "no number after decimal point";
	
	return '';
}

function val_minutes(text) 
{
	if (text.value == '') return true;
	var inString = new String(text.value);
	var i = inString.indexOf(':');
	
	var strTime;
	if (i == -1)
	{
		set_field_error(text, 'invalid format');
		return false;
	}
	else
	{
		var strError = is_numeric(inString.substring(0,i - 1),0);
		if (strError != '') 
		{
			set_field_error(text, 'hours are not numeric');
			return false;
		}
		var minutes = inString.substring(i+1,i+3);
		strError = is_numeric(minutes,0);
		if (strError != '') 
		{
			set_field_error(text, 'minutes are not numeric');
			return false;
		}
		if (Number(minutes) > 59)
		{
			set_field_error(text, 'minutes must be 0-59');
			return false;
		}
		var min = elementFromid(text.id + '_min')
		if (min != null)
		{
			if (TimeToNumber(text.value) < TimeToNumber(min.value))
			{
				set_field_error(text,"cannot be less than " + min.value);
				return false;
			}
		}
		
		var max = elementFromid(text.id + '_max')
		if (max != null)
		{
			if (TimeToNumber(text.value) > TimeToNumber(max.value))
			{
				set_field_error(text,"cannot be greater than " + max.value);
				return false;
			}		
		}
	}
	return true;
}
function TimeToNumber(value)
{
	var i = value.indexOf(':');
	return Number(value.substring(0,i)) * 60 + Number(value.substring(i+1));
}
function val_range(field,min,max,fMoveEnd)
{
	if (field.value == '') return true;
	var field_type = get_field_type(field);
	var StartValue;
	var EndValue;
	var start_field_value;
	var end_field;
	var boolAllowEndChange = false;
	
	if (field.id.indexOf('_start') != -1)
	{
		start_field_value = field.value;
		end_field = elementFromid(field.id.replace(/_start/,'_end'));
		if (end_field.value == '') return true;
		boolAllowEndChange = true;
	}
	else
	{
		start_field_value = field_value_from_id(field.id.replace(/_end/,'_start'));
		end_field = field;
	}
	 
	var min_text, max_text;

	if (field_type == 'text')
	{
		StartValue = Number(start_field_value);
		EndValue = Number(end_field.value);
		min_text = min;
		max_text = max;
	}
	else
	{
		var strFormatMask = elementFromid(field.id + '_format').value;
		EndValue = date_from_text(end_field.value, strFormatMask);
		StartValue = date_from_text(start_field_value, strFormatMask);

		if (min != null)
		{
			min = date_from_text(min, strFormatMask).getTime() + base_date_offset();
			min_text = date_as_range(min);
		}
		if (max != null)
		{
			max = date_from_text(max, strFormatMask).getTime() + base_date_offset();
			max_text = date_as_range(max);
		}
	}
	if (StartValue > EndValue)
	{
		if (last_field != null && field.id == last_field.id.substr(0, field.id.length) && boolAllowEndChange)
		{
			//if (min != null)

			set_field_value(end_field,start_field_value);
			if (field_type == 'text')
				EndValue = Number(end_field.value);
			else
				EndValue = date_from_text(end_field.value, strFormatMask);
		}
		else
		{
			set_field_error(end_field, "end must be after start");
			return false;
		}
	}
	
	if (min != null)
	{
		if ((EndValue - StartValue) < min)
		{
			set_field_error(end_field,"cannot cover less than " + min_text);
			return false;
		}
	}
	if (max != null)
	{
		if ((EndValue - StartValue) > max)
		{
			set_field_error(end_field,"cannot cover more than " + max_text);
			return false;
		}
	}
	return true;
}

function base_date_offset()
{
	return - (new Date('Sat Dec 30 00:00:00 UTC 1899').getTime());
}
function date_as_range(d)
{
	var i, s = '', one_day=1000*60*60*24;

	i = Math.floor(d / one_day);
	if (i > 0) 
	{
		s = i + ' day';
		if (i > 0) s += 's';
	}
	
	d -= i * one_day;
	i = Math.floor(d / (1000*60*60));
	if (i > 0) 
	{
		if (s != '') s += ' ';
		s += i + ' hour';
		if (i > 1) s += 's';
	}
	
	d -= i * 1000*60*60;
	i = Math.floor(d / 60);
	if (i > 0) 
	{
		if (s != '') s += ' ';
		s += i + ' minute';
		if (i > 1) s += 's';
	}
	return s;	
}
function val_date(text)
{
	var strFormatMask = elementFromid(text.id + '_format').value;
	return val_date_format(text,strFormatMask);
}
function val_date_format(text,strFormatMask)
{
	if (text.value == '' || text.value == NULL_VALUE) return true;
	if (!val_date_mask(text,strFormatMask)) return false;

	var DateParts = new Array();
	if (!dateparts_from_mask(text.value,strFormatMask,DateParts))
	{
		set_field_error(text,"invalid format");
		return false;
	}
	var iValid;
	if (strFormatMask != 'HH:nn')
	{
		iValid = isdate(DateParts[2], DateParts[1], DateParts[0]);
		if (iValid != 0)
		{
			if (iValid == 1) set_field_error(text,"invalid day");
			if (iValid == 2) set_field_error(text,"invalid month");
			if (iValid == 3) set_field_error(text,"invalid year");
			return false;
		}
	}
	iValid = istime(DateParts[3], DateParts[4], DateParts[5]);
	if (iValid != 0)
	{
		if (iValid == 1) set_field_error(text,"invalid hour");
		if (iValid == 2) set_field_error(text,"invalid minute");
		if (iValid == 3) set_field_error(text,"invalid second");
		safe_focus(text);
		return false;
	}

	var DateVal = new Date(DateParts[0], DateParts[1] - 1, DateParts[2], DateParts[3], DateParts[4], DateParts[5]);
	
	if (DateVal != '')
	{
		var check_date, range_field;
		
		range_field = elementFromid(text.id + '_min');
		if (range_field != null)
		{
			check_date = date_from_mask(range_field.value, strFormatMask);
			if (DateVal.valueOf() < check_date.valueOf())
			{
				set_field_error(text,"cannot be before " + range_field.value);
				return false;
			}
		}
		
		range_field = elementFromid(text.id + '_max');
		if (range_field != null)
		{
			check_date = date_from_mask(range_field.value, strFormatMask);
			if (DateVal.valueOf() > check_date.valueOf())
			{
				set_field_error(text,"cannot be after " + range_field.value);
				return false;
			}
		}
	}
	return true;
}
function text_from_date(date,mask)
{
	if (mask.indexOf('yyyy') != -1)
		mask = mask.replace(/yyyy/, date.getFullYear());
	else if (mask.indexOf('yy') != -1)
		mask = mask.replace(/yy/, new String(date.getFullYear()).substring(2));
	if (mask.indexOf('MM') != -1) mask = mask.replace(/MM/, NumberAsText(date.getMonth() + 1,2));
	if (mask.indexOf('dd') != -1) mask = mask.replace(/dd/, NumberAsText(date.getDate(),2));
	if (mask.indexOf('hh') != -1) mask = mask.replace(/hh/, NumberAsText(date.getHours(),2));
	if (mask.indexOf('nn') != -1) mask = mask.replace(/nn/, NumberAsText(date.getMinutes(),2));
	if (mask.indexOf('ss') != -1) mask = mask.replace(/ss/, NumberAsText(date.getSeconds(),2));
	return mask;	
}
function date_from_text(text,strFormatMask)
{
		var DateParts = new Array();
		dateparts_from_mask(text,strFormatMask,DateParts);
		return new Date(DateParts[0], DateParts[1] - 1, DateParts[2], DateParts[3], DateParts[4], DateParts[5]);
}
function val_date_mask(text,strFormatMask)
{
	var strText = new String(text.value);
	var strChar;
	var FormatMask = new String(strFormatMask);
	var iValid = 0;

	if (strText == "")
	{
		return true;
	}
	if (strText.length != FormatMask.length)
	{
		set_field_error(text,"invalid format");
		return false;
	}

	for(var i=0; i < FormatMask.length; i++)
	{
		strChar = FormatMask.charAt(i).toLowerCase();
		if (strChar != 'd' && strChar != 'm' && strChar != 'y' && 
			strChar != 'h' && strChar != 'n' && strChar != 's')
		{
			if (strText.charAt(i) != strChar)
			{
				set_field_error(text,"invalid format");
				return false;
			}
		}
	}
	return true;
}


function istime(h, n, s)
{
	var iValid = 0;
	if (!is_positive_integer(h))
		iValid = 1;
	else if (!is_positive_integer(n))
		iValid = 2;
	else if (!is_positive_integer(s))
		iValid = 3;
	else
	{
		h = Number(h);
		n = Number(n);
		s = Number(s);

		if (h < 0 || h > 23 ) 
			iValid = 1;
		else if (n < 0 || n > 59)
			iValid = 2;
		else if (s < 0 || s > 59)
			iValid = 3;
	}
	return iValid;
}

function isdate(d, m, y)
{
	var iValid = 0;
	if (d != null && !is_positive_integer(d))
		iValid = 1;
	else if (m != null && !is_positive_integer(m))
		iValid = 2;
	else if (y != null && !is_positive_integer(y))
		iValid = 3;
	else
	{
		if (d != null) d = Number(d);
		if (m != null) m = Number(m);
		if (y != null) y = Number(y);
		
		if (d != null && m != null)
		{
			switch (m)
			{
				case 1:
				case 3:
				case 5:
				case 7:
				case 8:
				case 10:
				case 12:
        			if ((d < 1) || (d > 31)) iValid = 1;
        			break;
				case 4:
				case 6:
				case 9:
				case 11:
					if ((d < 1) || (d > 30)) iValid = 1;
					break;
				case 2:
					if (y != null && ((y % 4) == 0) & (((y % 100) != 0) || ((y % 400) == 0)))
					{
						if ((d < 1) || (d > 29)) iValid =1;
					}
					else
					{
						if ((d < 1) || (d > 28)) iValid = 1;
					}
					break;
				default:
					// Invalid month
					iValid = 2;
			}
		}
		if (y != null && (y < 1850 || y > 2100))
		{
			// Invalid year
			iValid = 3;
		}
	}
	return iValid;
}

function date_only(date_in)
{
	date_in.setHours(0);
	date_in.setMinutes(0);
	date_in.setSeconds(0);
	date_in.setMilliseconds(0);
	return date_in;
}


function val_card(text, card_type)
{
	text.value = text.value.replace(/ /g,'');
	if (text.value == '') return true;
	if (!val_number(text,0)) return false;
	if (card_type != undefined)
	{
		var Card = card_check(text.value, card_type.value);
		if (Card[0] != '')
			text.value = Card[0];		

		if (!Card[1])
		{
			set_field_error(text,"invalid card number");
			return false;
		}
	}
	return true;
}

function card_check(strCC,CardType)
{
	
	// Returns array - "Card"
	// 0 - formatted card number
	// 1 - valid; true/false
	// 2 - card mask found

	var Card = new Array(4);

	Card[0] = '';
	Card[1] = false;
	
	switch (CardType)
	{
		case 'S':
			// Switch or Solo
			card_mask("6***** *************", strCC, Card);
			card_mask("6***** ************", strCC, Card);
			card_mask("6***** ***********", strCC, Card);
			card_mask("6***** **********", strCC, Card);
			card_mask("6***** *********", strCC, Card);
			card_mask("6***** ********", strCC, Card);
			card_mask("6***** *******", strCC, Card);
			card_mask("5***** *************", strCC, Card);
			card_mask("5***** ************", strCC, Card);
			card_mask("5***** ***********", strCC, Card);
			card_mask("5***** **********", strCC, Card);
			card_mask("5***** *********", strCC, Card);
			card_mask("5***** ********", strCC, Card);
			card_mask("5***** *******", strCC, Card);
			if (Card[1]) Card[1] = luhn_check_digit(Card[0]);
			break;	
			
		case 'V':
			// Visa
			card_mask("4*** **** **** ****", strCC, Card)
			card_mask("4*** **** **** *", strCC, Card);
			if (Card[1]) Card[1] = luhn_check_digit(Card[0]);
			break;
		case 'A':
			// Amex
			card_mask("37** **** **** ***", strCC, Card);
			card_mask("34** **** **** ***", strCC, Card);
			if (Card[1]) Card[1] = amex_luhn_check_digit(Card[0]);
			break;
		case 'M':
			// Master card
			card_mask("5*** **** **** ****", strCC, Card);
			if (Card[1]) Card[1] = luhn_check_digit(Card[0]);
			break;
		case 'D':
			// Diners club
			card_mask("36** **** **** **", strCC, Card);
			card_mask("38** **** **** **", strCC, Card);
			card_mask("300* **** **** **", strCC, Card);
			card_mask("301* **** **** **", strCC, Card);
			card_mask("302* **** **** **", strCC, Card);
			card_mask("303* **** **** **", strCC, Card);
			card_mask("304* **** **** **", strCC, Card);
			card_mask("305* **** **** **", strCC, Card);
			card_mask("4*** **** **** ****", strCC, Card);
			break;
	}

	return Card;
}
		
function card_mask(FormatMask, StringIn, Card)
{
	// if card already found, don't process
	if (Card[1])
		return;

	// format credit card number
	var sFormattedCC = new String("");
	var i = 0, j = 0
	for(; i < FormatMask.length; i++)
	{
		// skip over spaces
		for( ;  j < StringIn.length; j++)
		{
			if (StringIn.charAt(j) != " ")
				break;
		}
		if (FormatMask.charAt(i) == " ")
			sFormattedCC += " ";
		else
		{		
			if (FormatMask.charAt(i) != "*")
			{
				if (FormatMask.charAt(i) != StringIn.charAt(j))
				{
					return;
				}
			}
			sFormattedCC +=	StringIn.charAt(j);
			j++;
			if (j >= StringIn.length)
				break;
		}
	}

	// card mask is valid
	if (sFormattedCC.length == FormatMask.length && j == StringIn.length )
	{
		// card mask found
		Card[0] = sFormattedCC;
		Card[1] = true;
	}
	return;
}
function amex_luhn_check_digit(strCC)
{
	var i,j;
	var strCheck = new String("");
	
	for(i=0,j=0;i < strCC.length;i++)
	{
		if (strCC.charAt(i) != " ")
		{
			if (j % 2 == 1)
			{
				strCheck += Number(strCC.charAt(i)) * 2;
			}
			else
			{
				strCheck += Number(strCC.charAt(i));
			}
			j++;
		}
	}
	var iCheck = 0;
	for(i=0; i < strCheck.length; i++)
	{
		iCheck += Number(strCheck.charAt(i));
	}
	if (iCheck % 10 == 0)
		return true;
	else
		return false;
}
function luhn_check_digit(strCC)
{
	var i,j;
	var strCheck = new String("");
	
	for(i=0,j=0;i < strCC.length;i++)
	{
		if (strCC.charAt(i) != " ")
		{
			iMult = ((j+1) % 2) + 1;
			strCheck += Number(strCC.charAt(i)) * iMult;
			j++;
		}
	}
	var iCheck = 0;
	for(i=0; i < strCheck.length; i++)
	{
		iCheck += Number(strCheck.charAt(i));
	}
	if (iCheck % 10 == 0)
		return true;
	else
		return false;
}

