var curr_updates = new Array();
var curr_updates_lookup = new Object();
//var toggled_deletes = new Array();
//var toggled_deletes_lookup = new Object();
var toggled_deletes = new Object();
var tracked_fld_names = new Object();
var fields_needing_pre_save = new Object();
var pre_save_request = new Object();
var field_list

function field_needs_pre_save(tbl, fld, type, opt_params) {
	//fields_needing_pre_save[tbl + '_' + fld] = [type, opt_params];
	fields_needing_pre_save[tbl + '_' + fld] = [type, opt_params];
}
function possible_pre_save(tbl, fld, id, new_value) {
	if (!fields_needing_pre_save[tbl + '_' + fld]) return false;
	pre_save_request[tbl + '_' + fld] = new Array(tbl, fld, id, new_value);
	return true;
}

function build_pre_save_request() {
	var retStr='';
	for (obj_key in pre_save_request) {
		var obj = pre_save_request[obj_key];
		//retStr += '<CHECK type="' + fields_needing_pre_save[obj_key] + '" field="' + obj[1] + '" id="' + obj[2] + '" value="' + obj[3] + '"/>';
		retStr += fields_needing_pre_save[obj_key][0].replace('"', '""') + '("' + obj[0].replace('"', '""') + '", "' + obj[1].replace('"', '""') + '", "' + obj[2].replace('"', '""') + '", "' + obj[3].replace('"', '""') + '"';
		for (var j=0; j < fields_needing_pre_save[obj_key][1].length; j++) {
			retStr += ',"' + fields_needing_pre_save[obj_key][1][j] + '"'
		}
		retStr += ')\';';
	}
	
	return retStr;
	//return 'test';
}
function verify_pre_saves() {
	
	try {
		var str = build_pre_save_request();
		if (!str || str == '') return true;
		exec_pre_save(str);
		return false;
	} catch (e) {
		document.frmUpdate.submit();	
	}
}

function setup_update() {
	parent.doUpdate=doUpdate;
	parent.generate_update_obj = generate_update_obj;
	parent.queue_for_update_direct = queue_for_update_direct;
	parent.queue_for_update = queue_for_update;
	parent.frmUpdate = document.frmUpdate;
	parent.mark_for_deletion = mark_for_deletion;
	parent.mark_for_deletion_direct = mark_for_deletion_direct;
	parent.dump = dump;
	parent.flush_dump = flush_dump;
	parent.outstandingUpdates = outstandingUpdates;
	parent.newStyleUpdate = true;
}
function processSave(str) {
	if (parent.processSave) parent.processSave(str);
	parent.document.frmSelections.Saved.value = 1;
}
function getDeleteObj(table_name) {
	/*var base_array;
	var lookup = toggled_deletes_lookup[table_name];
	if (!lookup && lookup != 0) {
		toggled_deletes.push(base_array = new Object());
		toggled_deletes_lookup[table_name] = toggled_deletes.length - 1;
	} else {
		base_array = toggled_deletes[ lookup ];
	}*/
	var base_array = toggled_deletes[table_name];
	if (!base_array) base_array = toggled_deletes[table_name] = new Object();
	return base_array;
}
function getFldNamesObj(table_name) {
	var base_array = tracked_fld_names[table_name];
	if (!base_array) base_array =  tracked_fld_names[table_name] = new Object();
	return base_array;
}
function getTableUpdates(table_name) {
	var base_array;
	var lookup = curr_updates_lookup[table_name];
	if (!lookup && lookup != 0) {
		// if no updates for this table have occured yet, then setup the array
		curr_updates.push(base_array = new Object());
		curr_updates_lookup[table_name] = curr_updates.length - 1;
		// data will store the changes and id_lookup will allow me to find changes for a given id
		base_array['data'] = new Array();
		base_array['memo'] = new Array();
		base_array['id_lookup'] = new Object();
		base_array['name'] = table_name;
	} else {
		base_array = curr_updates[ lookup ];
	}
	return base_array;
}
var dump_store = new Array();
function flush_dump() {
		document.frmUpdate.thedump.value=dump_store.join('\n');
		dump_store = new Array();
}
function dump(str, store_only) {
	if (!parent.debug_) return;
	try {
		if (store_only)
				  dump_store.push(str);
		else
				  document.frmUpdate.thedump.value=document.frmUpdate.thedump.value + str  + '\n';
	} catch (e) {}
}
var addItemSuffix=1;
function getNextID() {
	return 'n_e_w' + addItemSuffix++;
}
function generate_update_obj(tbl, fld, id, value) {
	var obj = document.createElement('span');
	obj.setAttribute('tbl', tbl);
	obj.setAttribute('fld', fld);
	obj.setAttribute('id', id);
	obj.setAttribute('value', value);
	return obj;
}
function queue_for_update_direct(tbl, fld, id, value) {
	queue_for_update(generate_update_obj(tbl, fld, id, value));
}

