/*
  CLASS LIST:

	* LIApplication
	* LIRequest
	* LIString
	* LIDebug
*/

/*############################################################
	Liquid Intelligence:
	 Application Class
 ############################################################*/
/*
 
 NOTE: PLEASE!!! PUT THE FOLLOWING CODE ON 
 THE PAGE THAT INCLUDES LIAPPLICATION!!
 
    <script language="javascript">
    function GetRootPath()
    {
		return '<%= this.ResolveUrl("~") %>';
    }
    </script>
    
    <xml id="xmlSystemConfiguration">
		<%= Pandell.Firestorm.Core.Application.Instance.GetConfiguration().BuildConfigurationParametersForClientXml()%>
	</xml>
 
*/
/*==========================
 Constructor
 ==========================*/ 
function LIApplication(n_sessionGuid)
{ 
	var p = LIApplication.prototype;

	//Browser Detect Properties
	var ua				= window.navigator.userAgent;
	var msie			= ua.indexOf ( "MSIE " );
	p.IsBrowserIE		= msie > 0;
	p.IEMajorVersion	= parseInt (ua.substring (msie+5, ua.indexOf (".", msie )));

	//Mouse Cursor to User Properties
	p.CURSOR_COL_RESIZE  = (this.IEMajorVersion==5) ? "move" : "col-resize";
	p.CURSOR_NOT_ALLOWED = (this.IEMajorVersion==5) ? "default" : "not-allowed";

	//Misc Properties
	p.MasterWindow		  = window;
	p.RootPath			  = window.GetRootPath();
	p.WindowList		  = new ActiveXObject("Scripting.Dictionary");
	p.GlobalClientContext = "DEFAULT";

	//Configuration Collections
	//System Configuration
	p.SystemConfiguration = new Object();
	if (typeof(xmlSystemConfiguration) != "undefined" && xmlSystemConfiguration != null)
	{
		var x = new ActiveXObject("Microsoft.XMLDOM");
		x.loadXML(xmlSystemConfiguration.innerHTML);

		//KEYS CONVERTED TO UPERCASE
		var nodes = x.selectNodes("ClientSystemConfiguration/Parameter");	
		for (i=0; i<nodes.length ;i++)
		{
			var key = nodes[i].selectSingleNode("Name").text;
			var value = nodes[i].selectSingleNode("Value").text;
			p.SystemConfiguration[key.toUpperCase()] = value;
		}
	}

	//Embedded Objects Properties
	p.Html			= new LIHtmlApi(this);
	p.Xml			= new LIXmlApi(this);
	p.Api			= new LIApi(this);
	p.DialogHelper	= new LIDialogHelper();
	p.Request		= new LIApplicationRequest();
	p.String		= new LIApplicationString();
	p.Debug			= new LIApplicationDebug();
	p.Search		= new LIApplicationSearch();
	p.Events		= new LIEvents();
	window.Debug	= p.Debug;

	//Milan - add current page to the application object as well (if present and not yet added)
	if ("undefined" != typeof(window.CurrentPage)) {
		if ("undefined" == typeof(p.CurrentPage)) {
			p.CurrentPage = window.CurrentPage;
		}
	}

	//Constants
	p.PLATFORM			= "DHTML";
	p.USER_ERROR		= 0x80040200; // Base "user" automation error 
	p.NULL_GUID			= "00000000-0000-0000-0000-000000000000";
	p.EVERYTHING_GUID	= "FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF";
	Error.prototype.source = "Pandell Liquid Intelligence"; // Fills in the automation "source"

	//Event attachment
	window.attachEvent("onunload", p.ApplicationClosing );
	
	//Any Callbacks?
	if(typeof(window.LIApplicationInitializedCallbacks) != "undefined")
	{   
		for (key in window.LIApplicationInitializedCallbacks) 
		{  
			window.LIApplicationInitializedCallbacks[key](this); 
		}
	}
}

/*==========================
 VALUE Checkers
 ==========================*/ 
LIApplication.prototype.HasValue = function LIApplication_HasValue(v) {
	return ((typeof(v) != "undefined") && (null != v));
}

LIApplication.prototype.HasStringValue = function LIApplication_HasStringValue(v) {
	return (typeof(v) == "string" && v.length > 0) ? true : false;
}

/*==========================
 VALUE Getters
 - If value not valid, use supplied default value
 ==========================*/ 
LIApplication.prototype.GetValue = function(v, defaultValue) {
	return (this.HasValue(v))? v : defaultValue;
}

LIApplication.prototype.GetStringValue = function(v, defaultValue) {
	return (this.HasStringValue(v))? v : defaultValue;
}

