// Hold a reference to the last row selected
var gLastSelRow = new Object();
// Hold a reference to the currently selected row
var gCurSelRow;
var DEFAULT_ROW_STYLE = "ListItem";
var CLASS_HL = "Highlighted";

function EnforceCollection(el) {
	if (el == null) return null;
	if (el.length) {
		return el;
	} else {
		var ar = new Array();
		ar[0] = el;
		return ar;
	}	
}

function GetXmlTableRow(tableId, rowNum) {
	var tbl = document.all("tbl_list_" + tableId);
	if (tbl == null) return null;
	if (tbl.rows.length <= rowNum) return null;
	return tbl.rows[rowNum];
}

function SelectRowOnLoad(ifCondition, xmlDoc, tblId) {
	//alert(ifCondition);
	if (ifCondition == "") return;
	var node = xmlDoc.selectSingleNode("//node()[" + ifCondition + "]");
	if (node == null) return;
	var uid = node.selectSingleNode("@id").text;
	var r = GetRowById(tblId, uid);
	if (r == null) return;
	r.scrollIntoView(true);
	r.click();
}

function SyncXmlTableHeader(ctlId, hideList, tbl) {
	var tblHead = getElement("tbl_headers_" + ctlId);
	if (tblHead.length > 1) tblHead = tblHead[1];
	var hcols = tblHead.rows[0].cells;

	for (var i=0; i<hcols.length; i++) {
		var c = hcols[i];
		var inList = (hideList.indexOf("," + i + ",") >= 0);
		c.style.display = (inList) ? "none" : "block";
	}
	
	if (tbl == null) return;
	if (tbl.length > 1) tbl = tbl[1];
	if (tbl.rows == null) return;

	var k = 0;
	for (var i=0; i<hcols.length; i++) {
		var c = hcols[i];
		var inList = (hideList.indexOf("," + i + ",") >= 0);
		if (!inList) {
			var cc = null;
			try {
				cc = tbl.rows[0].cells[i];
			} catch(e) {}
			if (cc != null) {
				var w = parseInt(cc.clientWidth);
				//alert(i + ", " + w);
				if (!isNaN(w)) c.width = w; // - (k++ * 0.3); // - (1.2 * (k++ % 4));
			}
		}
	}
	//last visible column:
	for (var i=hcols.length-1; i>=0; i--) {
		var inList = (hideList.indexOf("," + i + ",") >= 0);
		if (!inList) {
			hcols[i].width = "";
			break;
		}
	}
	
	if (gCurSelRow != null && gCurSelRow.uid != null) {
		SelectRowById(gCurSelRow.uid, ctlId);
	}
}

function XmlTableHideColumns(ctlId, hideList) {
	hideList = hideList.replace(" ", "");
	hideList = "," + hideList + ",";
	//alert(hideList);
	
	var doc = getElement("xsl_list_" + ctlId);
	if (!doc) return;
	var forEach = doc.selectNodes("//xsl:for-each");
	var kk = (gFixedColumns) ? 1 : 0;
	//alert(kk);
	var columns = forEach[kk].selectNodes("./tr/td");
	//alert(columns.length);
	for (var i=0; i<columns.length; i++) {
		var inList = (hideList.indexOf("," + i + ",") >= 0);
		var st = (inList) ? "none" : "block";
		SetNode(columns[i], "@style", "display: " + st);
	}
	refreshXmlTable(ctlId, gFixedColumns);
	
	var tbl = getElement("tbl_list_" + ctlId);
	
	//synchronize headers:
	SyncXmlTableHeader(ctlId, hideList, tbl);
}

function SmallXmlTableHideColumns(ctlId, hideList) {
	hideList = hideList.replace(" ", "");
	hideList = "," + hideList + ",";

	var tbl = getElement("tbl_list_" + ctlId);
	if (tbl != null && tbl.rows != null) {
		var e = new Enumerator(tbl.rows)
		for (; !e.atEnd(); e.moveNext()) {
			var r = e.item();
			var cols = r.cells;
			var N = cols.length;
			for (var i=0; i<N; i++) {
				var c = cols[i];
				var inList = (hideList.indexOf("," + i + ",") >= 0);
				c.style.display = (inList) ? "none" : "block";
			}
		}
	}
	SyncXmlTableHeader(ctlId, hideList, tbl);	
}

function trim(s) {
	return s.replace(/^\s*|\s*$/g,"");
}

function GetRowByUid(tbl, uid) {
	var allRows = tbl.rows;
	var e = new Enumerator(allRows);
	for (; !e.atEnd(); e.moveNext()) {
		var r = e.item();
		if (r.uid && r.uid == uid) {
			return r;
		}
	}
	return null;
}

function GetRowById(tblId, uid) {
	var tbl = getElement("tbl_list_" + tblId);
	return GetRowByUid(tbl, uid);
}

function GetCheckedIds()
{
	var ret = new Array(); 
	var chks = document.getElementsByName("chkCheck");
	if (chks == null) return null;
	var len = chks.length;
	if (len < 1)
	{
		ret[0] = chks.uid;
	}
	else
	{
		for (var i = 0; i < len; i++)
		{
			var el = chks[i];
			if (el.checked)
			{
				ret[ret.length] = el.uid;
			}	
		}
	}	
	return ret;
}

function styleHighlight(el, hlClass) 
{ 
	if ( el.className.toLowerCase() != hlClass.toLowerCase() ) 
	{ 
		el.oldClass = el.className; 
		if (el.className != hlClass) el.className = hlClass; 
		//window.status = el.className;
	} 
} 

function styleReset(el) { 
	if (el.className.indexOf("Selected" < 0)) 
	{ 
		if (el.oldClass != null && el.className != el.oldClass) 
		{ 
			if (el.className != el.oldClass) el.className = el.oldClass; 
			//window.status = el.className;
		} 
	}  
}

