/*        Miscellaneous utilities for various Web 2.0 functions
  					 by R. Sutcliffe
  					Arjay Enterprises
  					
  				version 1.0    2007 09 12
   These utilities are drawn on either by the index.js file
   and are therefore not properly part of any one of the other packeges
   or by two or more of the other packages and are therefore abstracted out.
  */ 


			////////////////		Part One: shows and hides		/////////
					/* currently called from index.js only */

function HideID (theID, isDrop)
{
	theItem = document.getElementById(theID);
	theItem.drop = isDrop;
	Hide (theItem); 
}

function Hide (theItem)
{
	if (theItem.drop) theItem.style.display="none"
	else theItem.style.visibility = "hidden"
}

function ShowID (theID, isDrop)
{
	theItem = document.getElementById(theID);
	theItem.drop = isDrop; 
	Show (theItem);
}

function Show (theItem)
{
	if (theItem.drop) theItem.style.display="block"
	else theItem.style.visibility = "visible"
}

	// condShowHide does nothing if the item is not there
	// shows the item if the triggerID is present
	// and hides it otherwise
	// show/hide action is the opposite if the trigger ID is preceeded by "!"

function condShowHide (triggerID, itemID, isDrop)
{	
	if (!document.getElementById(itemID)) return // do nothing if item cannot be found
	isDrop = (isDrop == null || isDrop) // isDrop defaults to true
	var negOption = (triggerID [0]=="!") // see if neg option
	if (negOption) triggerID = triggerID.slice(1) // strop from triggerId if there
	var thetrig = document.getElementById(triggerID) // get the trigger item
	if (thetrig != null && !negOption || thetrig == null && negOption) ShowID (itemID, isDrop)
	else  HideID (itemID, isDrop)
}

	// clickhide enables us to have a goaway item in any element
function clickHide (triggerID, itemID, isDrop)
{
	if (!document.getElementById(itemID)) return // do nothing if item cannot be found
	isDrop = (isDrop == null || isDrop) // isDrop defaults to true
	var thetrig = document.getElementById(triggerID) // get the trigger item
	if (thetrig != null) thetrig.onclick = function() {HideID (itemID, isDrop)}
}

			////////////////		Part Two: Logon utility		/////////
					/* Called from an actual page form in the html */

function set_target()
{
	var
		username, password, servername, port_option, protocol;
		username     = document.forms.login_form.user.value;
		password     = document.forms.login_form.pass.value;
		servername   = document.forms.login_form.server.value;
		port_option  = document.forms.login_form.port_option.value;
		port_option == '2083' || '2096' || '2087' ? protocol = 'https://' : protocol = 'http://' ;
		document.forms.login_form.action = protocol + servername + ':' + port_option + '/login';
}


			////////////////		Part Three: GetElements	Package	/////////

/*    			version 1.1		2007 04 19
  				version 1.2		2007 09 04
  					removed bug affecting ie. Was trying to index strings by char as str[n] rather than str.charAt(n). ie allows only the latter.
*/

// Universal get element, gets from either the ID or just returns the original if already an object.
function getElementObj (elementToFetch)
{
	if (typeof elementToFetch == "string")
		return (document.getElementById (elementToFetch));
	else
		return (elementToFetch);	
}
                                          
// get a list of elements per the provided selector
// look; there are a lot of such functions, including ones more versatile but heavier
		// if you want to have the functionality to do attributes, pseudoclasses or some other possibilities
		// we left out, use one of those as a substitute. It should just plug in.
		// This one takes a selector in two parts, parses it to simple selectors, then uses
		// the first as an antecedent (for a descendent <space>, child <less than> or next sibling <plus>) with the usual syntax
		// and returns the selected list of objects.
		// a given tag (type), ID or class is allowed to be a comma delimited list of same
		// so you can use div,a>#id1,id2,id3, for instance
       