function get_tbl_name(obj) {
	return get_attr_name(obj, 'tbl')
}
function get_fld_name(obj) {
	return get_attr_name(obj, 'fld')
}
function get_attr_name(obj, attr) {
	var reg_find_props = new Object();
	reg_find_props['tbl'] = new RegExp("@t=([^@]*)@", "gi");
	reg_find_props['fld'] = new RegExp("@f=([^@]*)@", "gi");
	var prop = obj.getAttribute(attr)
	if (prop) return prop;
	prop = obj.getAttribute('pkg');
	if (!prop) return 'Information';
	var matches = reg_find_props[attr].exec(prop);
	if (matches && matches[1]) return matches[1];
	return 'Information'
}

function get_field_list_array(tbl) {
	var list_ele, list_obj = getFldNamesObj(tbl);
	var list_array = new Array();
	for (list_ele in list_obj) {
		list_array.push(list_ele);
   }
	return list_array;
}
function store_fld_name(tbl, fld) {
	var list = getFldNamesObj(tbl);
	list[fld] = true;
}
function queue_for_update(obj, oldstyle, linked_recs) {
	//if (objs[j].getAttribute('deleted') = 'yes') return;
	// I don't check for checkboxes here because a condition to check for them would
	//slow down every queue. Instead, I set the value of a checkbox prior to calling
	var base_array;
	var tbl = obj.getAttribute('tbl');
	var fld = obj.getAttribute('fld');
	var pkg = obj.getAttribute('pkg');
	var pkg = '|' + (pkg ? pkg : '') + (tbl ? '@@t=' + tbl : '') + (fld ? '@@f=' + fld : '');
	if (!tbl) tbl = get_tbl_name(obj);
	if (!fld) fld = get_fld_name(obj);
	
	store_fld_name(tbl, fld);
	
	//var id = obj.getAttribute('id');
	var id = obj.getAttribute('RecID')
	if (!id||id=='@xID@') id = obj.getAttribute('id');
	var val = obj.getAttribute('value');
	 
	var found_selected = false;
	if (obj.nodeName && obj.nodeName == 'SELECT') {
		val = '';
		for (var j=0; j < obj.options.length; j++) {
			if (obj.options[j].selected == true) {
				if (val.length > 0) val += '**';
				if (!obj.options[j].value) val += obj.options[j].text; 
				else val += obj.options[j].value;
				found_selected = true
			}
		}
		if (!found_selected) val = obj.getAttribute('InitVal');
	}
	if (obj.getAttribute('save_eval')) eval(obj.getAttribute('save_eval'));
	var action = '';
	if (id.substr(0, 5) == 'n_e_w') action = '@@a=i2';
	//var str = '|' + action + (pkg ? pkg : '') + (tbl ? '@@t=' + tbl : '') + (fld ? '@@f=' + fld : '') + '@@i=' + id + '@@v2=' + val + '!#!#' + '@@|';
	if (pkg=='|') pkg='@@t=Information@@';
	var str = '|' + (pkg ? pkg : '') + action + '@@i=' + id + '@@v2=' + val + '!#!#' + '@@|';
	//alert(pkg);

	if (linked_recs)
		for (var j=0; j < linked_recs.length; j++) {
			var str2 = '|@@a=i2@@t=' + get_tbl_name(linked_recs[j]) + '@@f=' + get_fld_name(linked_recs[j]) + '@@i=' + linked_recs[j].getAttribute('id') + '@@v2=' + linked_recs[j].getAttribute('value') + '!#!#' + '@@|';
			alert(str2);
			str = str + str2;
		}
/*	if (memo) {
		var memo_id;
		var str2 = '|@@a=i2@@i=' + memo_id=getNextID() + '@@t=Memo@@f=text@@v2=' + memo + '!#!#' + '@@|';
		var str2 = '|@@a=i2@@i=' + memo_id + '@@t=Memo@@f=linkedto@@v2=' + memopage + '!#!#' + '@@|';
	}*/
	if (!tbl) tbl = 'Information';
	var base_array = getTableUpdates(tbl);
	var pos = base_array['id_lookup'][id + fld];		// look for prev changes to this item
	if (!pos && pos != 0) {
		// if no previous changes to this id, add the change to data, and add that position to the id_lookup
		base_array['data'].push(str);
		//base_array['memo'].push(memo);
		base_array['id_lookup'][id + fld] = base_array['data'].length - 1;
	} else {
		// otherwise, update the outstanding change to this item
		base_array['data'][ pos ] = str;
		//base_array['memo'][ pos ] = memo;
	}
	possible_pre_save(tbl, fld, id, val);
}
function mark_for_deletion_direct(tbl, id, fields, memo) {
	var obj = document.createElement('SPAN');
	obj.setAttribute('tbl', tbl);
	obj.setAttribute('id', id);
	//obj.setAttribute('fields', fields);
	//alert(tbl + ':' + id + ':' + fields);
	mark_for_deletion(obj, fields, memo);
}

