
///////////////////////////////////////////////////////////////////////////////////////
// ramPortal.asp
//
// Description:	To be called from the src attribute of a script element.  Using .asp
//					instead of .js allows us to access server side information before
//					returning the JavaScript to the client.
//

//////////////////////////////////////////////////////////////////////////////////////
//	clientPortal ()
//
//	Description:	Client side object with methods and properties specific to the
//					framework.  Some of the properties allow the Client access to some 
//					server side information.
//
//	Usage:			var PORTAL = new clientPortal ();
//
function clientPortal () {
	try {

		// Add this object to the Ramesys WebPage object pool.  This allows us to get back to an
		// object instance during an event handler.
		thePage.addToObjectPool(this);
		this.globalScript_loaded = true;
	} catch(e) {
		// Prevent the absence of global.js from causing us a problem.
		this.globalScript_loaded = false;
	}

	this.webPathStart   		= '/ramportal/';
	this.webMaster   			= '';	
	this.userID      			= '';
	this.userEmail   			= '';
	this.userFullName			= '';
	this.executeURLCalls 	= 0;
	this.executeURLDebug		= false;
	this.activeLink 			= null;
	this.currentOperation 	= "";
	this.ieVersion			= null;
	
}

//////////////////////////////////////////////////////////////////////////////////////
//	clientPortal::getIEVersion ()
//
//	Description:	Works out the current Browser version, 0 is returned if the current
//					browser isn't IE.
//
//	Returns:		Number - Browser version, 0 if not IE.
//
clientPortal.prototype.getIEVersion = function() {
	// If we have already worked out the browser version then just return our last findings.
	if (this.ieVersion) return this.ieVersion;
	
	if ((iPos = navigator.appVersion.toLowerCase().indexOf("msie")) != -1) {
		sVersion = navigator.appVersion.substr(iPos + 5);
		if ((iPos = sVersion.indexOf(";")) != -1) sVersion = sVersion.substr(0, iPos);
		
		this.ieVersion = parseFloat(sVersion);
	} else {
		this.ieVersion = 0;
	}
	
	return this.ieVersion;
}

//////////////////////////////////////////////////////////////////////////////////////
//	clientPortal Properties.
//
clientPortal.prototype.logonModeTrusted = 'trusted';
clientPortal.prototype.logonModeUserName = 'username';

//////////////////////////////////////////////////////////////////////////////////////
// clientPortal::amendUrlArg (strUrl, strArg, strValue)
//
// Description: 
//
// Returns:  
//
clientPortal.prototype.amendUrlArg = function(strUrl, strArg, strValue, blnAmend) {
 
	if (strArg.length == 0) return strUrl;
 
 	// If the passed Arg string has then question mark then remove it.
	if (strArg.substr(0, 1) == "?") strArg = strArg.substr(1);
 
 	// If we hace only been passed an arg argument without a value then its a complete
	// argument(s) string.
	switch (typeof(strValue)) {
	case "boolean":
		blnAmend = strValue;
	case "undefined":
		var astrArgs = strArg.split("&");
		break;
   
	default:
		var astrArgs = new Array(strArg + "=" + strValue);
		break;
	}
 
	// Default the amend flag to be true.
	if (typeof(blnAmend) == "undefined") blnAmend = true;
 
	if (strArg.indexOf("=") == -1)
	{
		strArg += "=";
	}

	for (var i = 0; i < astrArgs.length; i++) {
 
		strValue = astrArgs[i].substr(strArg.length);
		// If the url already contains the required argument.
		if ((intStartPos = strUrl.toLowerCase().indexOf("&" + strArg.toLowerCase())) != -1 || (intStartPos = strUrl.toLowerCase().indexOf("?" + strArg.toLowerCase())) != -1) {
			intStartPos += strArg.length + 1;

			if (blnAmend) {
				if ((intEndPos = strUrl.substr(intStartPos).indexOf("&")) != -1) {
					strUrl= strUrl.substr(0, intStartPos) + strValue + strUrl.substr(intStartPos + intEndPos);
				} else {
					strUrl= strUrl.substr(0, intStartPos) + strValue;
				}
			}
		} else {
			// Just append the argument to the end of the url.
			strUrl= strUrl += (strUrl.indexOf("?") == -1 ? "?" : "&") + strArg + strValue;
		}
	}

	return strUrl;
}