function  getElementsBySelector (selector)
{ 
	var objectList = [];
	var firstSelItems = [];
	var secondSelItems = [];
	var nodeToStart;
	var parsedSel = parseSelector (selector);
	var len, len2;
	firstSelItems = getElementsBySimpleSelector (parsedSel [0]); //fetch the objs for the leftmost selector
	if (!parsedSel [1]) {return (firstSelItems);} 
	combinator = parsedSel [1]; 
	len = firstSelItems.length; 
	for (var i = 0; i < len; i++)
		{   
			nodeTostart = (combinator == "adjsibling")? firstSelItems[i].parentNode:firstSelItems[i] // get children of the parent if a sibling; filter for next sibling later
			secondSelItems = getElementsBySimpleSelector (parsedSel [2], nodeTostart, (parsedSel [1] == "child")||(parsedSel [1] == "adjsibling"));
			if (combinator == "adjsibling") secondSelItems=filterListByAdjSibling (secondSelItems, firstSelItems[i]);
			len2 = secondSelItems.length; 
			for (var j = 0; j < len2; j++) {objectList[objectList.length] = secondSelItems[j]; }
		}
	if (objectList.length == 0 && printSelErrors) window.alert (selErrorMsg + selector + ".")
	return (filterListByDupes(objectList));
}

// this function parses a selector into <simpleselector> [<combinator> <simpleselector>]? where <combinator> = descendent|child|adjsibling
function parseSelector (selector)
{
	var parsedSelector = [];
	var re = /^(\S+[a-zA-Z]+)\s*(\s+|\+|>)\s*(\S*)$/;
	var splitSelector = re.exec(selector); 
	if (!splitSelector) parsedSelector[0] = selector // case of bare simple selector
	else
		{
			parsedSelector [0] = splitSelector [1]
			parsedSelector [1] = (splitSelector [2] ==" ")? "descendent" : (splitSelector [2] ==">")? "child" :"adjsibling"
			parsedSelector [2] = splitSelector [3]
		}
	return parsedSelector;
}

// The next one is for picking apart a simple selector
// the selector is a single word, and may be a (qualified) id, a class, or a  tag (type) or a comma delimited list of same
// if a start node is given the search starts from that parent
// if childrenOnly is set then only immediate children of the given node are returned
// even if you leave out the "." or the "#" for starting a class or id (or list of), it will still find them
// although this is less efficient

function getElementsBySimpleSelector (selector, startNode, childrenOnly)
{	
	if (startNode == null) startNode = document; // use whole document
	var sel=[];
	var selid="";
	var selclass="";
	var tag;
	var theEls = [];
	var elList= [];
	var len;
	    // first try an id selector like #id or "tag#id" where "id" can be "id1,id2,id3..." (only one "#" needed) 
	if(selector.indexOf("#") >= 0) 
		{
			sel=selector.split("#"); 
			tag = sel[0].toUpperCase();
			selid =sel [1];  // store the id following it
			if(selid!="") //there must be an id for us to do this, or we skip this section
				{ 
					theEls = getElementsById(selid); // our function; splits a list, returns all objects for the ids
					len = theEls.length;
					for (var i = 0; i < len; i++)
					{
						if ((tag!="" && theEls[i].nodeName==tag) || tag == "") //enforce correctness of tag if present
							// now filter for child or descendent as needed
							if (childrenOnly) // the more restrictive case
							   {if (theEls[i].parentNode == startNode) elList[elList.length]=theEls[i]}
							else if (isNodeDescendentOf (theEls[i], startNode) || startNode == document) elList[elList.length]=theEls[i]; // return only if no tag or tag agrees
					}
					return (elList);
				}
		}

	// if we get here there is no "#" (id), so try for a "." (class)
	if (selector.indexOf(".") >= 0) //class selector like "tag.class" or just tag.
		{  
			sel = selector.split (".");
			tag = sel[0].length > 0 ? sel[0].toUpperCase() : "*"; // use * for default tag; finds everything
			selclass = sel[1]; // and the part after the point for the classname 
			elList = getElementsByClass (selclass, startNode, tag); // works on a comma delimited list of classes too
				// already filtered by startNode and tag, so filter for direct children required
			if (childrenOnly) elList = filterListByParent (elList, startNode); 
			return(elList);
		}
		
	// if we get here, original selector has neither a "#" nor a "." so must be a bare word, that is an tag or an id, or a class
	// the latter two aren't the best use of such designators, but we'll keep working away at this turkey anyway

	elList = getElementsByTag(selector.toUpperCase(), startNode); // try the bare word as a tag (type) (or list of)
	if (elList.length == 0) elList=getElementsById(selector); // if not, see if the bare word is an id (or list of)
	if (elList.length == 0) elList=getElementsByClass(selector, startNode); // if neither, try the bare word as a class (or list of)
	if (elList&&childrenOnly) elList = filterListByParent (elList, startNode);
	return(elList); 
}