function getElement(name, noMsg) {
	var doc = document.all(name);
	if (doc) {
		return doc;
	} else {
		try {
			//alert("eval(" + name + ")");
			doc = eval(name);
		} catch(e) {}
		if (doc) {
			return doc;
		} else {
			if (!noMsg) alert("Document element not found: " + name);
			return null;
		}	
	}
}

function setElement(name,value) {
	var doc = document.all(name);
	if (doc) {
		doc.value=value;
	} else {
		alert("Document element not found: " + name);
	}
}

function GetSortNode2(ctlId) {
	var xsl_list = getElement("xsl_list_" + ctlId);
	xsl_list.sortNode2 = (gFixedColumns) ? xsl_list.XMLDocument.selectNodes("//xsl:sort")[1] : null;
	return xsl_list.sortNode2;
}

var gFixedColumns = false;
function initXmlTable(ctlId) {
	//alert(ctlId);
	
	refreshXmlTable(ctlId);
	var xsl_list = getElement("xsl_list_" + ctlId);
	xsl_list.sortNode = xsl_list.XMLDocument.selectSingleNode("//xsl:sort");
	//alert(xsl_list.sortNode);
	//alert(xsl_list.sortNode2);
	//debugPrint(xsl_list.xml);
	var tbl_headers = getElement("tbl_headers_" + ctlId);
	if (tbl_headers.length == 2) {
		gFixedColumns = true;
		tbl_headers = tbl_headers[0];
	}	
	tbl_headers.style.display = "block";
	tbl_headers.style.visibility = "visible";
	//alert(tbl_headers.id);
	xsl_list.oldSortColumn = null;// tbl_headers.rows[0].cells[0];
	//alert(xsl_list.oldSortColumn.innerHTML);
	//xsl_list.oldSortColumn.sortSpan = getSortSpan(xsl_list.oldSortColumn);
	//alert(xsl_list.oldSortColumn.imgSpan.innerHTML);

	var sh = eval("gSmartHeight" + ctlId);
	if (sh) SetSmartTableHeight(ctlId);
	//alert("init " + ctlId + " - done");
	
	document.recalc();
	
	InitXmlFilterLists(ctlId);
	
}

function GetClientWidth(el) {
	var w = el.parentElement.parentElement.clientWidth;
	//alert(el.parentElement.parentElement.outerHTML + "\n" + w);
	if (w == null || parseInt(w) < 1) {
		w = "100";
	}
	return w;
}

function SetSmartTableHeight(ctlId) {
	var innerDiv = document.all("tbl_list_" + ctlId);
	var div = document.all("div_list_" + ctlId);
	if (innerDiv && div) {
		var h = div.style.height;
		h = parseInt(h.replace("px", ""));
		var maxH = GetDivHeight(innerDiv);
		if (maxH > 2 && (h < 50 || h > maxH)) div.style.height = maxH;
	}	
}

function SelectRowById(id, ctlId, focus) {
	var tbl = document.all("tbl_list_" + ctlId);
	if (!id || id < 0 || !tbl) return;
	var theRow = null;
	if (tbl.length > 1) tbl = tbl[1];
	var N = tbl.rows.length;
	for (var i=0; i<N; i++) {		
		theRow = tbl.rows.item(i); 
		if (theRow.uid == id) {
			SelRow(theRow);
			if (focus) theRow.scrollIntoView();
			break;
		}	
	}
	return theRow;
}

function getSortSpan(el) {
	return el.childNodes[0].childNodes[1];
}

function GetDivHeight(div) {
	var rect = div.getBoundingClientRect();
	if (rect == null) return 0;
	h = Math.abs(rect.bottom - rect.top);
	return h + 2;
}

var gTableXslFilter = "";
function refreshXmlTable(ctlId, secondOnly, syncHeight) {
	var xml_list = getElement("xml_list_" + ctlId, true);
	if (xml_list == null) {
		ctlId = ctlId.replace("IASW_", "");
		xml_list = getElement("xml_list_" + ctlId, true);
		if (xml_list == null) return;		
	}	
	var xslId = "xsl_list_" + ctlId;
	var xsl_list = getElement(xslId, true);
	var div_list = getElement("div_list_" + ctlId);
	
	if (!xml_list || !xsl_list || !div_list ) return;
	if (xsl_list.xml == "") {
		alert("Xml table has not been initialized (empy column list): " + ctlId);
		return;
	}
	if (xsl_list.length > 1) {
		alert("Error: there are " + xsl_list.length + " " + xslId + " elements, not one.");
		return;
	}
	var xmlDoc = (xml_list.ownerDocument == null) ? xml_list : xml_list.ownerDocument;
	
	var oldSel;
	var selNode = null;
	if (gTableXslFilter != null && gTableXslFilter.length > 1) {
		var forEach = xsl_list.selectSingleNode("//xsl:for-each");
		if (forEach) {
			selNode = forEach.selectSingleNode("@select");
			oldSel = selNode.text;
			selNode.text += gTableXslFilter;
		}
	}
	
	var s;
	
	if (secondOnly) {
		var doc = new ActiveXObject("Microsoft.XMLDOM"); //use transformNodeToObject instead :TODO:)
		xmlDoc.transformNodeToObject(xsl_list.XMLDocument, doc);
		var divName = "div_headers2_" + ctlId;
		var xp = "//div[@id='" + divName + "']";
		var divNode = doc.selectSingleNode(xp);
		if (divNode) {
			var div = getElement(divName);
			var tn = divNode.selectSingleNode("table");
			div.innerHTML = tn.xml;
		} else {
			alert("Node not found: " + xp);
		}
	} else {
		s = xmlDoc.transformNode(xsl_list.XMLDocument);
//		debugPrint(s);
		div_list.innerHTML = s;
	}	
	
	if (selNode != null) selNode.text = oldSel; //restore previous value
	//debugPrint(s);
	div_list.style.display = "block";
	div_list.style.visibility = "visible";
	btnsNoSelect(ctlId);

	var frm = document.all("frm_item_" + ctlId);
	if (frm) frm.style.display = "none";

	var div = document.all("div_item_" + ctlId);
	if (div) div.style.display = "none";
	
	try {
		DisablePageButtons(true);
	} catch(e) {}
	
	if (syncHeight) SyncTableHeight(ctlId);
	
}