//////////////////////////////////////////////////////////////////////////////////////
//	clientPortal::Logon ([strMode], [strSiteID])
//
//	Description:	Presents a Logon dialog to the user.  This should be called whenever
//					a new session is initialised.
//
//	Parameters:	strMode	- Optional String, this.logonModeTrusted or 
//								  this.logonModeUserName determines what the user should
//								  prompted for.
//
//					strSiteID	- Optional String,  ID of the site that the user is to
//								  logon to.
//
//	Returns:		Boolean - True, User logged on succesfully.
//
clientPortal.prototype.Logon = function (strMode, strSiteID) {
	varRetValue = self.showModalDialog (this.getDialogUrl(this.webPathStart + "utils/framework/ramLogon.asp?mode=" + strMode + "&siteid=" + strSiteID), 
												"",	
												"status:no;"			+ 
												"center:yes;"			+ 
												"help:no;"				+
												"minimize:no;"		+
												"maximize:no;"		+
												"border:thick;"		+ 
												"status:no;"			+
												"scroll:no;"			+
												"dialogWidth:420px;"	+
												"dialogHeight:250px");
													
	// Return the status of the logon.
	return (typeof(varRetValue) != "undefined" && varRetValue == "validated");
}

clientPortal.prototype.getDialogUrl = function (sUrl) {
//	alert( this.webPathStart + "utils/framework/ramDialog.asp?dialogUrl=" + sUrl);

	return this.webPathStart + "utils/framework/ramDialog.asp?dialogUrl=" + sUrl;
}

//////////////////////////////////////////////////////////////////////////////////////
//	clientPortal::Logoff ()
//
//	Description:	Logs the user out of the Portal and ends there current session.
//
clientPortal.prototype.Logoff = function (callBack) {
	this.executeURL (this.webPathStart + "utils/framework/ramLogoff.asp?logoffonly=true", callBack);
}

//////////////////////////////////////////////////////////////////////////////////////
// clientPortal::ErrorWindow (varErrorNumber, strErrorDescription, 
//																	[strSource], [strOperation])
//
//	Description:	Can be called from within the catch section of a try catch clause
//					The caught error is presented to the user with options to ignore,
//					log or retry.
//
//	Parameters:	varNumber:			Variant, Error number, if called from a catch then
//									 	this should be the number property of the error
//										object. (e.number).
//
//		 			strDescription: 	General error description, if called from 
//										a try catch statement, then this would be
//										the description property of the error object.
//
//					strSource:			Optional String, Source of the error. Defaults to 
//										the current document.
//
//					strOperation:		Optional String, String describing the operation
//										being performed when the error occured.  If this
//										isn't passed in then the value from the
//										currentOperation property is used.
//
clientPortal.prototype.lastErrors = new Array();
clientPortal.prototype.errorWindow = clientPortal.prototype.ErrorWindow = function (varErrorNumber, strErrorDescription, strSource, strOperation) {
	// Check that the current error hasn't already been reported and marked for ignore.
	if (typeof(thePage) == "undefined" || ((typeof (this.lastErrors) != "undefined" && this.lastErrors.indexOf(parseInt(varErrorNumber)) == -1) || 
		  typeof (this.lastErrors) == "undefined"))
	{
		// Create a new array for storing arguments to be passed to the error window.
		var arrArguments = new Array();
		arrArguments[0] = (!strSource) ? document.location.href : strSource;
		arrArguments[1] = varErrorNumber;
		arrArguments[2] = strErrorDescription;
		arrArguments[3] = PORTAL.webMaster;
		arrArguments[4] = (strOperation) ? strOperation : PORTAL.currentOperation;

		varRetValue = self.showModalDialog (PORTAL.webPathStart + "utils/framework/ramError.asp", 
													arrArguments,	
													"status:no;"			+ 
													"center:yes;"			+ 
													"help:no;"				+
													"minimize:no;"		+
													"maximize:no;"		+
													"border:thick;"		+ 
													"status:no;"			+
													"scroll:no;"			+
													"dialogWidth:550px;"	+
													"dialogHeight:300px");

		// Process the return value.
		switch (varRetValue) {
			case "retry" :
				// Refresh the current page.
				document.location.reload();
				break;
			
			case "ignore" :
				// If this is the first error for the current page then create and error array.
				if (typeof(this.lastErrors) == "undefined") this.lastErrors = new Array();
			
				// Append the error number onto the end of the error array.
				this.lastErrors[this.lastErrors.length] = varErrorNumber;
				break;
			
			case "close" :
			default :
				break;
		}
	}
}