//KEYS ALL UPERCASE, RETURNED VALUES ALL LOWER!
LIApplication.prototype.SystemConfigurationValue = function(key, defaultValue) {
	return this.GetStringValue(this.SystemConfiguration[key], defaultValue).toLowerCase();
}

/*==========================
 INFORMATION Message
 - Presents user a dialog with given message.
 
 TODO: Make this a nicer popup window...perhaps call off to vbscript.
 ==========================*/ 
LIApplication.prototype.ShowInformation = function(message) { alert(message); }

/*==========================
 RESOLVE URL
 Resolve leading ~ character in a URL to the absolute path. 
 ==========================*/ 
LIApplication.prototype.ResolveUrl = function LIApplication_ResolveUrl(url)
{
	if( url.charAt( 0 ) == "~" )
	{
		// get RootPath and trim trailing '/'
		var rootPath = this.RootPath;
		if( rootPath.charAt( rootPath.length-1 ) == "/" ){
			rootPath = rootPath.substr( 0, rootPath.length-1 );
		}

		// get remainder of URL and trim leading '/'
		var urlRemainder = (url.length > 1)? url.substr( 1 ) : "";
		if( urlRemainder.charAt( 0 ) == "/" ){
			urlRemainder = (urlRemainder.length > 1)? urlRemainder.substr( 1 ) : "";
		}
		return rootPath + "/" + urlRemainder;
	}
	return url;
}

/*==========================
 Object To Register
 
 Will register given object to opened windows
 as an expando property of the window object

 ==========================*/ 
LIApplication.prototype.ObjectToRegister = function LIApplication_ObjectToRegister(name, ob)
{
	if( !this.HasValue(this.objectsToRegister) )
	{
		this.objectsToRegister = new Object();
	}
	this.objectsToRegister[name] = ob;	
}

/*==========================
 Register Window
 
 Store a reference to given window and hook into it's
 onload event. Also append the global Application object 
 it's window as an expando property.

 ==========================*/ 
LIApplication.prototype.RegisterWindow = function LIApplication_RegisterWindow(win)
{
	if (win != null && win != this.MasterWindow)
	{
		Application.Debug.WriteMessage("RegisterWindow()","Registering: <font color='gray'>" + win.location.href + "</font>");
		if (this.WindowList.Exists(win) == false){ this.WindowList.Add(win, win) }; 
		if(win.Application == null) { win.Application = this; }
		if( Application.HasValue(this.objectsToRegister) )
		{
			for (key in this.objectsToRegister) 
			{  
				win[key] = this.objectsToRegister[key]; 
			}
		}
		win.attachEvent("onunload", LIApplication.prototype.WindowClosing );
	}
}

/*==========================
 UNREGISTER Window
 Remove a given window from our associative array
 of window references.
 ==========================*/ 
LIApplication.prototype.UnregisterWindow = function LIApplication_UnregisterWindow(win)
{
	if ((win != null) && this.WindowList.Exists(win))
	{
		this.WindowList.Remove(win)
	};
}

/*==========================
 WINDOW Closing
 One of the windows we have a reference to is 
 closing. Let's remove it's reference from our
 associative array!
 ==========================*/ 
LIApplication.prototype.WindowClosing = function LIApplication_WindowClosing()
{
	var keys = (new VBArray( LIApplication.prototype.WindowList.Keys() )).toArray();
	for (var i = keys.length; i-- > 0; )
	{
		if ("object" == typeof(keys[i].event) && null != keys[i].event)
		{
			if ("unload" == keys[i].event.type)
			{
				Application.Debug.WriteMessage(
					"WindowClosing()",
					"Unregistering window : <font color='gray'>" + keys[i].location.href + "</font>"
				);
				LIApplication.prototype.UnregisterWindow(keys[i]);
			};
		}
	}
}

/*==========================
 APPLICATION Closing
 The master window is closing. We need to shut down
 any child windows we have a reference to.
 ==========================*/ 
LIApplication.prototype.ApplicationClosing = function LIApplication_ApplicationClosing()
{
	Application.Debug.WriteMessage("ApplicationClosing()","The application is exiting.");
	var keys = (new VBArray( LIApplication.prototype.WindowList.Keys() )).toArray();
	for (i in keys)
	{
		if(keys[i] != null) {	try	{ keys[i].close(); } catch(e){} }
	}
}

/*================================
 ShowModalDialog
 ================================*/
LIApplication.prototype.ShowModalDialog = function LIApplication_ShowModalDialog(wnd, url, args, parameters)
{
	parameters = this.ResizeWindowParameters( parameters );
	return wnd.showModalDialog( url, args, parameters );
}

/*================================
 ShowModelessDialog
 ================================*/