function SortXmlTableDirect(ctlId, field, ascDesc, format, noRefresh) { 
	var xsl_list = getElement("xsl_list_" + ctlId);
	var sortNode = xsl_list.XMLDocument.selectSingleNode("//xsl:sort");
	if (sortNode == null) return;
	if (field == null) field = "@id";
	if (ascDesc == null) ascDesc = "ascending";
	if (format == null) format = "number";
	SetNode(sortNode, "@select", field);
	SetNode(sortNode, "@order", ascDesc);
	SetNode(sortNode, "@data-type", format);
	if (!noRefresh) refreshXmlTable(ctlId);
} 

function SortXmlTable(col, ctlId) {

	var bServerSide = false;
	try {
		bServerSide = gUseServerSideFilters;
	} catch(e) {}
	
	var xsl_list = getElement("xsl_list_" + ctlId);
	var oldCol = xsl_list.oldSortColumn;
	if(oldCol && oldCol.sortSpan ) {
		if(oldCol.sortSpan.innerText) oldCol.sortSpan.innerText = "";
	} else {
		var tbl = getElement("tbl_headers_" + ctlId);
		if (tbl) {
			tbl = EnforceCollection(tbl);
			for (var k=0; k < tbl.length; k++) {
				var cls = tbl[k].rows[0].cells; //all headers
				for (var i=0; i<cls.length; i++) {
					var c = cls[i];
					var ch = c.childNodes[0].childNodes[1];
					try {
					if (ch && ch.innerText != null) ch.innerText = "";
					} catch(e) {}
				}
			} 
		}
	}
	var sortNode;		
	if (col == null) { 	//sorting by @id
		SortXmlTableDirect(ctlId);
		return;
	}
	sortNode = getSortSpan(col);
	var field = col.field;
	var dataTypeAtt = xsl_list.sortNode.attributes.getNamedItem("data-type");
	var fmt;
	var sortFmt = col.sortFormat;
	if (sortFmt == null) sortFmt = col.format;
	switch (sortFmt) {
		case "ckeckimage" :
			fmt = "text";
			break;	
		case "html" :
		case "textbox" :			
			fmt = col.sortFormat;
			break;
		case "text" :
		case "checkbox" :
			fmt = "text";
			break;
		case "date" :
		case "dt" :
			field = "user:Date2Number(" + field + ")";
			fmt = "number";
			break;
		default:
			fmt = "number";
	}
	dataTypeAtt.text = fmt;
	var selAtt = xsl_list.sortNode.attributes.getNamedItem("select");
	var orderAtt = xsl_list.sortNode.attributes.getNamedItem("order");
	
	if (selAtt.text == field) {
		if (orderAtt.text == "ascending") {
			orderAtt.text = "descending";
			try {
			sortNode.innerText = "\u25BC";
			} catch(e) {}
		} else {
			orderAtt.text = "ascending";
			try {
			sortNode.innerText = "\u25B2";
			} catch(e) {}
		}
	} else {
		selAtt.text = field;
		orderAtt.text = "ascending";
		try {			
		sortNode.innerText = "\u25B2";
		} catch(e) {}
	}

	xsl_list.oldSortColumn = col;
	xsl_list.oldSortColumn.sortSpan = getSortSpan(xsl_list.oldSortColumn);

	var sn2 = GetSortNode2(ctlId);
	if (sn2 != null) {
		SetNode(sn2, "@select", selAtt.text);
		SetNode(sn2, "@order", orderAtt.text);
		SetNode(sn2, "@data-type", fmt);
	}
	
	if (bServerSide) {
		try {
			SSSort(ctlId, field, fmt, orderAtt.text);
			return;
		} catch(e) {}	
	}	
	
	refreshXmlTable(ctlId);
	
	if (gFixedColumns) {
		var div = getElement("div_headers2_" + ctlId);
		SyncScroll(div);
	}
	
	try {
		if (ok_click()) {
			div_item.style.display = "none";
			//div_item.innerHTML = "";
		}
	} catch(e) {}
	
	gLastSelectedRow = null;
}


function checkXmlNodeByIdExists(ctlId, uid) {
	var xml_list = getElement("xml_list_" + ctlId);
	var xpath = "//.[@id='" + uid + "']";
	var node = xml_list.selectSingleNode(xpath);
	if (!node) {
		//leave commented out
		//used to check for existence of a node by id
		//alert("Table.js:getXmlNodeById: XML node not found: " + xpath);
	}
	return node;
}

function getXmlNodeById(ctlId, uid) {
	var xml_list = getElement("xml_list_" + ctlId);
	var xpath = "//.[@id='" + uid + "']";
	var node = xml_list.selectSingleNode(xpath);
	if (!node) {
		alert("Table.js:getXmlNodeById: XML node not found: " + xpath);
	}
	return node;
}

function getXmlNodeById2(ctlId, uid) {
	//not hardcoded prefix of element id
	var xml_list = getElement(ctlId);
	//alert(xml_list);
	//alert(xml_list.XMLDocument);
	//alert(xml_list.XMLDocument.xml);
	var xpath = "//.[@id='" + uid + "']";
	var node = xml_list.selectSingleNode(xpath);
	if (!node) {
		alert("Table.js:getXmlNodeById2: XML node not found: " + xpath);
	}
	return node;
}

function GetHLClassName(className) {
	var cl = className + CLASS_HL;
	var rule = GetStyleByName(cl);
	var ret;
	if (rule == null) {
		ret = DEFAULT_ROW_STYLE + CLASS_HL;
	} else {
		ret = cl;
	}
	return ret;
}

function GetHLBgColor(className) {
	if (className == null) className = DEFAULT_ROW_STYLE;
	className += CLASS_HL;
	var ret;
	var rule = GetStyleByName(className);
	if (rule == null) {
		//if not found - use default
		var cl = DEFAULT_ROW_STYLE + CLASS_HL;
		ret = GetBgColor(cl);
	} else {	
		ret = rule.style.backgroundColor;
	}
	return ret;
}