clientPortal.prototype.executeURLSync = function(sUrl) {
	var sDialogFeatures 	= "dialogHeight: 1px; dialogWidth: 1px; dialogTop: 1200px; dialogLeft: 1200px;" 
							+ "center: No; help: No; resizable: No; status: No;";
							  
	return window.showModalDialog(this.webPathStart + "scripts/syncExecute.asp?url=" + escape(sUrl) + "&referer=" + escape(document.location.href), null, sDialogFeatures);
}

//////////////////////////////////////////////////////////////////////////////////////
// clientPortal::executeURL (vObject, [callBack], [sName])
//
//	Description:	Executes the passed URL in a hidden frame.  The requested document
//				  	can then set a return value by setting a returnValue attribute on
//					document.body of the requested URL.  The return value is then
//					passed as a paramter to the passed callBack function (if specified).
//
//	Parameters:	vObject:			String Or FORM Element, URL to be exucuted or FORM
//										being submitted.
//
//					callBack:			Optional Function, Function reference to be called
//										when the passed URL has been loaded.
//
//					sName				Optional String, Name to be used with the execution
//										call, making multiple call with the same name will
//										result in each execution taking place one after the
//										other and not all at once.
//
clientPortal.prototype.executeURL = function(vObject, callBack, sName) {
	// Get the current browser version number.
	var nVersion = this.getIEVersion();
	var bSync = (typeof(callBack) == "boolean" && callBack);
	try {
		// If we are to run in sync with the caller and only return when the url has been executed.
		if (bSync) return this.executeURLSync(vObject);
					
		// If we are to give the execution a name and an existing execution with
		// the same name is still in executing.	
		if (sName && (objIFrame = document.all(sName))) {
			// The required frame is still busy so we will just add the execution call
			// to the queue.
			PORTAL.currentOperation = "Add another call to the Queue";
			objIFrame.queueUrl[objIFrame.queueUrl.length] = vObject;
			objIFrame.queueCallback[objIFrame.queueCallback.length] = callBack;			
		} else {
			// Create our IFrame element and set the style so that it isn't visible within the browser.
			var objIFrame = document.createElement("IFRAME");
			objIFrame.style.display = this.executeURLDebug ? "block" : "none";

			// Store the debug flag on the iframe so that the executeURLFinished method can access it,
			// Why? because the executeURLFinished method is triggered by an event it doesn't have a
			// reference to this, hence it can't check the status of executeURLDebug.
			objIFrame.executeURLDebug = this.executeURLDebug;

			// If we have been given the name to be assigned to the new IFrame.
			if (sName) {
				// Create some queues so that we can queue up any future calls for the
				// same frame.
				objIFrame.queueUrl = new Array;
				objIFrame.queueCallback = new Array;
				objIFrame.id = objIFrame.name = sName;
			} else {
				// Give the iframe a name so that we can back at it through the frames collection to get back at our IFrame.
				// We need to allow for a form having been passed in instead of a URL.
				if (typeof(vObject) == "object") {
					// If the form already has a target string then we'll use that as the name of of our IFrame.
					if (vObject.target) {
						objIFrame.id = objIFrame.name = vObject.target;
					} else {
						vObject.target = objIFrame.id = objIFrame.name = "exec_" + this.executeURLCalls;
					}
				} else {
					objIFrame.id = objIFrame.name = "exec_" + this.executeURLCalls;
				}
			}

			// If we are running in debug mode, in other words the previous IFrames weren't removed
			// then we need to rename it so that it doesn't get confused with this executeURL call.
			if (this.executeURLDebug && this.executeURLCalls && (objOldFrame = document.all(objIFrame.id))) {
				objOldFrame = objOldFrame.removeNode(true);
			}
			
			// Increment the flag that indicates how many times we have been called.
			this.executeURLCalls++;
			// How the IFrame is appended to the document differs upon the browser version/
			if (nVersion >= 5.5) {
				// Append the new IFrame element to the body of the calling document.
				document.body.appendChild (objIFrame);

				// We only need to process the onload event if we are to do something withit.
				if (typeof(callBack) != "undefined") objIFrame.attachEvent("onload", this.executeURLFinished);	

				// If we have been given a URL then set the url property other wise we have been given a
				// form element which will populate the src property with the submit.
				if (typeof(vObject) == "string") {
					// Point the IFrame at the required source.
					objIFrame.src = vObject;
				} else {
					// BUG Workaround. IE bug prevents dynamicly created frames from being used from a form being submitted.
					document.frames(objIFrame.id).name = objIFrame.id;
				}
			} else {
				// Append the new IFrame element to the body of the calling document.
				document.body.insertAdjacentHTML("beforeEnd", objIFrame.outerHTML);
				objIFrame = document.all(objIFrame.id);
				objIFrame.name = objIFrame.id;
				
				// save this away cos if we are running IE5.01 then the
				// event.srcElement is not correctly populated
				this.urlIFrame = objIFrame;				
				
				
				// If we have been given a URL then set the url property other wise we have been given a
				// form element which will populate the src property with the submit.
				if (typeof(vObject) == "string") {
					// Point the IFrame at the required source.
					objIFrame.src = vObject;
				} else {
					// BUG Workaround. IE bug prevents dynamicly created frames from being used from a form being submitted.
					document.frames(objIFrame.id).name = objIFrame.id;
				
					event.cancelBubble = true;
					event.returnValue = false;
					vObject.submit();
				}

				// We only need to process the onload event if we are to do something withit.
				if (typeof(callBack) != "undefined") {

					// Get a reference to the window of the URL being executed.
					oWindow = document.frames(objIFrame.id);

					// If the global.js script is present within the current document then we can use
					// the object pool to get a reference to this.
					if (this.globalScript_loaded) {	
						oWindow.attachEvent("onload", new Function ("return " + this.toString() + ".executeURLFinished(document.all('" + objIFrame.id + "'));"));
					} else {
						// We can call the finished function directly because we know that the function
						// does't need to reference this.
						oWindow.attachEvent("onload", new Function ("return PORTAL.executeURLFinished(document.all('" + objIFrame.id + "'));"));
					}
				
				}
			}

			// Store a reference to the callers call back function.	
			objIFrame.callBack = callBack;
		}
	} catch(e) {
		this.errorWindow (e.number, e.description);	
	}
}