LIApplication.prototype.ShowModelessDialog = function LIApplication_ShowModelessDialog(wnd, url, args, parameters)
{
	parameters = this.ResizeWindowParameters( parameters );
	return wnd.showModelessDialog( url, args, parameters );
}

/*================================
 GetBaseModalStyle
 ================================*/
LIApplication.prototype.GetBaseModalStyle = function LIApplication_GetBaseModalStyle(width, height)
{
	var style = "dialogHeight:" + height + "px" +
		";dialogWidth:" + width + "px" +
		";resizable:no" +
		";status:no" +
		";scroll:no" +
		";unadorned:yes" + 
		";help:no";

	return style;
}

/*================================
 ResizeWindowParameters
 ================================*/
LIApplication.prototype.ResizeWindowParameters = function LIApplication_ResizeWindowParameters(parameters)
{
	// Extract the parameters into a key/value map for easier parsing
	var keyValuePairs = parameters.split( ";" );
	var map = new Object();
	for( var i in keyValuePairs )
	{
		var token = keyValuePairs[ i ].split( ":" );
		if( token.length == 2 )
			map[ this.String.Trim( token[ 0 ] ) ] = token[ 1 ];
	}
	// Ensure the dialog height fits on the screen
	if( map.hasOwnProperty( "dialogHeight" ) && map[ "dialogHeight" ].toString().toLowerCase().indexOf("px") > -1 )
	{
		var screenHeight = parseInt( screen.availHeight, 10 );
		var windowHeight = parseInt( map[ "dialogHeight" ].toString(), 10 );
		if( map.hasOwnProperty( "status" ) )
		{
			switch( map[ "status" ].toString().toLowerCase() )
			{
				case "no":
				case "0":
				case "off":
					if(	window.location.hostname != "localhost" &&
						this.IsBrowserIE &&
						window.navigator.userAgent.indexOf("Windows NT 5.1") > -1 &&
						window.navigator.userAgent.indexOf("SV1") > -1 )
					{
						// If the user is running IE under XP SP2 on anything other than localhost
						// then add an extra 20 pixels to the window height to accomodate the
						// status bar that cannot be turned off on modal windows
						windowHeight += 20;
					}
					break;
			}
		}
		if( windowHeight > screenHeight )
			windowHeight = screenHeight;
		map[ "dialogHeight" ] = windowHeight + "px";
	}
	// Ensure the dialog width fits on the screen
	if( map.hasOwnProperty( "dialogWidth" ) && map[ "dialogWidth" ].toString().toLowerCase().indexOf("px") > -1 )
	{
		var screenWidth = parseInt( screen.availWidth, 10 );
		var windowWidth = parseInt( map[ "dialogWidth" ].toString(), 10 );
		if( windowWidth > screenWidth )
			windowWidth = screenWidth;
		map[ "dialogWidth" ] = windowWidth + "px";
	}
	// Build the new parameter string
	var newParameters = "";
	for( var key in map )
		newParameters = newParameters + key + ":" + map[ key ] + ";";
	// Return the new parameter string
	return newParameters;
}

/*############################################################
	Liquid Intelligence:
	 Events
 ############################################################*/

function LIEvents()
{
	LIEvents.prototype.EventHandlers = new Object();
}

LIEvents.prototype.AddHandler = function LIEvents_AddHandler(eventName, handler)
{
	var nameOfEvent = eventName.toLowerCase();
	if( ! this.EventHandlers.hasOwnProperty( nameOfEvent ) )
		this.EventHandlers[ nameOfEvent ] = new Array();
	this.EventHandlers[ nameOfEvent ].push( handler );
}

LIEvents.prototype.FireEvent = function LIEvents_FireEvent(eventName, eventObject)
{
	var nameOfEvent = eventName.toLowerCase();
	if( this.EventHandlers.hasOwnProperty( nameOfEvent ) )
	{
		for( var i in this.EventHandlers[ nameOfEvent ] )
			this.EventHandlers[ nameOfEvent ][ i ]( eventObject );
	}
}

/*############################################################
	Liquid Intelligence:
	 Search
 ############################################################*/
function LIApplicationSearch()
{

		//--------------------------------------
		//Is term noise?
		//--------------------------------------
		this.IsNoise = function(term)
		{
			//Noise word?
			for(var i=0;i<Application.Search.EnglishNoiseArray.length;i++) {
				if(term.toLowerCase() == Application.Search.EnglishNoiseArray[i]) { return true; }
			}	
			return false;
		}

		//Noise array
		this.EnglishNoiseArray = new Array("about","after","all","also","an","and","another","any","are","as","at","be","because","been","before","being","between","both","but","by","came","can","come","could","did","do","each","for","from","get","got","has","had","he","have","her","here","him","himself","his","how","if","in","into","is","it","like","make","many","me","might","more","most","much","must","my","never","now","of","on","only","or","other","our","out","over","said","same","see","should","since","some","still","such","take","than","that","the","their","them","then","there","these","they","this","those","through","to","too","under","up","very","was","way","we","well","were","what","where","which","while","who","with","would","you","your","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","$","1","2","3","4","5","6","7","8","9","0");

}