function GetBgColor(className) {
	var rule = GetStyleByName(className);
	if (rule == null) return "";
	return rule.style.backgroundColor;
}

function GetStyleByName(name) {
	if (name.charAt(0) != ".") name = "." + name;
	var sh = document.styleSheets;
	var e = new Enumerator(sh);
	for (; !e.atEnd(); e.moveNext()) {
		var ro = sh.item().rules;
		for (var j=0; j<ro.length; j++) {
			var rule = ro[j];
			var nm = rule.selectorText;
			if (nm == name) {
				return rule;
			}
		}
	}	
	return null;	
}

var gLastSelectedRow = null;
function SelRow(r) 
{
	if (gLastSelectedRow == r) return;
	gLastSelectedRow = r;
	gLastUid = parseInt(r.uid);
	var cl = r.className;
	if (cl == null) {
		cl = "ListItem";
	} else {
		cl = cl.replace(CLASS_HL, "");
	}	

	var bgColor = GetHLBgColor(r.className);

	// Get the parent table/element
	if (r.parentElement == null) return;
	var tbl = r.parentElement.parentElement;
	var tblId = tbl.id;
	var ctlId = tblId.replace("tbl_list_", "");
	// Get the XSL element
	var xslId = tblId.replace("tbl_", "xsl_");
	
	var hl = GetHLClassName(cl); 
	var xsl_list = getElement(xslId, true);
	
	var lastSel; 	
	if (xsl_list == null) { //for backwards compatibility
		lastSel = gLastSelRow;
		hl = "ListItem";
	} else {
		lastSel = xsl_list.lastSelectedRow;
	} 
	
	try {
		DisablePageButtons(false);
	} catch(e) {}
	
	if (r == lastSel) {
		if (event.srcElement.type == "text") {
			event.cancelBubble = true; //do not call RowClick() :TODO:
		}
		return;
	} 
	
	var tds = r.cells;
	if (tds) {
		for (var i=0; i<tds.length; i++) {
			var c = tds[i].firstChild.firstChild;
			if (c && c.type == "text") {
				c.oldBgColor = c.style.backgroundColor;
				c.style.backgroundColor = bgColor;
			}
		}
	}
	
	if (lastSel) {
		lastSel.className = lastSel.oldClassName;
		lastSel.style.backgroundColor = lastSel.oldBgColor;
		if (lastSel.row2) {
			lastSel.row2.className = lastSel.row2.oldClassName;
			lastSel.row2.style.backgroundColor = lastSel.row2.oldBgColor;
		}
		var tdsSel = lastSel.cells;
		if (tdsSel.length) {
		for (var i=0; i<tdsSel.length; i++) {
			var c = tdsSel[i].firstChild.firstChild;
			if (c && c.type == "text") {
				if (c.oldBgColor != null) c.style.backgroundColor = c.oldBgColor;
			}
		}
	}

	}
	
	r.oldClassName = r.className;
	r.oldBgColor = r.style.backgroundColor;
	
	var re = /[0-9]/;
	var s = r.className.replace(re, "");

	r.className = hl;
	r.style.backgroundColor = "";
	
	
	// Store the currently selected row
	gCurSelRow = r;

	if (xsl_list == null) {
		gLastSelRow = r;
	} else {
		xsl_list.lastSelectedRow = r;
	}

	bntsSingleSelect(ctlId);
	
	if (gFixedColumns) {
		var tbls = document.all(tblId);
		var idx = 0;
		var e = new Enumerator(tbl.rows);
		if (e) {
			for (; !e.atEnd(); e.moveNext()) {
				if (e.item() == r) break;
				idx++;
			}
		}
		var nTbl = (tbls[0] == tbl) ? 1 : 0;
		var r2 = tbls[nTbl].rows[idx];
		r2.oldClassName = r2.className;
		r2.oldBgColor = r2.style.backgroundColor;
		s = r2.className.replace(re, "");
		r2.className = hl;
		r2.style.backgroundColor = "";
		xsl_list.lastSelectedRow.row2 = r2;
	}

	//:TODO: set @seleted=1 in the XML node, so it keeps selected even after sorting (how to get selected element? Store uid globally or as xml_list member?);  
	//document.recalc();
}

function GetSelRow()
{
	// Return the currently selected row
	// NOTE if no row is selected 'null' is returned
	return gCurSelRow;
}


function SelRowBg(r, bgColor) {
	var tblId = r.parentElement.parentElement.id;
	var ctlId = tblId.replace("tbl_list_", "");
	var xslId = tblId.replace("tbl_", "xsl_");
	var xsl_list = getElement(xslId);
	var lastSel = xsl_list.lastSelectedRow;
	if (r == lastSel) return;
	if (lastSel) {
		lastSel.style.backgroundColor = lastSel.oldBgColor;
	}
	r.oldBgColor = r.style.backgroundColor;
	r.style.backgroundColor = bgColor;
	xsl_list.lastSelectedRow = r;
	bntsSingleSelect(ctlId);		
}


function enableButton(btnId, enable) {
	var btn = document.all(btnId);
	if (btn) btn.disabled = !enable;
}

function Form2Xml(frm, xmlNode, noTrim) {
	var N = frm.length;
	var bChanges = false;
	var c;
	for (var i=0; i<N; i++) {
		c = frm.elements[i];
		switch (c.type) {
			case "button" :
				//skip
				break;
			case "checkbox" :
				var val = (c.checked) ? "Y" : "N";
				if (SetNode(xmlNode, c.name, val, true)) bChanges = true;
				break;
			default :
				var val = (noTrim) ? c.value : trim(c.value) ;
				if (SetNode(xmlNode, c.name, val, true)) bChanges = true;
		}	
	}
	return bChanges;
}

function Form2XmlNode(frm) {
	//:TODO:
}