//////////////////////////////////////////////////////////////////////////////////////
// clientPortal::executeURLFinished ()
//
//	Description:	This method is private, it is called by the IFrame.onload event of  
//					the executeURL IFrame.  This is responsible for calling the callBack
//					function if requested.
//
clientPortal.prototype.executeURLFinished = function (oElement) {
PORTAL.currentOperation = "process the completed executeURL";
	try {
		PORTAL.currentOperation = "Get the IFrame from the event object";
		try {
			objIFrame = event.srcElement;
		} catch (e) {
			objIFrame = this.urlIFrame;
			if (typeof(objIFrame) == "undefined" || objIFrame == null)
			{
				PORTAL.errorWindow (e.number, e.description);
				return true;
			}
		}
		
		// If were passed a callBack function reference then call it and pass in the return return value of
		// of the requested loaded document.
		if (typeof(objIFrame.callBack) != "undefined") {
			PORTAL.currentOperation = "Send result to supplied callback function.";
			// Try to access the return value from within the requisted document.  Cross frame security may cause an error
			// so be ready to trap any and just set the return value to null.
			try {
				var varValue = document.frames.item(objIFrame.name).document.body.getAttribute("returnValue");
			} catch(e) { 
				PORTAL.errorWindow (e.number, e.description);			
				var varValue = null; 
			}

			if (typeof(objIFrame.callBack) == "function") {
				// Call the callers callback functions and provide them with the return Value.
				objIFrame.callBack (varValue, objIFrame.src);	
			} else {
				// If the callback string doesn't have the function brackets.
				if (objIFrame.callBack.indexOf("(") == -1) {
					eval (objIFrame.callBack + "(varValue, objIFrame.src)");
				} else {
					eval (objIFrame.callBack);
				}
			}
		}

		PORTAL.currentOperation = "work out if we have more queued up";
		// If the current IFrame doesn't have further execution URL queued up to be executed.
		if (typeof(objIFrame.queueUrl) != "undefined" && objIFrame.queueUrl.length > 0) {
			PORTAL.currentOperation = "Process next in the queue for this IFrame";		
			objIFrame.src = String(objIFrame.queueUrl.shift());
			objIFrame.callBack = objIFrame.queueCallback.shift();
		} else {
			PORTAL.currentOperation = "Remove the IFrame as we have finished with it";
			// We have finished with the IFrame and the document within so remove it.
			//if (!objIFrame.executeURLDebug)
			objIFrame = objIFrame.removeNode(true);
			this.urlIFrame = null;
		}
	} catch(e) {
		PORTAL.errorWindow (e.number, e.description);
	}
	
	return true;
}

