/** ------------------------------------------------------------------------------------
Author: Dean Stringer (deeknow @ pobox . com)
Original Release Date: 22/Mar/2006
This Release Date: 27/Apr/2006
Version: 0.7
Description/Purpose:

	Provides support utilities for manipulating DOM objects, mostly
	used in partnetship with treeEdit.js

	Requires a browser supporting the DOM and parsing of XML
	(this means IE5.5+, Mozilla/Firefox, Netscape6+, Opera8+ amongst 
	others)

	Useful resources:
		http://www.quirksmode.org/dom/
		http://www.w3schools.com/dom/dom_element.asp

LICENSE

treeUtils.js: misc DOM and AJAX related utitities
Copyright (C) 2006  Dean Stringer (deeknow @ pobox . com)

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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

*/

var utils = {};

/** ------------------------------------------------------------------------------------

		The following are generic and utility functions, AJAX and DOM inspection related stuff etc
	
	------------------------------------------------------------------------------------ */


/**
 * Takes a node and serialize, uses the proprietary xml() method if IE otherwise
 * uses the XMLSerializer object in Moz/FF etc
 * @param {Node} xmlNode - node to render as plain-text
 */
function serializeXML(xmlNode) {
	if (window.XMLHttpRequest) {	// assume Moz/FF etc
		var mySerializer = new XMLSerializer();
		return mySerializer.serializeToString(xmlNode);
	} else { // assume IE
		return xmlNode.xml;
	}
}


/**
 * Performs a platform independant asynchronous AJAX request. Checks if IE and
 * uses 'Microsoft.XMLHTTP' object, or 'XMLHttpRequest' if not for FF/Mozilla etc
 * sets up a process request change handler to listen for the response.
 * @param {String} thisMethod - GET (default) or POST
 * @param {String} remoteFile - name of remote resource to update
 * @param {String} thisData - data to send (typically XML)
 */
utils.doAsynchRequest = function (thisMethod, remoteFile, thisData){
	if (thisMethod != 'GET' && thisMethod != 'POST') {		thisMethod = 'GET'; 	}
	var rndCacheStopper = Math.round(Math.random()*999999);
    var url = tree.dataURL + remoteFile + '&amp;rnd=' + rndCacheStopper;
	if (thisData != null) {	thisData = serializeXML(thisData); }
	//alert('mode: ' + thisMethod + ' file: ' + remoteFile + ' data: ' + thisData);
	if (window.XMLHttpRequest) {
        tree.dataReq = new XMLHttpRequest();	// non-IE support
    } else if (window.ActiveXObject) {
        tree.dataReq = new ActiveXObject("Microsoft.XMLHTTP");	// IE 5+ support
    }
    tree.dataReq.onreadystatechange = asynchGetProcessReqChange;
    tree.dataReq.open(thisMethod,	// method
					url,	// target URL
					true	// async flag
					);		// can also send username/pwd authentication info

	if ((thisMethod == 'POST') && window.ActiveXObject) {
		// for some reason IE must send the text/xml header otherwise no data is received by the CGI
		tree.dataReq.setRequestHeader("Content-type", "text/xml");
	}
    tree.dataReq.send(thisData);

	//setRequestHeader("Content-type", "application/x-www-form-urlencoded");
	//.setRequestHeader("Content-length", parameters.length);
	//.setRequestHeader("Connection", "close");
}



/**
 * AJAX handler that listens for and checks status of back-end response
 * the readyState property indicates:
 *		0 = uninitialized
 *		1 = loading
 *		2 = loaded
 *		3 = interactive
 *		4 = complete
*/
function asynchGetProcessReqChange() {
    if (tree.dataReq.readyState == 4) {	// complete, see above..
        if (tree.dataReq.status == 200) {	// HTTP status (could check for '500', '30n' or '40n's etc
            // process response
			//var treeAJAXresponse = treeDataReq.responseText;
			//var parser = new DOMParser();
			//tree.XmlDoc = parser.parseFromString(treeAJAXresponse, "text/xml");
			tree.XmlDoc =  tree.dataReq.responseXML;
			//alert('here' + tree.dataReq.responseText);
			asynchMsgStatusUpdate('');
			tree.renderForDisplay();
        } else {
			alert("there was an error requesting this page..\n" + tree.dataReq.statusText);
			asynchMsgStatusUpdate('');
		}
    }
}



/**
 *  Updates an HTML element with the id 'asynchMsg' with a passed string, used
 *  to indicate to user what the process is up to, eg 'Saving...' or 'Loading...'
 *  @param (String) thisMsg - message to be displayed
 */
function asynchMsgStatusUpdate(thisMsg) {
	var asynchMsg = utils.getByID('asynchMsg');
	asynchMsg.innerHTML = ' <b>' + thisMsg + '</b>';
}



/**
 * Uses getElementByID to find and return a requested element and
 * falls back to document.all[] if the former not supported
 * @param {String} itemid ID of the element whos object reference we want to return
 * @returns an element reference
*/
utils.getByID = function (itemid) {
	//alert('thisID = ' + itemid);
	  if (document.getElementById != null)
		  return document.getElementById(itemid)
	  if (document.all != null)
		  return document.all[itemid]
	  return null
}