function XmlNode2Form(node, frm) {  //Or always use XSLT instead? Advantage: can use simple HTML form instead of XSL file. :TBD:
	var nodes = node.childNodes;
	var dataNode = nodes.nextNode();
	while (dataNode) {
		var name = dataNode.nodeName;
		var val = dataNode.text;
		SetFormControl(frm, name, val);
		dataNode = nodes.nextNode();
	}
}

function SetFormControl(frm, name, val) {
	var ctl = eval("frm." + name);
	if (ctl) {
		switch (ctl.type) {
			case "checkbox" :
				ctl.checked = (val == "Y" || val == "1");
				break;
			case "select" :
				//???
				break;	
			default:
				ctl.value = val;
		}
	} else {
		//try to find it in the DOM:
		ctl = document.all(name);
		if (ctl) {
			ctl.innerHTML = val;
		} else {
			//alert("Control not found on the form: " + name);
		}	
	}
}

function GetNextId(xmlDoc) {
	var allIds = xmlDoc.selectNodes("//@id");
	var e = new Enumerator(allIds);
	var maxId = 0;
	for (; !e.atEnd(); e.moveNext()) {
		var node = e.item();
		var id = parseInt(node.text);
		if (!isNaN(id) && id > maxId) maxId = id;
	}
	return maxId + 1;
}

function GetMaxNodeValue(nodeList, attrName) {
	var e = new Enumerator(nodeList);
	var maxVal = 0;
	for (; !e.atEnd(); e.moveNext()) {
		var node = e.item();
		var attrNode = node.selectSingleNode(attrName);
		var val = 0;
		if (attrNode) val = parseInt(attrNode.text);
		if (!isNaN(val) && val > maxVal) maxVal = val;
	}
	return maxVal;
}


function ClearNode(node) 
{ 
	var nodes = node.childNodes;
	if (!nodes) return;
	var dataNode = nodes.nextNode();
	while (dataNode) {
		dataNode.text = "";
		dataNode = nodes.nextNode();
	}
} 

function SetAttribute(node, name, value) { 
	var atts = node.attributes; 
	var attr = atts.getNamedItem(name); 
	if (!attr) { 
		var attr = node.ownerDocument.createAttribute(name); 
		attr = node.attributes.setNamedItem(attr); 
	} 
	attr.value = value; 
} 

function SetNode(doc, nodeName, newValue, rememberOldVal, doNotCreateEmpty) { //refObj) { 
	if (doc == null) return;
	//actually gets called in iMaintain
//PY 2005 07/13
//	var node = (nodeName == "") ? doc : doc.selectSingleNode(nodeName);
	var bChanges = false; 
	var isAttribute = false; 
	if (nodeName.substr(0,1) == '@') 
	{ 
		//it's an attribute 
		nodeName = nodeName.substr(1); 
		isAttribute = true; 
	} 
//PY 2005 07/13
	var node = (nodeName == "") ? doc : doc.selectSingleNode(nodeName);
	if (node) 
	{ 
		if (newValue == null && isAttribute) 
		{ 
			var atts = doc.attributes; 
			if (atts) atts.removeNamedItem(nodeName); 
		} 
		else 
		{ 
			if (newValue == null) newValue = "";
			//never aply 10.00 vs 10 (same number in different format)
			var oldVal = node.text;
			var bOld = isNaN(oldVal);
			var bNew = isNaN(newValue);
			if ( 
				((bOld || bNew) && oldVal != newValue) 
				|| oldVal.length != newValue.length
				|| newValue == "" || (bOld != bNew) 
				|| (!bOld && parseFloat(newValue) != parseFloat(oldVal)) 
				) {
				if (newValue.toString() != oldVal.toString()) 
				{ 
					try {
						var updattr = node.parentNode.ownerDocument.createAttribute("UPDATED");
						updattr.value = "Y";
						node.parentNode.attributes.setNamedItem(updattr);
					} catch(e) {}
					
					//!!! "0" may be equal to "" if not converted to string! 
					if (rememberOldVal) 
					{ 
						var atts = node.attributes; 
						if (!atts || !atts.getNamedItem("OLD") ) 
						{ 
							var attr = node.ownerDocument.createAttribute("OLD"); 
							attr.value = node.text; 
							node.attributes.setNamedItem(attr); 
						} 
					} 
					bChanges = true; 
					node.text = newValue; 
				} 
			}	
		} 
	} 
	else 
	{ 
		if (newValue != null && (!doNotCreateEmpty || newValue.toString() != "")) {
			bChanges = true;
			//if (refObj != null) refObj.newCreated = true;
			if (isAttribute) {
				var attr = doc.ownerDocument.createAttribute(nodeName); 
				attr.value = newValue; 
				doc.attributes.setNamedItem(attr); 
			} else {
				var el = doc.ownerDocument.createElement(nodeName);
				el = doc.appendChild(el);
				el.text = newValue;
			}	
			if (rememberOldVal && newValue != "") 
			{ 
				var attr = el.ownerDocument.createAttribute("OLD"); 
				attr.value = ""; 
				el.attributes.setNamedItem(attr); 
			} 
		}
	} 
	return bChanges; 
} 

function RenderEmptyNode(name) {
	return "<" + name + "></" + name + ">";
}

function CreateNewNode(ctlId, idTag) {
	if (!idTag) idTag = "id"; //default
	var idAttr = "@" + idTag;
	var xml_list = document.all("xml_list_" + ctlId);
	if (!xml_list) {
		alert("xml_list not found:");
		return null;
	}
	var node = xml_list.XMLDocument.childNodes[0].childNodes[0];
	var newNode = node.cloneNode(true);
	ClearNode(newNode);
	newNode.selectSingleNode("@id").text = "0";
	return newNode;
}