/////////////////////////////////////////////////////////////////////////////////////////
//	clientPortal::launchHref (strHref, [strTarget])
//
//	Description:	Dynamically creates an (A)nchor element and set the href property to
//					required value.  The target property is also set if passed in.  The link
//					is then actioned as if it were clicked.  The (A)nchor element is then
//					removed.
//
//	Parameters:	strHref 	- String, Href/Url value to be launched.
//
//					strTarget	- String, Name of the required Target frame.
//
clientPortal.prototype.launchHref = function (strHref, strTarget) {
	// Create a new (A)nchor element.
	var objA = document.createElement("A");
	
	// Set the re	quired link properties.
	objA.href = strHref;
	if (strTarget) objA.target = strTarget;
	
	// Append the link to the current document.
	document.body.appendChild (objA);
	
	// Fire of the link and then remove it from the document.
	objA.click();
	objA = objA.removeNode (true);
}

/////////////////////////////////////////////////////////////////////////////////////////
//	clientPortal::pageLinks ([blnEnable)
//
//	Description:	Sets up the document to catch the onclick of a document.  The 
//					clicked element is then checked for a 'pageid' attribute.  Any found 
//					pageid's are then looked up and Activated by the Licence manager, the 
//					Url of the PageID is then launched as a link.
//
//	Parameters:	blnEnable		- Optional Boolean, False: disable click monitering.
//									  True (Default): enable click monitering.
//
//	Usage:
//		Every element on the calling document is (when enabled) monitered for the 
//		onclick event.  Any element with a pageid attribute are then treated as a
//		hyperlink.  Additional functionality can be used by giving the element
//		any of the following attributes.
//			pageid		-	ID of the Portal frmaework page to launched.
//
//			arguments	-	Arguments to be appended to the URL relevent to the pageid.
//							Any existing PageID arguments will be overwrittin by the arguments
//							within this Attribute.
//
//			keepLink	-	True: The destination page of the PageID is only activated 
//							for the first click, any subsequent clicks just fire of the
//							PageID's URL without performing the Page Licence Activation.
//							False (Default): The destination page is activated upon every 
//							click.
//
//		Example:
//			<div pageid="demaproj1" arguments="code=1000">
//												View Project Details For Project One</div>
//
//		NOTE:
//			The library script global.js must be present.
//
clientPortal.prototype.pageLinks = function (blnEnable) {
	// We need to have thePage object (global.js)
	if (typeof (thePage) == "undefined") return;
	
	if (typeof(blnEnable) == "undefined" || blnEnable) {
		document.onclick = new Function ( "return " + this.toString() + ".pageClick();" );	
	} else {
		document.onclick = null;
	}
}

