/*
	DynaTable - A DHTML-based Table Data API
	XML Recordset Object
	Version 0.9a (14-Mar-04)
	Copyright (C) 2004 Daniel Nolan (dynatable@danere.com)
	
	For more information, visit the DynaTable Website:
	http://dynatable.sourceforge.net

	This program is free software; you can redistribute it and/or modify it 
	under the terms of the GNU General Public License as published by the 
	Free Software Foundation; either version 2 of the License, or (at your 
	option) any later version.
	
	This program is distributed in the hope that it will be useful, but 
	WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
	or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
	for more details.
	
	You should have received a copy of the GNU General Public License along with 
	this program; if not, write to the Free Software Foundation, Inc., 59 Temple 
	Place, Suite 330, Boston, MA 02111- 1307 USA
*/
if (window.XMLDocument && !XMLDocument.prototype.selectNodes)
{
	Element.prototype.selectNodes = XMLDocument.prototype.selectNodes = function (s_xpathExpr)
	{ 
		var result = ((this.ownerDocument)?this.ownerDocument:this).evaluate(s_xpathExpr, this, null, 0, null);
		var node;
		var nodes = new class_dynatable_collection;
		while ( (node = result.iterateNext()) ) 
			nodes.add(node);
		return nodes;
	}
	Element.prototype.selectSingleNode = XMLDocument.prototype.selectSingleNode = function(s_xpathExpr) 
	{
		return ((this.ownerDocument)?this.ownerDocument:this).evaluate(s_xpathExpr, this, null, 9, null).singleNodeValue;
	}
}