function CreateNewNodeByHeaders(nodeName, ctlId, idTag) {
	if (!idTag) idTag = "id"; //default
	var idAttr = "@" + idTag;
	var xml = "<" + nodeName + " " + idTag + "='0'>"; 
	var tbl = document.all("tbl_headers_" + ctlId);
	if (tbl) {
		var r = tbl.rows[0];
		for (var i=0; i<r.cells.length; i++) {
			var c = r.cells[i];
			var f = c.field;
			if (f != idAttr) {
				xml += RenderEmptyNode(f);
			}
			//alert(c.field);
		}
	} else {
		alert("Table headers not found");
		return null;
	}
	xml += "</" + nodeName + ">";
	//alert(xml);
	var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
	xmlDoc.loadXML(xml);
	//alert(xmlDoc.parseError.reason);
	//alert(xmlDoc.xml);
	return xmlDoc.childNodes[0];
}

function bntsSingleSelect(ctlId) {
	enableButton("btn_add_" + ctlId, true);
	enableButton("btn_edit_" + ctlId, true);
	enableButton("btn_del_" + ctlId, true);
	enableButton("btn_clone_" + ctlId, true);
	enableButton("btn_invert_" + ctlId, true);
	enableButton("btn1_" + ctlId, true);
	enableButton("btn_status_" + ctlId, true);
}
	
function btnsNoSelect(ctlId) {
	enableButton("btn_add_" + ctlId, true);
	enableButton("btn_edit_" + ctlId, false);
	enableButton("btn_del_" + ctlId, false);
	enableButton("btn_clone_" + ctlId, false);
	enableButton("btn_invert_" + ctlId, false);
	enableButton("btn1_" + ctlId, false);
	enableButton("btn_status_" + ctlId, false);
}

function ValidateForm(frm) {
    var firstMissing = null;
	var N = frm.length;
	var c;
	var nMissing = 0;
	var msg = "";
	var pwd = "";
	for (var i=0; i<N; i++) {
	  c = frm.elements[i];
	  if (c.type != "button") {
		c.value = trim(c.value);
		
		if ( (c.required == "1" || c.required == "10") && c.value == "") {
			if (firstMissing == null) {
				firstMissing = c;
			}
			nMissing++;	
			msg += "\n- " + c.title;
		} 
		
		if (c.required == "10") {
			if (pwd == "") {
				pwd = c.value;
			} else {
				if ( (pwd == "" || c.value != pwd) && c.value != "" ) {
					msg += "\nThe passwords you typed do not match.\n";
					c.value = "";
					firstMissing = c;
				}
			}	
		}		
	  }	
	} //for
	if (msg != "") {	
		if (nMissing > 1) {
			msg = "The following fields are required:\n" + msg;
		} else {
			if (nMissing > 0) {
				msg = msg.replace("- ","") + " field is required.";
			}	
		}
		alert(msg);
		firstMissing.focus();
		return false;
	}
	return true;
}

function SwapNodes(UpperNode, LowerNode) { //order is important!
	var node = LowerNode.cloneNode(true);
	LowerNode.parentNode.removeChild(LowerNode);
	UpperNode.parentNode.insertBefore(node, UpperNode);
}

function RemoveDummyNodes(uid) {
	var xmlDoc = getElement("xml_list_" + uid);
	var node = xmlDoc.selectSingleNode("//.[@id = '0']");
	if (node) node.parentNode.removeChild(node);
}

function SyncDivHeight(btn) {
	if (btn == null) {
		var img = document.all("imgExpColTable");
		if (img == null) return;
		if (img.length > 1) {
			btn = img[currentLevel];
		} else {
			btn = img;
		}	
	}
	if (btn == null || btn.div == null) return;
	div = document.all(btn.div);
	var innerDiv = document.all(btn.div.replace("div_", "tbl_"));
	if (innerDiv) {	
		var realH = GetDivHeight(innerDiv);
		div.style.height = realH;
		div.oldHeight = h;
	}	
}

function SyncTableHeight(tblName) {
	var tbl = "tbl_list_" + tblName;
	var innerTable = document.all(tbl);
	if (innerTable == null) return;
	var realH = GetDivHeight(innerTable);
	if (realH < 1) return;
	var div = document.all("div_list_" + tblName);
	if (div == null) return;
	if (div.oldHeight == null) {
		div.oldHeight = div.style.height;
	} else {
		var h = div.oldHeight;
		if (h >= 100 && realH > h) realH = h; //limit max height
	} 
	if (realH > 5 && realH < 21) realH = 21;
	div.style.height = realH;
}

function ExpColDivHeight(btn, collapse, setMax) {
	collapse = (collapse == true);
	if (btn == null) {
		var img = document.all("imgExpColTable");
		if (img.length > 1) {
			btn = img[currentLevel];
		} else {
			btn = img;
		}	
	}	
	var div = document.all(btn.div);
	if (div.expanded) {
		div.style.height = div.oldHeight;
		div.expanded = false;
		btn.src = btn.src.replace("Collapse", "Expand");
	} else {
		if (collapse) return; //do nothing if already collapsed
		var h = div.style.height;
		h = h.replace("px", "");
		
		var innerDiv = document.all(btn.div.replace("div_", "tbl_"));
		var maxH = parseInt(btn.newH);
		if (innerDiv) {
			var realH = GetDivHeight(innerDiv);
			if (realH > 2) maxH = realH;
		}	
		
		if (h > maxH || setMax) h = maxH;
		if (parseInt(btn.newH) > maxH) btn.newH = maxH;
		div.oldHeight = h;
		div.style.height = btn.newH;
		div.expanded = true;
		btn.src = btn.src.replace("Expand", "Collapse");
	}
}

function ExpColTableHeight(btn) {
	var div = document.all(btn.div);
	if (div.expanded) {
		if (div.oldHeight != null) div.style.height = div.oldHeight;
		div.expanded = false;
		btn.src = btn.src.replace("Collapse", "Expand");
	} else {
		if (div.oldHeight == null) div.oldHeight = div.style.height;
		div.expanded = true;
		btn.src = btn.src.replace("Expand", "Collapse");
		var tbl = div.id.replace("div_list_", "");
		SyncTableHeight(tbl);	
	}
}