// a debugging function that gives access to the above by ID
function getElementsBySimpleSelectorsId (selector, startId)
{
	var startNode = document.getElementByIdstartId;
	return (getElementsBySimpleSelector (selector, startNode));
}

// JavaScript does not have the following function, so we cook one up
// the searchClass can be a comma delimited list of classes
// and each may be preceeded by a ! (not) which gets passed to the filter, and means all matching classes by this one (these ones)
function getElementsByClass (searchClass, startNode, tag) // we make it fairly versatile, even though we may not be using all the functionality
{ 
	var newList = [];
	var v = [];
	var w = []
	var len;
	var len2;
	var filterOut;

	if (startNode == null) startNode = document; // no start so use whole document
	if (tag == null) tag = '*'; // default tag
	filterOut = (searchClass.charAt(0) == "!") //test for negative option & set flag
	if (filterOut) searchClass = searchClass.slice(1); // remove the bang if present

	var classList = commaListToArray (searchClass); // separate out all the classes in the list
	len = classList.length; 
	v = startNode.getElementsByTagName(tag); // get everything from that node on with that tag (type) as the initial list
	if (filterOut) // remove all items with the classes indicated from the original list and return it
		{
			for (var i = 0; i < len; i++)
				v = filterListByNotClass (v, classList[i]);
			newList = v;
		}	
	else // add items with the named classes to a list and return that
		{
			for (var i = 0; i < len; i++)
				{ 
					w = (filterListByClass (v, classList[i])); // cherry pick the ones we wwant
					len2 = w.length;
					for (var j = 0; j < len2; j++) 
						newList [newList.length] = w [j] // and append them
				}
		}
	return (filterListByDupes(newList));
}

function getElementsById (searchId) // gets elements by the ids in a potentially comma delimited list of ids
{ 
	var id;
	var newList = [];
	var idList = commaListToArray (searchId);
	var len = idList.length
	for (var i = 0; i < len; i++)
		{
			id =document.getElementById(idList[i])
			if (id) newList[newList.length] = id
		}
	return (newList);
}


function getElementsByTag (searchTag, startNode) // gets elements by the tag (type) in a potentially comma delimited list of tags
{ 
	var tag; 
	var v = [];
	var len;
	var len2;
	if (startNode == null) startNode = document; // no start so use whole document
	var newList = [];
	var tagList = commaListToArray (searchTag);
	len = tagList.length; 
	for (var i = 0; i < len; i++)
		{
			v = startNode.getElementsByTagName(tagList[i].toUpperCase())
			len2 = v.length;
			for (var j = 0; j < len2; j++) {newList [newList.length] = v [j]}
		}
	return (newList);
}

// next two functions needed because the interpretation of what the next sibling is is too literal & depends on whats on page, such as text.
function GetNextSiblingObj (node)
{
	do node = node.nextSibling;
	while (node && node.nodeType != 1);
	return node;
}

function GetPrevSiblingObj (node)
{
	do node = node.previousSibling;
	while (node && node.nodeType != 1);
	return node;
}