/*############################################################
	Liquid Intelligence:
	 Request
 ############################################################*/ 
function LIApplicationRequest()
{
		//--------------------------------------
		//Emulate the server QueryString function
		//--------------------------------------
		this.QueryString = function(win, key)
		{
			Application.Debug.WriteMessage("QueryString()","Requesting variable: '" + key + "'");

			var regex = new RegExp(key + "=([^&]+)&?", "i");
			var matches = regex.exec(win.location.search);
			return (matches != null ? unescape(matches[1]) : "");
		}
}

/*############################################################
	Liquid Intelligence:
	 LIDialogHelper
  ############################################################*/
function LIDialogHelper() 
{
		//--------------------------------------
		//Create an object to pass to Modal Dialog
		//--------------------------------------
		this.DialogArgument = function(win, args)
		{
			var ret = new Object();
			ret.Window = win; 
			ret.Argument = args;

			return ret;
		}
}

/*############################################################
	Liquid Intelligence:
	 String Helpers
  ############################################################*/
function LIApplicationString() 
{
	//TRIM FUNCTIONS
	this.TrimRight = function(v) { return v.replace( /\s+$/g, "" ); }
	this.TrimLeft  = function(v) { return v.replace( /^\s+/g, "" ); }
	this.Trim	   = function(v) { return this.TrimLeft(this.TrimRight(v)); }

	//BASIC VALIDATION
	this.IsValidEmail = function(v)
	{
		var re = /^\w[-\.\w]+@\w[-\.\w]+(\.\w+)+$/;
		return re.test(v);
	}
}

/*############################################################
	Liquid Intelligence:
	 Debug
  ############################################################*/
function LIApplicationDebug()
{
	this.DebugWindow = null;
	this.ACTIVE = false;
	this.DebugLevel = "BASIC";

		//--------------------------------------
		//Initialize()
		//--------------------------------------
		this.Initialize = function() 
		{
 			this.ACTIVE = ( Application.HasStringValue(Application.Request.QueryString(window, "DEBUG")) ) ;
 			this.DebugLevel = Application.GetStringValue(Application.Request.QueryString(window, "DEBUG_LEVEL"),"BASIC");
 
 			if(this.ACTIVE){ this.ShowDebugWindow(); }
		}

		//--------------------------------------
		//Should we output?
		//--------------------------------------
		this.ShouldOutput = function() { return ( this.ACTIVE  && 
					(Application.HasValue(this.DebugWindow) && 
					 !this.DebugWindow.closed) ); 
		}

		//--------------------------------------
		//Create a Debug window and display it.
		//--------------------------------------
 		this.ShowDebugWindow = function() 
 		{
 			//Acqire Debug window
			this.DebugWindow = window.open("about:blank", null, 
				"status=yes,toolbar=no,menubar=no,location=no,resizable=yes,scrollbars=yes");
			while(!this.DebugWindow.document){};

			//Init window
			this.DebugWindow.document.title = "Debugger Output Window";
			this.Body  = this.DebugWindow.document.body;
			this.Style = this.Body.style;
			this.Style.fontFamily="Arial";
			this.Style.fontSize="10pt";
			this.WriteHtml("Debugger Online: " + Application.Debug.DebugLevel + " mode<br>");
		}
		
		//--------------------------------------
		//* WriteHtml:
		//* WriteMessage:
		//* WriteTextMessage:
		//--------------------------------------
		this.WriteHtml = function(html)	{ 
			if (this.ShouldOutput()){ this.Body.innerHTML += html + "<br>"; } 
		}

		this.WriteMessage = function(functionName, html) {
			this.WriteHtml("<font color='#8080C0'><b>" + functionName + ": </b></font>" + html);
		}
		
		this.WriteTextMessage = function(functionName, text)
		{
			var el = document.createElement("div");
			el.innerText = text;
			this.WriteHtml(el.outerHTML);
		}
}


/*############################################################
  LOCAL HELPERS
  ############################################################*/
//--------------------------
//Return true if the specified value exists
//(i.e. is defined and is not null). Once a value
//is valid, it can be used for access to methods
//and properties
function isValueValid(value)
{
	return ((undefined != value) && (null != value));
}
