//START OF COMMON CODE WITH SERVER SCRIPTS

// this file contains java that is common to client and server side scripts
// for client side it is included in ydrClientScripts.js
// for server side it is included in ydrServerScripts.asp

// the code is to be kept IDENTICAL with the client side being editted and the
// server side copied save that the server side is encapsulated in < % % >

// the method and the function trim remove whitespace from the front and end of a string 
// the function trim also tolerates an undefined variable

var sendMailPage="mailto:"
function ydrMessenger(destination, domain, subject, body)
{
	var details="";
		
	if (subject != undefined)
		details = "?subject="+escape(subject);
		
	if (body != undefined)
	{
		if (details.length>0)
			details+="&body=";
		else
			details = "?body=";
		details += escape(body);
	};
	
	if (sendMailPage== "mailto:")		
		window.location ="mailto:"+destination.replace(/#/g,".")+"@"+domain.replace(/#/g,".")+details;
	else
	{
		if (details.length<=0)		
			detail="?";
		window.location = "http://yorkdevres.co.uk/ydr/email.asp"+details+"&page="+escape(sendMailPage)+"&destination="+destination+"&domain="+domain;
	};	
	
	return false;
}

function String_trim()
{	
	var left=this.search(/\S/);
	
	if (left<0)	
		return this;
	
	return this.substring(left,this.search(/\s*$/));
}		
String.prototype.trim = String_trim;			

function trim(value)
{
	if (value == undefined || value == "--")
		return undefined;
	
	return value.trim();
}

// END OF COMMON CODE WITH SERVERSCRIPTS



function ydrAllCountValidate(id, property, expectedValue, minCount, maxCount)
{
	var foundAll = document.all(id);
	property=property.toLowerCase();
	
	var encountered=0;
	
	if (foundAll != undefined)
	{
		if (foundAll.length == undefined)
		{
			switch (property)
			{
				case "checked":
					if (minCount == 1)
					{
						foundAll.checked= expectedValue;
						encountered = 1;
					}
					else
						encountered = (foundAll.checked == expectedValue ? 1 : 0);
						
					break;
			};
		}
		else
		{	
			for (var i=0; i<foundAll.length; i++)
			{
				switch (property)
				{
					case "checked":
						if (foundAll(i).checked == expectedValue)
							encountered++ ;
							
						break;
				};
			};
		};
	}
	else
	{
		return "Error in Page: Cannot validate object '"+property+"'";
	};
		
	if (encountered < minCount)
		return "\n\nError in page data: field '"+id+"' must have at least " + minCount
			+ " members with '"+property+"' set to '"+expectedValue+"'.";
	else if (encountered > maxCount)
		return "\n\nError in page data: field '"+id+"' must have at most " + maxCount
			+ " members with '"+property+"' set to '"+expectedValue+"'.";
	else
		return "";
}

// early exclaim type validation of a data field
function ydrValidate(object, fmt, validation)
{
	var errorMessage="";
	var value;
	
	switch (fmt)
	{
		case "ft0decimals":
			value=trim(object.value);
							
			if (value != undefined)
				if (value != parseInt(object.value))
				{
					errorMessage += "\nValue is expected to be an integer";
					value = parseInt(object.value).toString();
					if (typeof(value) == "number")
						object.value = value;
					else
						object.value = "0";
				};
			break;
			
	}
	
	if (errorMessage.length >0)
	{
		ydrPopup.show ("Error in data content for "+object.id+" = '"+value+"'.\n"+errorMessage);
		return false;
	}
	else
		return true;
}

function once(activivity, observation)
{
	var msg= "Request Submitted - Please wait";
	
	if (activivity != undefined && observation != undefined)
	{
		if (0 < (document.getElementById(observation).innerHTML+"").length)
		{
			document.getElementById(activivity).visibility="hidden"; //stops self working 		
			document.getElementById(observation).innerHTML="<span Style='font-weight:bold; color:red;'>Your request has already been submitted - Please wait</span>";
			return false;
		}
		else
		{
			document.getElementById(observation).innerHTML="Request Submitted - Please wait";
			return true;
		}
	}
	else
	{
		document.getElementById(observation).innerHTML="Request Submitted - Please wait";
		return true;
	}
};



// static object serving client scripting functions
// DOMcarrier - hides the differences between IE and Netscape XML via HTTP object
// fullURLpath - turns a local relative path to a full relative path for the document location
// DOMcarrierListSearch - poor man's very poor xpath
// XMLHttpRequest - gets the best/nearest HTTP get object

var ydrClientScripts = new function ()
{
	// very simple xpath over a list made by listMaker()
	this.DOMcarrierListSearch = function(nodeList,attributeName,value,method)
	{
		switch (method)
		{
			case "=" :
				for (var i=0;i<nodeList.length;i++)
				{
					if (nodeList[i].getAttribute(attributeName) == value)
						return nodeList[i];
				};
				break ;
			case "!=" :
				for (var i=0;i<nodeList.length;i++)
				{
					if (nodeList[i].getAttribute(attributeName) != value)
						return nodeList[i];
				};
				break ;
		};
	};
	
	// this carrier maps many Netscape and Mozilla XML functions into a common mould
	// you can still access the underlying object by using the .element property
	// note that due to incompatibilities in available functions there are some strict limitations of 
	// use and 
	this.isIE = window.navigator.appName == "Microsoft Internet Explorer";
	this.DOMcarrier = function (domElement)
	{	
		if(window.navigator.appName == "Microsoft Internet Explorer")
			return new DOMcarrierIE(domElement)
		else /* if (window.navigator.appName="Netscape")*/
			return new DOMcarrierNetscape(domElement);
			
		function DOMcarrierNetscape(domElement)
		{
			function listMaker(nodeList)
			{
				var newList = new Array();
				
				for (var i=0;i<nodeList.length;i++)
				{
					newList[i]=new DOMcarrierNetscape(nodeList[i]);
				};
				
				return newList;
			};
			
			// about me
			this.element = domElement;
			this.type="Netscape";
			
			// mapped functions - all properties becomes methods with get and set
			this.getAttribute = function (name) { return this.element.getAttribute(name) }; 
			this.hasAttribute = function(name) { return this.element.hasAttribute(name) }; 
			this.hasAttributes = function() { return this.element.hasAttributes() }; 
			this.setAttribute = function (name,value) { this.element.setAttribute(name,value) };  
			this.removeAttribute = function(name) { this.element.removeAttribute(name) }; 

			this.cloneNode = function(deep) { return new DOMcarrierNetscape(this.element.cloneNode(deep)) };

			this.childNodes = function() { return listMaker(this.element.childNodes())};
			
			this.appendChild = function(domElement) { this.element.appendChild(domElement.element);  return domElement;}
			this.firstChild = function () { return new DOMcarrierNetscape(this.element.firstChild) };
			this.lastChild = function () { return new DOMcarrierNetscape(this.element.lastChild) };
			this.removeChild = function(domElement) { this.element.removeChild(domElement.element);  return domElement;}
			this.replaceChild = function(domElement, refElement) { this.element.replaceChild(domElement.element,refElement.element);  return domElement;}
			this.insertBefore = function(domElement, refElement) { this.element.insertBefore(domElement.element,refElement.element);  return domElement;}			
			
			this.nextSibling = function(domElement) { return new DOMcarrierNetscape(this.element.nextSibling);}
			this.previousSibling = function(domElement) { return new DOMcarrierNetscape(this.element.previousSibling);}
			
			this.createElement = function(name) { var element = this.element.ownerDocument.createElement(name); return new DOMcarrierNetscape(element) };
			this.getElementById = function (id){ return new DOMcarrierNetscape(this.element.getElementById(id)) };
			this.nodeName = function() {return this.element.nodeName };
			this.nodeType = function() {return this.element.nodeType };
			this.nodeValue = function() {return this.element.nodeValue };
			this.ownerDocument = function () {return this.element.ownerDocument}; // note not mapped !!!!
			this.parentNode = function() { return new DOMcarrierNetscape(this.element.parentNode) };

			this.prefix = function() { return this.element.prefix }; 
			this.namespaceURI = function() { return this.element.namespaceURI};
			
			this.getTextContent = function() { return this.element.textContent };
			this.setTextContent = function(value) { this.element.textContent = value};
			this.getElementsByTagName = function(tagname) { return listMaker(this.element.getElementsByTagName(tagname))};
		};
		
		function DOMcarrierIE(domElement)
		{
			function listMaker(nodeList)
			{
				var newList = new Array()
				
				for (var i=0;i<nodeList.length;i++)
				{
					newList[i]=new DOMcarrierIE(nodeList[i]);
				};
				
				return newList;
			};
			
			// about me
			this.element = domElement;
			this.type="Microsoft Internet Explorer";
			
			// mapped functions - all properties becomes methods with get and set
			this.getAttribute = function (name) { return  this.element.getAttribute(name) }; 
			this.hasAttribute = function(name) { return this.element.hasAttribute(name) }; 
			this.hasAttributes = function() { return this.element.hasAttributes() }; 
			this.setAttribute = function (name,value) { this.element.setAttribute(name,value)};  
			this.removeAttribute = function(name) { this.element.removeAttribute(name) }; 

			this.cloneNode = function(deep) { return new DOMcarrierIE(this.element.cloneNode(deep)) };

			this.childNodes = function() { return listMaker(this.element.childNodes())};
			
			this.appendChild = function(domElement) { this.element.appendChild(domElement.element);  return domElement;}
			this.firstChild = function () { return new DOMcarrierIE(this.element.firstChild) };
			this.lastChild = function () { return new DOMcarrierIE(this.element.lastChild) };
			this.removeChild = function(domElement) { this.element.removeChild(domElement.element);  return domElement;}
			this.replaceChild = function(domElement, refElement) { this.element.replaceChild(domElement.element,refElement.element);  return domElement;}
			this.insertBefore = function(domElement, refElement) { this.element.insertBefore(domElement.element,refElement.element);  return domElement;}			
			
			this.nextSibling = function(domElement) { return new DOMcarrierIE(this.element.nextSibling);}
			this.previousSibling = function(domElement) {return new DOMcarrierIE(this.element.previousSibling);}
			
			this.createElement = function(name) { var element = this.element.ownerDocument.createElement(name); return DOMcarrierNetscape(element) };
			this.getElementById = function(id){ return new DOMcarrierIE(this.element.getElementById(id)) };
			
			this.nodeName = function() {return this.element.nodeName };
			this.nodeType = function() {return this.element.nodeType };
			this.nodeValue = function() {return this.element.nodeValue };
			this.parentNode = function() { return new DOMcarrierIE(this.element.parentNode) };
			
			this.prefix = function() { return this.element.prefix};
			this.namespaceURI = function() { return this.element.namespaceURI};
			
			this.getTextContent = function() { return this.element.text };
			this.setTextContent = function(value) { this.element.text = value};
			this.getElementsByTagName = function(tagname) { return listMaker(this.element.getElementsByTagName(tagname))};
		};		
	};
	
	// if you use this to get responseXML then you need to use the form
	// ydrClientScripts.DOMcarrier(thishhtpRequest.responseXML) to hide most of the 
	// differences
	
	this.XMLHttpRequest=function ()
	{	 
	    try
	    {
			if(window.XMLHttpRequest)
			{
				//Mozilla-based browsers
				request = new XMLHttpRequest();
			} 
			else if (window.ActiveXObject)
			{
				// IE browsers
				request=new ActiveXObject("Msxml2.XMLHTTP");
				if (! request)
					request=new ActiveXObject("Microsoft.XMLHTTP");
			}
		} catch(e) {};
		
		if(request == undefined)
			throw "ydrClientScripts.XMLHttpRequest: Your browser does not support XML HTTP Requests via JavaScript objects!";
			
		return request;
	};
	
	this.fullURLpath = function(filename)
	/* generates a full path name from
		http:// ................. ' aboslute ref
		/............... ' relative to root dir of web site (htdocs)
		............  ' full relative name	
	*/	
	{
		if (filename.substring(0,6) == "http://" || filename.substring(0,7) == "https://")
			return filename
		else if (filename.charAt(0) == "/")
			return document.location.href.substring(0,document.location.href.indexOf(document.location.pathname))
				+filename;
		else
			return document.location.href.substring(0,document.location.href.indexOf(document.location.pathname))
				+document.location.pathname.substring(0,document.location.pathname.lastIndexOf("/")+1)
				+filename;
	}
	
	//		var encoder=document.createElement("conv");
	this.HTMLencode = function(s)
	{
		return s.toString().replace(/\</g,"&lt;").replace(/\>/g,"&gt;").replace("&","&amp;");
		// sadly code below not reliable in netscape
		//encoder.innerText = s;
		//return encoder.innerHTML;
	};
	

}  

///-----------------------------------------------------------------------------------------------------------

// this are scripts for processing fields created via ydrExclaimfieldDEF 
// at present only good for mask type assoc fields
// they are essentially static based upon data in the document at a given id as created by ydrTAGGET and YDREXCLAIMFIELDDEF
var ydrClientScriptsExclaim = new function()
{
	// get all nodes having a name the same as the id of the given node and the same element type
	function getAll(id)
	{
		var node=document.getElementById(id);
		return ydrClientScripts.DOMcarrier(node.parentNode).getElementsByTagName(node.nodeName);
		//return node.parentNode.getElementsByTagName(node.nodeName)
	}
	
	this.getValue = function(id, surrogateListValue)
	{
		// presently only implements assoc ydrexclaimfields
		// if present then uses the structures in the document but the value of the textual list
		var foundAll = getAll(id);
		var result = 0;
		
		if (surrogateListValue == undefined)
		{
			// classic form - data from the database
			
			for (var i=0; i<foundAll.length; i++)
			{
				if (foundAll[i].getAttribute("checked"))
					result = result | foundAll[i].getAttribute("value");
			};
		}
		else
		{
			if ((typeof surrogateListValue) != "string")
				surrogateListValue= surrogateListValue.toString();
				
			for (var i=0; i<foundAll.length; i++)
			{
				if (surrogateListValue.indexOf(
					surrogateListValue.charAt(0)
					+foundAll[i].nextSibling().nodeValue().trim()
					+surrogateListValue.charAt(0))
				>=0)
					result = result | foundAll[i].getAttribute("value");
			};
		};		
		
		return result;
	};

	this.setProperty = function(id, property, newValue)
	{
		// sets all instances of property for tags named id to the value newvalue
		// property must be a member of the implemented list below
		// if node is given then only looks for name in the given node 
		// otherwise uses legacy document.all

		try 
		{ 	
			var foundAll = getAll(id);
			property=property.toLowerCase();
		
			for (var i=0; i<foundAll.length; i++)
			{
				foundAll[i].setAttribute(property,newValue);		
			}
		} catch (e) {alert (e)};
	}

	// takes a delimited list |v1|v2|.....|vn| and return with |t1|t2|.....|tn| 
	// where t is the locale text equivalent of the value v according to the given xml data type
	// conversion is via xml in IE and by custom code for 
	var converter;
	
	/*if (ydrClientScripts.isIE)
		converter=document.createAttribute("conv");*/
	this.valueList2Text = function(newValue, dataType)
	{
		var result = newValue;
		switch (dataType)
		{
			case "date" :
			case "dateTime" :
				// note this gives the user dates in the user's language not that of the spreadsheet
				
				if (selElement.type =="Microsoft Internet Explorer")
				{
					var dates=result.split(delimEntry);

					if (converter == undefined)
					{
						// have to use home made convertor
						for (j=0;j<dates.length;j++)
						{
							if (dates[j].length)
							{
								try
								{
									dates[j]=yfXML2Date(dates[j]).toLocaleString().replace("00:00:00","").trim();								
								} catch(e) {};
							}
						}
					}					
					else
					{
						// yippee can use XML vie IE
						converter.dataType= dataType;
					
						for (j=0;j<dates.length;j++)
						{
							if (dates[j].length)
							{
								try
								{
									converter.nodeValue=dates[j];
									dates[j]=new Date(converter.nodeTypedValue).toLocaleString().replace("00:00:00","").trim();								
								} catch(e) {};
							}
						}
					};
					result=dates.join(delimEntry);
				};
										
				break;
			
			case "int" :
				// fine as is
				break;
				
			case "string" :
				// fine as is
				break;
			
			default :
				throw "ydrClientScriptsExclaim.valueList2Text: Unrecognised data type "+ dataType;
		};
		
		return result;
	}
	
		// takes a delimited list |v1|v2|.....|vn| and return with |t1|t2|.....|tn| 
	// where t is the locale text equivalent of the value v according to the given xml data type
	// conversion is via xml in IE and by custom code for 
	// if delimiter is not provided then the default delimiter is used
	// if value is not provided then the value in the document is used

	this.textList = function(id, value, delimiter)
	{
		if (delimiter == undefined)
			delimiter = delimEntry;
			
		if (value == undefined)
			value=this.getValue(id);
			
		var foundAll = getAll(id);
		var result = delimiter;
		
		{
			if ((typeof surrogateListValue) != "string")
				value=value.toString();
				
			for (var i=0; i<foundAll.length; i++)
			{
				if (foundAll[i].getAttribute("checked"))
					result = result + foundAll[i].nextSibling().nodeValue().trim() + delimiter;
			};
		};		
		
		return result;
	};
};


// a generic popup mechanism for all apps
var ydrPopup = new function ()
/* members 
	show(message, banner, size) - triggers a pop up from a client page
	cookie()  a premade exampel popup that describes cookies
	onload() the executable for the loaded popup
	
	// by default utilises ydrPopup.asp
*/
{
	this.show =  function(message, title, size, file)
	{
		// message to be issued - format is innerHTML
		// optional banner for the message - format is innerHTML
		// optional rendering size for the message
		// optional file for the pop up file - this file should be modelled on blank.htm and MUST contain
			// the following ids
			// plainDefault - a button that is to get the focus by default when the form is loaded
			// plainInner - the location where the message goes - typically a div or td
			
		
		// not using dialogArguments gets around microsofts changes that now prevent dialogArguments being used
		// easily across security zones
		
		var msg="?message="+escape(message)+"&title=" +escape(title)
		
		if (file == undefined) 
			file = 'http://yorkdevres.co.uk/ydr/ydrPopup.asp';
			
		var sizes="";
		
		if (size != undefined)
			switch (size.toLowerCase())
			{
				case "small" : sizes = ';dialogHeight:5em;dialogWidth=30em;'; break;
				case "medium" : sizes = ';dialogHeight:8em;dialogWidth=50em;'; break;
				case "large" : sizes = ';dialogHeight:15em;dialogWidth=90em;'; break;
			};
			
		try 
		{
			return showModalDialog(file+msg,'','status:No;resizable:Yes;center:Yes;unadorned:Yes;help:No;'+sizes);
		}
		catch (e) 
		{
			window.alert(banner 
				+((message.substr(0,1)=="<") 
					? "\n\nYour browser does not support the showModalDialog method.  The following message may contain control information.\n\n" 
					: "\n\n")
				+message);
		}
	}

	this.cookie =  function(title)
	{
		ydrPopup.show("<p><b>Cookie:</b> "
			+"A small file that is held on your computer that enables a web server to recognise "
			+"who you are each time you visit another page of the web site.</p><p>  For this web "
			+"site the cookie contains a session identifier that correlates to your details held on the web server</p>",title, "small");
	}

	this.onload = function()
	{
		// for use when form blank.ASP is loaded
		// which must have its own buttons one of which can have an id of defaultButton to which focus will go if it exists
		
		document.getElementById("popupDefault").focus();
	}
};