function delete_row(tbl, obj, fields, memo) {
	while (obj.nodeName != 'TR' && obj.parentNode) obj = obj.parentNode;
	if (obj.nodeName != 'TR') return;
	mark_for_deletion(obj, fields, memo)
}

function mark_for_deletion(obj, fields, memo) {
	// this function is used when the delete removes the item from the table. No further action for this item
	//  can occur because it's data in the update table is cleared. If you were to undo the delete, it would need to
	//  find all of the inputs to restablish the current data for the id. For situations where
	//  deletes can be toggled (a checkbox to delete a row), use mark_for_delete_toggle
	var inputs, table_name, fld, id;
	if (obj.nodeName == 'TR') {
		inputs = obj.getElementsByTagName('INPUT');
		//tbl = inputs[0].getAttribute('tbl');
		tbl = get_tbl_name(inputs[0]);
		var base_array = getTableUpdates(tbl);
	} else {
		//tbl = obj.getAttribute('tbl');
		tbl = get_tbl_name(inputs[0]);
		var base_array = getTableUpdates(tbl);
		//alert('BA: ' + base_array);
		id = obj.getAttribute('RecID')
		if (!id) id = obj.getAttribute('id');
		//var fields = obj.getAttribute('fields').split(',');
		fields = get_field_list_array(tbl);
		for (var j=0; j < fields.length; j++){
			fld = fields[j];
			//alert('F' + fld);
			var pos = base_array['id_lookup'][id + fld];
			if (pos || pos == 0) {
				//alert('found it: ' + id + fld);
				base_array['data'][ pos ] = null;
				base_array['memo'][ pos ] = null;
				base_array['id_lookup'][id + fld] = null;
			}
		}
		// if this is a new item, it is sufficient to remove the add instructions
		//if (id.substr(0, 5) == 'n_e_w') return;
	}
	//var base_array = getTableUpdates(tbl);
	if (inputs) {
		for (var j=0; j < inputs.length; j++) {
			id = inputs[j].getAttribute('RecID')
			if (!id) id = inputs[j].getAttribute('id');
			//var fld = inputs[j].getAttribute('field');
			var fld = get_fld_name(inputs[j]);
			var pos = base_array['id_lookup'][id + fld];
			if (pos || pos == 0) {
				base_array['data'][ pos ] = null;
				base_array['memo'][ pos ] = null;
				base_array['id_lookup'][id + fld] = null;
			}
			inputs[j].setAttribute('deleted', 'yes');
		}
		id = inputs[0].getAttribute('RecID')
		if (!id) id = inputs[0].getAttribute('id');
	}
	if (id.substr(0, 5) == 'n_e_w') return;
	var str = '|@@a=d@@t=' + tbl + '@@i=' + id + '@@|';
	base_array['data'].push(str);
	base_array['memo'].push(memo);
	base_array['id_lookup'][id + 'del'] = base_array['data'].length - 1;
}

function doUpdate(dont_wait) {
	setMessage('Saving... Please Wait.');
	save();
	//if (dont_wait) save();
	//else setTimeout("save()", 20); // this allows the message change to be seen
	return false;
}
function frmUpdate_onsubmit() {
//	if (document.frmUpdate.PreSave.value)
		alert(document.frmUpdate.PreSave.value );
	return true;
}

function save() {
	start = new Date();
	
	readform2(parent, true);
	
	end = new Date();
	//alert('done:' + (end.getTime()-start.getTime())/1000);
	document.frmUpdate.submit();
	parent.document.frmSelections.iframe_hits.value = eval(parent.document.frmSelections.iframe_hits.value) + 1; 
}

/*function closeIt() {
    event.returnValue = "Any string value here forces a dialog box to appear before closing the window.";
}*/

function setMessage(message) {
		parent.document.getElementById('divMessage').innerHTML = message;
		window.status = message;
}