// Next one is just to check if we are a descendent of a given node. Use for filtering
function isNodeDescendentOf (node, theAncestor)
{ 
	result = false;
	parentToTry = node.parentNode
	do
		{
			if (parentToTry == theAncestor) result = true;
			else parentToTry = parentToTry.parentNode;
		} 
	while (!result && parentToTry != document)
	return result;
}

function commaListToArray (string)
{ 
	var newList = [];
	if (string == null ) return (string);
	if (string.indexOf (",") >=0) newList=string.split(",")
	else newList[0] = string
	return (newList);
}

// now for some filter functions
function filterListByClass (list, theClass)
{ 
	var len = list.length;	
	var newList=[];
	for (var i = 0;i < len; i++)
		if (list[i].className == theClass)
			newList[newList.length] =list[i];	// and if so, append to the return list. Not all JS has push, so use this instead		
	return newList;
}

function filterListByNotClass (list, theClass)
{
	var len = list.length;	
	var newList=[];
	for (var i = 0; i < len; i++)
		if (list[i].className!=theClass)
			newList[newList.length] = list[i]; 
	return newList;
}
	

function filterListByTag (list, tag)
{ 
	var newList=[];
	var len = list.length;	
		for (var i = 0;i < len; i++)
			if (list[i].nodeName == tag)
				newList[newList.length] =list[i];			
	return newList;
}


function filterListByParent (list, theParent)
{ 
	var newList=[];
	var len = list.length;	
		for (var i = 0;i < len; i++)
			if (list[i].parentNode == theParent)
				newList[newList.length] =list[i];			
	return newList;
}

function filterListByAncestor (list, theAncestor)
{
	var newList=[];
	var len = list.length;
		for (var i = 0;i < len; i++)
			{
				parentToTry = list[i].parentNode
				do
					{
						if (parentToTry == theAncestor) newList[newList.length] =list[i];
						else parentToTry = parentToTry.parentNode
					} 
				while (parentToTry != document)
			}	
	return newList;
}

function filterListByAdjSibling (list, theSibling)
{ 
	var newList=[];
	var nodeToCheck = GetNextSiblingObj (theSibling)
	if (!nodeToCheck) return (newList);
	var len = list.length;	
	for (var i = 0;i < len; i++) 
		if (nodeToCheck == list[i]) {newList[newList.length] =list[i];	return newList;}
	return newList;
}

function filterListById (list, theId)
{ 
	var newList=[];
	var len = list.length;	
	for (var i = 0;i < len; i++)
		if (list[i].Id == theId) newList[newList.length] =list[i];			
	return newList;
}

function doesListContain (list, value)
{
	if(list == null) return false;	
	for (var i=0; i < list.length; i++)
		if(value == list[i]) return true;
	return false;
}

function filterListByDupes (list)
{
	if(list == null) return null;	
	var newList=[];
	for (var i=0; i < list.length; i++)
		if (!doesListContain (newList, list[i])) newList[newList.length] =list[i]
	return newList;
}	


			////////////////		Part Four: Writing the date		/////////

function writeDate ()
{
	today = new Date();
	var Year;
	var Month;
	var day;
	var Hours;
	var Mins;
	var DateStr;
	Year = today.getYear();
	   if (Year < 1900) {Year = Year + 1900;}
	Month = today.getMonth();
	  Month = Month + 1;
	  if (Month < 10) {Month = "0" + Month;}	
	Day = today.getDate();
	  if (Day < 10) {Day = "0" + Day;}
	Hours = today.getHours();
	  if (Hours < 10) {Hours = "0" + Hours;}
	Mins = today.getMinutes();
	  if (Mins < 10) {Mins = "0" + Mins;}
	  <!-- Assemble string -->	
	DateStr = '<div id = "datestr">' + "<i>for</i>&nbsp;&nbsp;" + Year + "&nbsp;"+ Month + "&nbsp;" + Day + "&nbsp;&nbsp;<i>at</i>&nbsp;" + Hours + Mins +"</div>"

	document.write (DateStr);
}



			////////////////		Part Five: URL Utilities		/////////