function ToggleChildren(ctlId, k, level, td) {
	event.cancelBubble = true;
	var el = event.srcElement;
	level++;
	var pref = ctlId + "_childRow" + level;
	var name = pref + "_1";
	var name2 = pref + "_2";
	var childRows = document.all(name);
	if (!childRows) {
		alert("Element not found: " + name);
		return;
	}
	var r1 = childRows[--k];
	if (!r1) return;
	var r = null;
	var node = null;
	if (td) {
		r = td.parentElement;
		if (r.uid > 0) {
			var xpath = "//" + gLevelList[0] + "[@id='" + r.uid + "']";
			node = xml_data.selectSingleNode(xpath);
		}
	}
	var childRows2 = document.all(name2);
	var r2 = childRows2[k];
	if (r1.style.display == "none") {
		r1.style.display = "block";
		r2.style.display = "block";
		el.innerText = "-";
		el.className = "MenuButtonPressed";
		el.title = "Collapse child nodes";
		if (node) SetNode(node, "@expanded", "1");
	} else {
		r1.style.display = "none";
		r2.style.display = "none";
		el.innerText = "+";
		el.className = "MenuButton";
		el.title = "Expand child nodes";
		if (node) SetNode(node, "@expanded", null);
	}
}

function SelectFirstRow(ctlId) {
	var tbl = getElement("tbl_list_" + ctlId);
	var rows = tbl.rows;
	if (!rows || rows.length < 1) return;
	rows[0].click();
}

function GetNodeVal(doc, nodeName, defVal) {
	if (!doc||nodeName=="") return defVal;
	try {//py 2005 02-16
		var node = doc.selectSingleNode(nodeName);
		if (node) {
			return node.text;
		} else {
			return defVal;
		}
	}
	catch(e){}
	return defVal;
}

var gSyncTop = null;
var gSyncLeft = null;
var gLastVertScroll = 0;
function SyncScroll(container) {
	var anchor = container.firstChild;
	var rect = anchor.getBoundingClientRect();	
	var div = div_fixed_columns;
	var hdr = div_floating_headers;
	if (gSyncTop == null) {
		var r2 = div.getBoundingClientRect();
		gSyncTop = parseInt(r2.top);
		var r3 = hdr.getBoundingClientRect();
		gSyncLeft = parseInt(r3.left) + 2;
	}
	div.style.position = "relative";
	//window.status = rect.top;
	var d = parseInt(rect.top) - gSyncTop;
	div.style.top = d;
	
	//var hh = 0;
	//hh = Math.abs(parseInt(div.divHeight) - d);
	//div.style.height = hh;
	
	div.style.height = parseInt(div.divHeight) - d;
	gLastVertScroll = d;
	
	var h = parseInt(rect.left) - gSyncLeft;
	hdr.style.left = h;
	hdr.style.width = parseInt(hdr.divWidth) - h;
}

function ShowLastFixedRow(show) { //show = true/false
	var div = div_fixed_container;
	if (show) {
		div.oldHeight = div.style.height;
		div.style.height = div.maxHeight;
	} else {
		if (div.oldHeight != null) div.style.height = div.oldHeight;
	}
}

function XmlTableTabSynch(ctlId)
{
	var tbl = getElement("tbl_list_" + ctlId);
	if (tbl.length > 1) tbl = tbl[1];
	//alert(tbl.outerHTML);
	var allRows = tbl.rows;
	var e = new Enumerator(allRows);
	for (; !e.atEnd(); e.moveNext())
	{
		var r = e.item();
		if (r.uid == gSelectedId)
		{
			r.click();
			break; 
		}
	}
}

function XmlTableRowKeyDown(ctlId) {
	var r = null;
	try { r = event.srcElement; } catch(e) {}
	if (r == null) return;
	var inpName = r.name;
	var inpIndex;
	var isInput = (r.tagName == "INPUT");
	if (isInput) {
		inpIndex = GetElementIndex(r);
	}
	if (r.tagName != "TR") r = r.parentElement;
	if (r.tagName != "TR") r = r.parentElement;
	if (r == null) return;
	if (r.tagName != "TR") r = r.parentElement;
	if (r == null || r.uid == null) return;
	if (r != gCurSelRow) r = gCurSelRow;
	var kk = event.keyCode;
	var nextRow = null;
	switch (kk) { //can use row offset from the same current event.srcElement, since it never changes?
		case 38: //up
			if (r.previousSibling) {
				nextRow = r.previousSibling;
				if (isInput) SetNextElementFocus(inpName, inpIndex-1);
			}	
			break;
		case 40: //down
			if (r.nextSibling) {
				nextRow = r.nextSibling;
				if (isInput) SetNextElementFocus(inpName, inpIndex+1);				
			}
			break;
		default :
	}
	if (nextRow != null) {
		var div = nextRow.parentElement.parentElement.parentElement;
		var divBounds = div.getBoundingClientRect();
		var rowBounds = nextRow.getBoundingClientRect();
		if ((rowBounds.top - 20) < divBounds.top || (rowBounds.bottom + 20) > divBounds.bottom) {
			event.returnValue = false;
			nextRow.scrollIntoView();
		}	
		nextRow.click();
		if (event.repeat) {
			//?? :TODO;
		}
	}
}

function SetNextElementFocus(inpName, idx) {
	var inp = GetElementByIndex(inpName, idx);
	if (inp != null) {
		inp.focus();	
		setTimeout("document.all('" + inpName + "')[" + idx + "].select()", 100); //inp.select();
	}	
}