/////////////////////////////////////////////////////////////////////////////////////////
//	clientPortal::pageClick () (PRIVATE)
//
//	Description:	Function called by the onclick event of the current document.  This
//					method is then responsible for checking the source element for a pageid
//					attribute.
//
clientPortal.prototype.pageClick = function () {
	var srcElement = event.srcElement;
	
	// If the element which fired the event doesn't have a pageid attribute then go no further.
	if (!(strPageID = srcElement.getAttribute("pageid"))) return;
	// Prevent the event from being processed by the href click handler.
	event.cancelBubble = true;
	event.returnValue = false;
	
	// If the details of the current link have been stored from a previous call then use them.
	if (srcElement.getAttribute("keepLink") && srcElement.getAttribute("lastHref")) {
		this.launchHref (srcElement.getAttribute("lastHref"), srcElement.getAttribute("lastTarget"));
	} else {
		// Store a reference to the source element so that we can get to it when the executeURL
		// callback function is called.
		this.activeLink = srcElement;
		// Try to retreive the URL and possible target of the clicked PageID. 
		this.executeURL (this.webPathStart + "utils/framework/ramPageLink.asp?pageid=" + strPageID, this.toString() + ".pageActivated", "PageLink");
	}

	// Prevent the click from being processed any further.
	return false;
}

/////////////////////////////////////////////////////////////////////////////////////////
//	clientPortal::isPageLink ([objElement])
//
//	Description:	Function to be called by the users client side script to verify that
//					an element is a pagelink element.
//
//	Parameters:	objElement - 	Optional Element, Element to be change for the required
//									pageLink attributes.
//
clientPortal.prototype.isPageLink = function (objElement) {
	try { if (typeof(objElement) == "undefined") objElement = event.srcElement; } 
	catch (e) { return false; }
	
	return (objElement.getAttribute("pageid") ? true : false);
}


clientPortal.prototype.pageActivated = function(strPageDetails) {
	var astrHref = strPageDetails.split("|");

	// If the selected Link has additional or override arguments then place them onto the Url details.
	if ((strArgs = this.activeLink.getAttribute("arguments"))) astrHref[0] = this.amendUrlArg(astrHref[0], strArgs)

	// The selected link may have an override target.
	if ((strTarget = this.activeLink.getAttribute("target"))) astrHref[1] = strTarget;
	
	// If the link has the keepLink attribute set to true then store the link details within the
	// link element to prevent the Lookup from having to take place in the future.
	if (this.activeLink.getAttribute("keeplink")) {
		this.activeLink.lastHref = astrHref[0];
		this.activeLink.lastTarget = astrHref[1];
	}
	
	this.launchHref (astrHref[0], astrHref[1]);
	this.activeLink = null;
}

clientPortal.prototype.setAlternateProps = function(objTable, strAttribute, strEvenValue, strOddValue, bIncludeHidden) {
	var blnEven = false;
	
	// Ensure that we have some reasonable class names.
	if (typeof(strEvenValue) == "undefined") strEvenValue= "";
	if (typeof(strOddValue) == "undefined") strOddValue= "";
		
	// Loop through every table row.
	for (var i = 0; i < objTable.rows.length; i++) {
		oRow = objTable.rows(i);
		// Ignore header rows.
		if (oRow.cells(0).nodeName == "TH" || (!bIncludeHidden && oRow.style.display == "none")) continue;
		
		// Set the required property value appropriatly.
		oRow.setAttribute(strAttribute, (blnEven ? strEvenValue : strOddValue));
		
		blnEven = !blnEven;
	}
}

// If the current page doesn't already have a client side PORTAL object then create one.
if (typeof (PORTAL) == "undefined") {
	var PORTAL = new clientPortal ();

	// ??? crad - Do we realy want to default this.
	//PORTAL.pageLinks();
}