// feed the following a complete URL and get back only the directories

function pathDir (theUrl)
{
	hName = location.host;
	dStart = theUrl.indexOf (hName) + hName.length + 1;
	dEnd = theUrl.lastIndexOf ("/") +1
	//debug (theUrl + "  start = " + dStart + "  end = " + dEnd + " return= " + theUrl.slice (dStart,dEnd))
	return theUrl.slice (dStart,dEnd)
}

function file (theUrl)
{
	dStart = theUrl.lastIndexOf ("/") +1
	return theUrl.slice (dStart)
}

function path (theUrl)
{
	hName = location.host;
	dStart = theUrl.indexOf (hName) + hName.length + 1;
	return theUrl.slice (dStart)
}

function isLocalLink(theUrl)
{
	if (theUrl.indexOf (location.host) == -1) return false
	else return true
}

function lastDirName (theUrl)
{
	re = /^(.+\/)+(.+\/)+(.*)$/;
	var uArray = re.exec(theUrl);
	if (uArray) return (uArray[2])
	else return ("")
}

/* Following takes links within the page system and adjusts them according to whether they are inside a folder
if the link is of the form ../thePage, this won't help much, so turn off the auto variable in the locus
file and put in a manual call to this proc with the selector adjusted for classes
Look, this thing is a kludge, all right, but it will solve some problems.

*/
function adjustLocalLinksByDir (selector, start, parentUrl)
{
	var startNode = getElementObj(start)
	dir = pathDir (parentUrl)
	host = location.host
	prot = location.protocol+"//"
	//debug (dir)
	if (selector == null) 
		var list = getElementsByTag ("a", startNode)
	    else var list = getElementsBySelector (selector)
	var len = list.length;	
	for (var i = 0;i < len; i++)
		if (isLocalLink(list[i].href))
			list[i].href = prot+host+"/"+dir+path(list[i].href);
}

			////////////////		Part six: Handler Utilities		/////////
					/* This section is experimental */

function addOnload() {
	if (typeof(window.onload) != 'function') {
		window.onload = piInit;
	} else {
		var oldOnload = window.onload;
		window.onload = function () { oldOnload(); piInit(); }
	}
}

function addOnClick(element, newClickFunction)
{	debug ("here1" + newClickFunction)
var oldOnClick = element.onclick; 
debug ("here1" + oldOnClick)
	element.onclick = function ()
		{debug ("here3")
			if (typeof(oldOnClick) == 'function') {debug ("here4");oldOnClick (); debug ("here5")}
			newClickFunction (); debug ("here6")
		
	}
	debug ("here7"+element.onclick)
}



// add an event handler, such as "load", "click", "hover" etc
// the function will prepend the word "on"
function addEventHandler (eSource, eType, func)
{
	eSource =  getElementObj (eSource) // convert to obj
	var eStr = "eSource.on" + eType; //debug (eStr +eSource.Id)
	var eHandler = eval (eStr);
	// we haven't gotten the next part tested yet.
	if (typeof eHandler == 'function') {  eval (eStr + " = function() {eHandler(); func();}");} // if existing sequence, append	//debug ("here3     "+eStr + " = function() {eHandler(); func();}" +"   "+eHandler+"    "+func);
	else  eval(eStr + " = func;"); // else attach as first handler
}


function addEventHandlerB (eSource, eType, func)
{calls++
	eSource =  getElementObj (eSource) // convert to obj
	var eStr = "eSource.on" + eType;
	var eHandler = eval (eStr);  debug (calls + eHandler + " x  " +eStr +"  y  "+func+"  z  "+eSource.Id)
	// we haven't gotten the next part tested yet.
	if (typeof eHandler == 'function') { debug ("here3     "+eStr + " = function() {eHandler(); func();}"); eval (eStr + " = function() {"+eHandler+";"+ func+"}");} // if existing sequence, append	//
	else  eval(eStr + " = func;"); // else attach as first handler
	debug (eSource.onclick)
}