var gLastUid = 1;
var gRecalcRow = false;
function RecalcXmlTableRow(ibox) {
	gRecalcRow = true;
	var r = ibox.parentElement.parentElement.parentElement;
	var uid = r.uid;
	gLastUid = uid;
	var tbl = r.parentElement.parentElement;
	var tid = tbl.id;
	var xmlId = tid.replace("tbl_list_", "xml_list_");
	var doc = document.all(xmlId);
	var autoRefresh = false;
	var xp;
	if (doc == null) {
		doc = document.all("xml_data");
		var nn;
		try {
			nn = gLevelList[currentLevel];
			autoRefresh = true;
		} catch (e) {
			nn = "ROW";
			autoRefresh = false;
		}
		xp = "//" + nn + "S/" + nn + "[@id='" + uid + "']"; 
	} else {	
		xp = "//.[@id='" + uid + "']";
		autoRefresh = true;
	}	
	var node = doc.selectSingleNode(xp);
	if (node) {
		var field = ibox.name.replace("txt", "").replace("chk", "").replace("lst", "");   //remove txt or (chk, or lst) from the name
		var val;
		switch (ibox.type) {
			case "checkbox" :
				val = (ibox.checked) ? "Y" : "N";
				break;
			case "select" : 
				//:todo:, + maltivalue	(miltiple=true)
				break;
			default:
				ibox.value = trim(ibox.value);
				val = ibox.value;
				switch (ibox.sortFormat) {
					case "date" :
						if (val != "") {
							val = FormatDateDb(val);
							if (val == null) {
								alert("Invalid date: " + ibox.value);
								ibox.focus();
								ibox.select();
								return;	
							} else {
								ibox.value = val;
							}
						}
						break;
					default :
				}
				break;
		}
		var v = trim(val);
		//var refObj = new Object();
		var changed = SetNode(node, field, v, true, true); //, refObj);
		if (changed) {
			if (autoRefresh) {
				try {
					//if (!refObj.newCreated || v != "") {
						ibox.style.backgroundColor = AuditOnScreenBgColor;
						ibox.oldBgColor = AuditOnScreenBgColor;
					//}	
				} catch(e) {}
			}
			var oldMode = null;
			try {
				oldMode = GetNodeVal(node, "@MODE", null);
			} catch(e) {}
			if (oldMode == null) {
				SetNode(node, "@MODE", "U");
				SetNode(node, "@UNDONE", null);
			}
			var saveBtn = document.all("btnSave");
			if (saveBtn != null) saveBtn.disabled = false;
		}
		
		try 
		{
			UseNewXML(); //this function should be implemented on a caller page
		} 
		catch(e) 
		{
			//alert("Error!" + e.message);
		}
	} else {
		alert(xp + " node not found in document \n\n" + doc.xml);
	}
	try { CorrectIMFormPosition(); } catch(e) {}
}	

//var isLoading = false;
function ChangeXmlTableFilter(list, recur) {
	var name = list.id.substring(7);
	var xp = "//" + name + "S/" + name;
	var val = list.value;
	var fld = list.fld;
	if (fld == null) return;
	//if (val != "") xp += 
	var rows = xml_data.selectNodes(xp);
	var N = rows.length;
	for (var i=0; i<N; i++) {
		var row = rows[i];
		if (val == "") {
			SetNode(row, "@hide", "");
		} else {
			var node = row.selectSingleNode(fld);
			if (node != null && node.text == val) {
				SetNode(row, "@hide", "");
			} else {
				SetNode(row, "@hide", "1");
			}
		}
	}
	if (recur != null) return;
	
	//Apply all other filters (if any): call the same procedure recursively for each filter
	var all = document.all(list.id);
	if (all.options == null) {
		for (var i=0; i<all.length; i++) {
			var lst = all[i];
			if (lst != list) ChangeXmlTableFilter(lst, true);
		}
	}
	
	var tableName = list.id.substring(4);
	refreshXmlTable(tableName);
	if (gLastSelectedRow != null) SelectRowById(gLastSelectedRow.uid, tableName, false);
	//if (!isLoading) FillLeftMenuTree();
}

function InitXmlFilterLists(ctlId) {
	var name = ctlId.substring(3);
	var xp = "//" + name + "S/" + name;
	var all = document.all("fltr" + ctlId);
	if (all == null) return false;
	if (all.options != null) all = new Array(all);
	var N = all.length;
	//var rows = xml_data.selectNodes(xp);
	for (var i=0; i<N; i++) {
		var list = all[i];
		var xp2 = xp + "/" + list.fld;
		var nodes = xml_data.selectNodes(xp2);
		var K = nodes.length;
		for (var k=0; k<K; k++) {
			var node = nodes[k];
			var val = node.text;
			if (FindInList(list, val) < 0) {
				list.options.add(new Option(val, val));
			}
		}
		if (list.showAlways == null && list.options.length < 3) list.style.display = "none";
	}
}

function FindInList(list, val) {
	var opt = list.options;
	var N = opt.length;
	for (var i=0; i<N; i++) {
		var c = opt[i];
		if (c.value == val) return i;
	}
	return -1;
}

function GetColumnByFied(ctlId, field) {
	var hdr = document.all("tbl_headers_" + ctlId);
	if (hdr == null) return;
	var cols = hdr.rows[0].cells;
	for (var i=0; i<cols.length; i++) {
		var col = cols[i];
		if (col.field == field) return col;
	}
	return null;
}

function HighlightNewTableRow(ctlId) {
	var tbl = getElement("tbl_list_" + ctlId);
	if (tbl == null || tbl.rows == null) return;
	var lastRow = tbl.rows[tbl.rows.length-1];
	//SyncTableHeight(ctlId);	
	//lastRow.scrollIntoView();
	
	var inp = GetFirstRowInput(lastRow);
	if (inp != null) {
		inp.focus();
		inp.select();
	}
	
	SelRow(lastRow);
	window.setTimeout("CorrectIMFormPosition()", 300);
	//var e = new Enumerator(tbl.rows)
	//for (; !e.atEnd(); e.moveNext()) {
	//	var r = e.item();
	//	var cols = r.cells;
	//	var N = cols.length;
	//	for (var i=0; i<N; i++) {
	//		var c = cols[i];
	//		var inList = (hideList.indexOf("," + i + ",") >= 0);
	//		c.style.display = (inList) ? "none" : "block";
	//	}
	//}
}

function GetFirstRowInput(r) {
	for (var i=0; i<r.cells.length; i++) {
		var cell = r.cells[i];
		var el = null;
		try { el = cell.firstChild.firstChild; } catch(e) {}
		if (el != null) {
			if (el.tagName == "INPUT") return el;
		}
	}
	return null;
}