function outstandingUpdates(){
	var temp = '';
	for (var j=0; j < curr_updates.length; j ++)
		temp += curr_updates[j]['data'].join('');
	return (temp.length > 0);
}
function readform() { return readform2() };
function readform2(frame, clear_data) {
//alert('readform2');
	if (!frame) {frame = document;}
	
	document.frmUpdate.pkg.value='';
	document.frmUpdate.pkg2.value='';
	var alreadyAdded = new Object();
	// if we have defined a priority order for table updates, then go through this list and process those
	// tables in order, marking the ones we process
	if (parent.table_update_priority)
		for (var j=0; j < parent.table_update_priority.length; j++) {
			var base_array = getTableUpdates( parent.table_update_priority[j] );
			append_table_updates(base_array, clear_data);
			alreadyAdded[parent.table_update_priority[j]] = true;
		}
	// now we process any other table updates for any tables not included in priority list
	
	for (var j=0; j < curr_updates.length; j ++) {
		if (!alreadyAdded[curr_updates[j]['name']]) {
			append_table_updates(curr_updates[j], clear_data, curr_updates[j]['name']);
			alreadyAdded[curr_updates[j]['name']] = true;
		}
	}
	var del_tbl;
	for (del_tbl in toggled_deletes) {
		// we could have just deletes, no updates for a table. Check for unhandled delets
		if (!alreadyAdded[del_tbl]) {
			apply_toggled_deletes(del_tbl);
			append_table_updates(getTableUpdates(del_tbl), clear_data, del_tbl, true);
		}
	}
	if (clear_data) {
		curr_updates = new Array();
		curr_updates_lookup = new Object();
	}
	document.frmUpdate.size2.value = document.frmUpdate.pkg2.value.length;
	document.frmUpdate.PreSave.value = build_pre_save_request();
		
	others(frame);
}
function mark_for_delete_toggle(obj, undelete) {
	// this function simply flags a certain table and id as being deleted, but doesn't do the deletion
	//  this allows a delete to be toggled off before the save occurs. The toggled_deletes are checked and applied at time of save
	var tbl = get_tbl_name(obj);
	var base_array = getDeleteObj(tbl);
	id = obj.getAttribute('RecID')
	
	if (!id) id = obj.getAttribute('id');
	base_array[id] = undelete ? null : id;
}
function apply_toggled_deletes(tbl) {
	var del_obj = getDeleteObj(tbl);
	for (row_del in del_obj) {
		if (del_obj[row_del] != null) {
			delete_row(tbl, document.getElementById('tr_' + del_obj[row_del]));
		}
   }
}
function append_table_updates(table_updates, clear_data, tbl_name, no_dels) {
	if (!no_dels) apply_toggled_deletes(tbl_name);
	document.frmUpdate.pkg2.value += table_updates['data'].join('');
		if (clear_data) {
			table_updates['data'] = null;
			table_updates['memo'] = null;
			
			table_updates['id_lookup'] = null
			table_updates = null;
		}
}

function others(frame) {
	document.frmUpdate.CurrURL.value = frame.frmSelections.CurrURL.value;
	document.frmUpdate.Page.value = frame.frmSelections.Page.value;
	document.frmUpdate.PageID.value = frame.frmSelections.PageID.value;
	document.frmUpdate.LastUpdated.value = frame.frmSelections.LastUpdated.value;
	document.frmUpdate.EndAction.value = frame.frmSelections.EndAction.value;
	document.frmUpdate.FormatOption.value = frame.frmSelections.FormatOption.value;
	document.frmUpdate.Saved.value = frame.frmSelections.Saved.value;
	frame.frmSelections.pkg2.value = document.frmUpdate.pkg2.value
}

function getRow(tbl) {
	//document.frmUpdate.pkg2.value = '|@@t=' + tbl + '@@f=' + fld + '@@i=' + id + '@@v=' + input.getAttribute("value") + '!#!#' + '@@|';
	
}

function customByRow(table, pkgstart_str, rowstart_str, field_str, rowend_str, pkgend_str) {
	var rows = table.getElementsByTagName('TBODY')[0].childNodes;
	var final_str = '',str = '', substr, input;
	for (var j=0; j < rows.length; j++) {
		substr = '';
		var inputs = rows[j].getElementsByTagName('INPUT');
		for (var i=0; i < inputs.length; i++) {
			if (inputs[i].getAttribute('Changed') == '1')
					substr += eval(field_str);
		}
		if (substr.length > 0) str += eval(rowstart_str) + substr + eval(rowend_str);
	}
	if (str.length > 0) final_str = eval(pkgstart_str) + str + eval(pkgend_str);
	alert(final_str);
	document.frmUpdate.pkg2.value = final_str;
	others(document);
	return final_str;
	//return str.replace('"', '""');
}