with (behavior_dynatable_xmlRecordset = inheritFrom(behavior_dynatable_recordset))
{
	prototype.name = "XML_RECORDSET";
	prototype.loading = false;

	prototype.xmlDocument = null; // XMLDocument
	prototype.nodePath = null; // XPath String
	prototype.nodeInsertPath = null; // XPath String
	prototype.nodeTagName = null; // String
	prototype.valueAttrName = null; // e.g. "value"

	prototype.saveRecordInfo = false; // Move to ancestor?
	prototype.useTextValueForReadOnly = false; // When populating a read-only field (such as a SPAN's text) use the XmlText of the Node instead of the Code attribute

	prototype.init = function(oGrid)
	{
//		this.nodePath = oGrid.domTableNode.getAttribute("dtblNodesPath");

		this.reg("beforeactivate", this.checkRecordset);
	
		oGrid.rowDef.xmlNode = null;
		oGrid.recordset = this;
	
		oGrid.rowDef.getRecordsetValue = function(fieldName, getDisplayText)
		{
			if (this.sect != this.sect.grid.rowItemSect) return;
			if (!fieldName) return;
			// IEXML: Conformed to W3C: var oNodes = this.xmlNode.selectNodes(fieldName); // getElementsByTagName
			var attr;
			var oNodes = this.xmlNode.selectNodes(fieldName);
			if (oNodes.length)
			{
				var s_code;
				var node = oNodes.item(0);
				return (!getDisplayText && this.sect.grid.recordset.valueAttrName && (attr = node.attributes.getNamedItem(this.sect.grid.recordset.valueAttrName)) != null && (s_code = attr.nodeValue) != null) ? s_code : ((node.hasChildNodes()) ? node.firstChild.nodeValue : ""); // IEXML: "text" instead of getText()
			}
			else
			{
				return ((attr = this.xmlNode.attributes.getNamedItem(fieldName)) != null) ? attr.nodeValue : ""; // IEXML: Conformed to W3C "getAttribute(fieldName)"
			}
		}
	
		oGrid.rowDef.setRecordsetValue = function(fieldName, fieldVal, fieldText, noEvent)
		{
			if (this.sect != this.sect.grid.rowItemSect) return;
			// IEXML: Conformed to W3C: var oNodes = this.xmlNode.selectNodes(fieldName);
			if (fieldName)
			{
				var oNodes = this.xmlNode.selectNodes(fieldName);
				if (oNodes.length)
				{
					var n = oNodes.item(0);
					if (this.sect.grid.recordset.valueAttrName && n.attributes.getNamedItem(this.sect.grid.recordset.valueAttrName) != null) 
					{
						n.setAttribute(this.sect.grid.recordset.valueAttrName, fieldVal);
	
						var oField;
	
						if (fieldText == null)
						{
							if ((oField = this.fields.byName[fieldName]) != null) fieldText = oField.getControlValue(true);
								else return; // Can't find place to put value
						}
						if (fieldText == null) fieldText = "";
	
						if (!n.hasChildNodes()) n.appendChild(n.ownerDocument.createTextNode(fieldText));
							else n.firstChild.nodeValue = fieldText;
						
					}
					else
					{
						if (fieldVal == null) fieldVal = "";
						if (!n.hasChildNodes()) n.appendChild(n.ownerDocument.createTextNode(fieldVal));
							else n.firstChild.nodeValue = fieldVal;
					}
				}
				else
				{
					this.xmlNode.setAttribute(fieldName, fieldVal);
				}
			}
	
			if (!noEvent && !this.sect.grid.recordset.loading)
			{
				if (this.sect.grid.recordset.saveRecordInfo) this.setRecordsetValue(DTBL_FIELDINFO_MODIFIED, new Date, null, true);
				this.fireEvent("recordsetupdate");
			}
		}
	}

	prototype.addRowBindNode = function(xmlNode, insertBefore)
	{
		var o_newRow = this.context.addRow(insertBefore, false);
		o_newRow.xmlNode = xmlNode;
		o_newRow.activate();
	}

	prototype.updateField = function(oSect, evt) // Move to ancestor?
	{
		//var s_customPath;
		
		if (this.loading) return;
		var c = evt.dynatableItem;
		var oRow = evt.dynatableRow;
		if (c.prefix != DTBL_PREFIX_FIELD) return;
		oRow.setRecordsetValue(c.nodePath, c.getValue(), c.getControlValue(true)); // (s_customPath = c.domNode.getAttribute("dtblPath")) ? s_customPath : c.name
	}

	prototype.checkRecordset = function(oGrid, evt)
	{
		if (!this.xmlDocument) return dtbl_handleErr("XMLDocument was not specified.", this.name); //  || !this.nodePath

		var fld;
		for (var i=0; i<oGrid.fields.length; i++)
			if ((fld = oGrid.fields.item(i)).nodePath==null)
				fld.nodePath = fld.name;
		
//		this.saveRecordInfo = (this.nodeTemplate && this.nodeTemplate.attributes.getNamedItem("dtbl_date_created") != null);

		if (this.nodePath)
		{
			var ar_pathParts = this.nodePath.split("/");
			var s_lastPart = dtbl_removeFromArray(ar_pathParts, ar_pathParts.length-1);
	
			if (!this.nodeTagName) this.nodeTagName = s_lastPart.split("[")[0];
			if (!this.nodeInsertPath) this.nodeInsertPath = ar_pathParts.join("/");
			this.load();
		}
		
		this.reg("update", this.updateField, this.sect);
		this.reg("rowinsert", this.insertRow, this.sect); // if (this.nodeTemplate)
		this.reg("rowdelete", this.deleteRow, this.sect);
		this.reg("rowmove", this.moveRow, this.sect);
	}

	prototype.load = function (xmlDocument)
	{
		if (xmlDocument) this.xmlDocument = xmlDocument;
		this.loading = true;
		var bHoldGridActive = this.grid.activated;
		if (bHoldGridActive) this.grid.activated = false;
		this.sect.empty();

		var evt = new Object;
		evt.xmlDocument = this.xmlDocument;
		if (this.nodePath)
		{
			//evt.xmlNodes = this.nodeParent.getElementsByTagName(this.nodePath);
			evt.xmlNodes = this.xmlDocument.selectNodes(this.nodePath);
		}
		else // Don't know if this is relevant...
		{
			evt.xmlNodes = this.nodeParent.childNodes;
			//(evt.xmlNodes = new class_dynatable_collection()).add(this.nodeParent);
		}
/*		if (!this.grid.keyFieldName)
		{
			var o_node = (evt.xmlNodes.length) ? evt.xmlNodes.item(0) : this.nodeTemplate;
			if (o_node && o_node.getAttribute("id")) this.grid.keyFieldName = "id";
		}*/
		
		if (this.context.fireEvent("beforerecordsetload", evt)!=false)
		{
			for (var i=0; i<evt.xmlNodes.length; i++)
				this.populateRow(this.sect.addRow(null, false), evt.xmlNodes.item(i));

			this.loading = false;
			this.grid.activated = true;

			this.context.fireEvent("recordsetload", evt);

		}
		this.loading = false;
		this.grid.activated = bHoldGridActive;
	}

	prototype.populateRow = function(oRow, oNode)
	{
		var b_getDispText;
		var b_watchForVals = false;
//		var s_customPath = "";
		
		if (oNode) oRow.xmlNode = oNode;
		if (oRow.fireEvent("beforerowpopulate")==false) return false;
		if (!oRow.activated) oRow.activate();
			else b_watchForVals = true;
			
		for (var fieldName in oRow.fields.byName)
		{
			var field = oRow.fields.byName[fieldName];
			b_getDispText = (this.useTextValueForReadOnly && field.controlType == "readonly");
			if (field.nodePath && (!b_watchForVals || !field.getValue())) 
				field.setValue(oRow.getRecordsetValue(field.nodePath, b_getDispText)); // (s_customPath = field.domNode.getAttribute("dtblPath")) ? s_customPath : fieldName
		}

		oRow.fireEvent("rowpopulate");
		return oRow;
	}
	
	prototype.insertRow = function(oSect, evt)
	{
		if (this.loading) return;
		var r = evt.dynatableRow;
		// IEXML: Changed from: "xmlNode = this.nodeParent.appendChild(this.nodeTemplate.cloneNode(true));"
//		if (this.nodeParent.ownerDocument.importNode) r.xmlNode = this.nodeParent.appendChild(this.nodeParent.ownerDocument.importNode(this.nodeTemplate, true));
		if (!r.xmlNode) r.xmlNode = this.xmlDocument.createElement(this.nodeTagName); // this.nodeTemplate.cloneNode(true);
		if (r.fireEvent("datanodeconstruct", evt)==false) return false;
		this.xmlDocument.selectSingleNode(this.nodeInsertPath).appendChild(r.xmlNode);
		r.fireEvent("recordsetupdate");
		this.populateRow(evt.dynatableRow);
		if (this.saveRecordInfo) r.setRecordsetValue(DTBL_FIELDINFO_CREATED, new Date, null, true);
	}
	
	prototype.deleteRow = function(oSect, evt, noEvent)
	{
		if (this.loading) return;

		evt.dynatableRow.xmlNode.parentNode.removeChild(evt.dynatableRow.xmlNode);

		if (!noEvent) evt.dynatableRow.fireEvent("recordsetupdate");
	}

	// IEXML: Added
	prototype.moveRow = function(oSect, evt)
	{
		var node = evt.dynatableRow.xmlNode;
		if (evt.dynatableRow.getIndex() == (oSect.rowCount()-1))	node.parentNode.appendChild(node);
			else node.parentNode.insertBefore(node, oSect.rows.item(evt.dynatableRow.getIndex()+1).xmlNode);
		
		evt.dynatableRow.fireEvent("recordsetupdate");
	}
	
	// IEXML: Added
	prototype.getXML = function ()
	{
		return dtbl_getXML(this.xmlDocument);
// was for XML4Script:		return this.nodeParent.ownerDocument.getXML();
	}
}