/**
 * Searches a passed nodelist looking for child nodes with a given name and id attribute
 * returning the value of the text node the element contains
 * @param {NodeList} nodeList - nodes to search through
 * @param (String)   findNodeName - name of element we're looking for
 * @param (String)   id - value of attribute id of the node we're looking for
 */
function getNodeTextByID(nodeList, findNodeName, id) {
	for (i=0; i<nodeList.length; i++)	{
		var thisNoteID = nodeList[i].getAttribute('id');
		if (thisNoteID != id) continue;		// skip unless its the id we're looking for
		for (j=0; j<nodeList[i].childNodes.length; j++)	{
			var thisNode = nodeList[i].childNodes[j];
			if (thisNode.nodeType != 1) continue;	// skip unless a text node
			if (thisNode.nodeName == findNodeName) {
				if (thisNode.childNodes.length > 0) {
					return thisNode.firstChild.nodeValue;	// [todo] should fetch all children in case more than one text node
				} else {
					return '';
				}
			}
		}
	}
	return '';
}



/**
 * Searches a passed nodelist looking for child nodes with a given name and id attribute
 * and updates the value of the text node the element contains
 * @param {NodeList} nodeList - nodes to search through
 * @param (String)   findNodeName - name of element we're looking for
 * @param (String)   id - value of attribute id of the node we're looking for
 */
function saveItemNodeValue(nodeList, findNodeName, id, textValue) {
	for (i=0; i<nodeList.length; i++)	{
		var thisNoteID = nodeList[i].getAttribute('id');
		if (thisNoteID != id) continue;		// skip unless its the id we're looking for
		for (j=0; j<nodeList[i].childNodes.length; j++)	{
			var thisNode = nodeList[i].childNodes[j];
			if (thisNode.nodeType != 1) continue;	// skip unless a text node
			if (thisNode.nodeName == findNodeName) {
				if (thisNode.childNodes.length > 0) {
					thisNode.firstChild.nodeValue = textValue;
					return 1;
				} else {
					// no child text node, so create and add one
					var treeTextNode =  document.createTextNode(textValue)
					thisNode.appendChild(treeTextNode);
				}
			}
		}
	}
	return 0;
}



/** ------------------------------------------------------------------------------------

	single/double click handlers from: http://www.chipchapin.com/WebTools/JavaScript/example3-01.html

 ------------------------------------------------------------------------------------ */

var dcTime=250;    // doubleclick time
var dcDelay=100;   // no clicks after doubleclick
var dcAt=0;        // time of doubleclick
var savEvent=null; // save Event for handling doClick().
var savEvtTime=0;  // save time of click event.
var savTO=null;    // handle of click setTimeOut
 
 
 function hadDoubleClick() {
   var d = new Date();
   var now = d.getTime();
   if ((now - dcAt) < dcDelay) {
     return true;
   }
   return false;
 }
 
 function handleClick(which, thisWord) {
   switch (which) {
     case "click": 

       // If we've just had a doubleclick then ignore it
       if (hadDoubleClick()) return false;
        
       // Otherwise set timer to act.  It may be preempted by a doubleclick.
       savEvent = which;
       d = new Date();
       savEvtTime = d.getTime();
       savTO = setTimeout("doClick('" + thisWord + "')", dcTime);
       break;
     case "dblclick":
       doDoubleClick(which);
       break;
     default:
   }
 }
 
 function doClick(thisWord) {
   // preempt if DC occurred after original click.
   if (savEvtTime - dcAt <= 0) {     return false;   }
   customHandler(thisWord);
 }
 
 function doDoubleClick(which) {
   var d = new Date();
   dcAt = d.getTime();
   if (savTO != null) {
     clearTimeout( savTO );          // Clear pending Click  
     savTO = null;
   }
   // we dont actually wanna do anything for a double-click, just let it fall thru to the container doubleclick event
   //alert("Handle DoubleClick at " + dcAt);
 }



function asynchFlickrGet(thisWord){
	var rndCacheStopper = Math.round(Math.random()*999999);
    var url = customFlickrProxy + '?tag=' + thisWord + '&amp;rnd=' + rndCacheStopper;
	if (window.XMLHttpRequest) {
        auxDataReq = new XMLHttpRequest();	// non-IE support
    } else if (window.ActiveXObject) {
        auxDataReq = new ActiveXObject("Microsoft.XMLHTTP");	// IE 5+ support
    }
    auxDataReq.onreadystatechange = asynchFlickrProcessReqChange;
    auxDataReq.open('GET',	// method
					url,	// target URL
					true	// async flag
					);		// can also send username/pwd authentication info

    auxDataReq.send(null);
}

function asynchFlickrProcessReqChange() {
    if (auxDataReq.readyState == 4) {	// complete, see above..
        if (auxDataReq.status == 200) {	// HTTP status (could check for '500', '30n' or '40n's etc
			var flickrAJAXresponse = auxDataReq.responseText;
			var flickrImg = utils.getByID('flickrImg');
			flickrImg.innerHTML = flickrAJAXresponse;
        } else {
			alert("there was an error requesting this page..\n" + auxDataReq.statusText);
		}
    }
}
