//
function TLookingGlass()
{
	this.aBeanCounters = Array();
	
	this.fvUpdateBeanCounter = function(p_sApp, p_nBeans)
	{
		if(p_nBeans > 0)
		{
			$("#" + p_sApp + "-beanCounter").removeClass("appBeanCounter_Empty");
			$("#" + p_sApp + "-beanCounter").addClass("appBeanCounter");			
			$("#" + p_sApp + "-beanCounter").html(p_nBeans);
		}
		else
		{
			$("#" + p_sApp + "-beanCounter").removeClass("appBeanCounter");			
			$("#" + p_sApp + "-beanCounter").addClass("appBeanCounter_Empty");			
			$("#" + p_sApp + "-beanCounter").html("");
		}
	}
}

LookingGlass = new TLookingGlass();
	
function TFormManipulator(p_sFormName)
{
	this.sName = p_sFormName;
	this.aChangeHandler = Array();
	
	this.fvAddChangeHandler = function(p_sElement, p_sValue, p_sAction, p_sElseAction)
	{
		if(this.aChangeHandler[p_sElement] == null)
			this.aChangeHandler[p_sElement] = new TFormObject(p_sValue, p_sAction, p_sElseAction);
		else
			this.aChangeHandler[p_sElement].fvAddHandler(p_sValue, p_sAction);
	}
	
	this.fvProcess = function(p_sElement)
	{
		this.aChangeHandler[p_sElement].fvMatchValue( document.forms[this.sName].elements[p_sElement].value );
	}
	
}

function TFormObject(p_sValue, p_sAction, p_sElseAction)
{
	this.nItems = 0;
	this.aIndex = Array();
	this.sElseAction = p_sElseAction;
	this.aIndex[this.nItems] = Array();	
	this.aIndex[this.nItems][0] = p_sValue;
	this.aIndex[this.nItems][1] = p_sAction;	

	
	this.fvAddHandler = function(p_sValue2, p_sAction2)
	{
		bOkToAdd = true;
		
		//Make sure this value doesnt exist already
		for(nX=0;nX<this.aIndex.length;nX++)
		{
			if(this.aIndex[nX][0] == p_sValue2)
				bOkToAdd = false;
		}
		
		if(bOkToAdd)
		{
			this.nItems++;
			this.aIndex[this.nItems] = Array();	
			this.aIndex[this.nItems][0] = p_sValue2;
			this.aIndex[this.nItems][1] = p_sAction2;		
		}
	}
	
	this.fvMatchValue = function(p_sValue)
	{
		bProcessed = false;
		
		for(nX=0;nX<this.aIndex.length;nX++)
		{
			
			if(this.aIndex[nX][0] == p_sValue)
			{
				eval(this.aIndex[nX][1]);
				bProcessed = true;
			}
		}
		
		if(!bProcessed)
		{
			eval(this.sElseAction);			
		}
	}
}


function TNavigation()
{
	this.sCurrentApp  = "";
	this.sCurrentAppPage = "";
	this.sCurrentRootApp = "";	
	this.sCurrentRootPage = "";
	this.aCurrentPages = Array();
	
	//Load/unload request queue
	this.tRequestQueue = Array();
	this.nReqs = 0
	this.nReqsToGo = 0;
	
	//Queue processing
	this.bInProcess = false;
	
	//Timed processing
	this.nTimer = 1000;
	this.nTID = setInterval("Navigation.fvProcessQueue();", this.nTimer);
	
	
	//Focus controller
	this.bEventOnFocus = false;
	this.sTargetFocus = "";
	this.sCodeOnFocus = "";
	
	//Variable controller
	this.nVarFlags = 0;
	this.aWaitForVar = Array();
	this.bVarBlock = false;
		
	//Popup confirmation widget
	this.fbConfirmLink = function(p_sText, p_sActionLink)
	{
		sBody = "<div class=\"confirmPopupControls\"><form><input type=\"button\" value=\"Yes\" onclick=\"Navigation.fvRawRequest('" + p_sActionLink + "', divFocus, false);fvHideShadow('confirmPopup');$('#confirmPopup').remove();\"> <input type=\"button\" value=\"No\" onclick=\"fvHideShadow('confirmPopup');$('#confirmPopup').remove();\"></form></div>";
		
		$(document.body).append("<div id=\"confirmPopup\" class=\"confirmPopup\"><div class=\"confirmPopupTitle\">Please confirm</div><div class=\"confirmPopupBody\">" + p_sText + "<br/>" + sBody + "</div></div>");
		fvCenterDiv("confirmPopup");
		fvShowShadow("confirmPopup");
	}
	
	this.fvRedirect = function(p_sURL)
	{
		window.location = p_sURL;
	}
	
	this.fvRawRequest = function(p_sURL, p_sTarget, p_bSilent, p_bSilentLoadingIndicator)
	{
		if(p_sTarget == null)
			p_sTarget = divBody;
		
		if(p_bSilent == null)
			p_bSilent = false;
			
		if(p_bSilentLoadingIndicator == null)
			p_bSilentLoadingIndicator = false;
		
		this.nReqs++;
		this.tRequestQueue[this.nReqs] = new TRequest("", p_sURL, p_sTarget, "raw", p_bSilent, p_bSilentLoadingIndicator);
	}		
	
	this.fvRequest = function(p_sType, p_sApp, p_sPage, p_sTarget, p_bSilent, p_bSilentLoadingIndicator)
	{
		if(p_sPage != "#")
		{
			if(p_sTarget == null)
				p_sTarget = divBody;
			
			if(p_bSilent == null)
				p_bSilent = false;
	
			if(p_bSilentLoadingIndicator == null)
				p_bSilentLoadingIndicator = false;			
			
			this.nReqs++;
			this.tRequestQueue[this.nReqs] = new TRequest(p_sApp, p_sPage, p_sTarget, p_sType, p_bSilent, p_bSilentLoadingIndicator);
		}
	}	
	
	this.fvRequestRoot = function(p_sRootApp, p_sPage, p_sTarget, p_bSilent, p_bSilentLoadingIndicator)
	{
		if(p_sTarget == null)
			p_sTarget = divBody;
		
		if(p_bSilent == null)
			p_bSilent = false;
			
		if(p_bSilentLoadingIndicator == null)
			p_bSilentLoadingIndicator = false;			
			
		if(p_sPage == null)
			p_sPage = "index.php";
		
		this.nReqs++;
		this.tRequestQueue[this.nReqs] = new TRequest(p_sRootApp, p_sPage, p_sTarget, "root", p_bSilent, p_bSilentLoadingIndicator);
	}
	
	this.fvRequestApp = function(p_sApp, p_sPage, p_sTarget, p_bSilent, p_bSilentLoadingIndicator)
	{			
		if(p_sTarget == null)
			p_sTarget = divBody;
		
		if(p_bSilent == null)
			p_bSilent = false;
			
		if(p_bSilentLoadingIndicator == null)
			p_bSilentLoadingIndicator = false;			
			
		if(p_sPage == null)
			p_sPage = "";			
					
		this.nReqs++;
		this.tRequestQueue[this.nReqs] = new TRequest(p_sApp, p_sPage, p_sTarget, "app", p_bSilent, p_bSilentLoadingIndicator);	
			
	}
	
	this.fvRequestAppMenu = function(p_sApp, p_sPage)
	{
		if(p_sPage == null)
			p_sPage = "menu.php";
			
		this.nReqs++;
		this.tRequestQueue[this.nReqs] = new TRequest(p_sApp, p_sPage, divMenu, "app", true, false);		
	}
	
	this.fvRequestRootMenu = function(p_sRootApp, p_sPage)
	{
		if(p_sPage == null)
			p_sPage = "menu.php";
					
		this.nReqs++;
		this.tRequestQueue[this.nReqs] = new TRequest(p_sRootApp, p_sPage, divMenu, "root", true, false);		
	}	
	
	//Refreshes the specified div
	this.fvRefresh = function(p_sTarget, p_bSilent, p_bSilentLoadingIndicator)
	{
		if(p_bSilent == null)
			p_bSilent = false
			
		if(p_bSilent == true)
			if(p_bSilentLoadingIndicator == null)
				p_bSilentLoadingIndicator = false;
		else if(p_bSilent == null)
			p_bSilentLoadingIndicator = false;
			
		this.fvRawRequest(this.aCurrentPages[p_sTarget], p_sTarget, p_bSilent, p_bSilentLoadingIndicator); 
	}
	
	//Waits for the focus to change and runs a function
	this.fvWaitForFocus = function(p_sTarget, p_sCodeOnFocus)
	{
		this.bEventOnFocus = true;
		this.sCodeOnFocus = p_sCodeOnFocus;
		this.sTargetFocus = p_sTarget;
	}
	
	//Waits for a variable to become a certain value and then executes code
	this.fvWaitForVariable = function(p_sVar, p_sValue, p_sCode)
	{
		this.nVarFlags ++;
		this.aWaitForVar[p_sVar] = Array();
		this.aWaitForVar[p_sVar][0] = p_sVar;
		this.aWaitForVar[p_sVar][1] = p_sValue;
		this.aWaitForVar[p_sVar][2] = p_sCode;
	}
	
	this.fvProcessQueue = function()
	{	
		if(this.bInProcess == false)
		{				
			if(this.nReqs != 0)
			{
				this.bInProcess = true;
				
				for(nX=1;nX<=this.nReqs;nX++)
				{	
					if(this.tRequestQueue[nX].sType == "root")
					{
						
						if(this.tRequestQueue[nX].sPage.indexOf("?") == -1)
							this.tRequestQueue[nX].sPage += "?";
							
						if(this.tRequestQueue[nX].sApp != "" && this.tRequestQueue[nX].sApp != ".")
							this.tRequestQueue[nX].sApp += "/";
						else
							this.tRequestQueue[nX].sApp = "";
							
						//Process root request
						if( this.tRequestQueue[nX].bSilent == false)
						{
							//Retain the currently loaded app / page
							this.sCurrentRootApp = this.tRequestQueue[nX].sApp;							
							this.sCurrentRootPage = this.tRequestQueue[nX].sPage;
							
							
							OpenURL("/" + this.tRequestQueue[nX].sApp + this.tRequestQueue[nX].sPage, this.tRequestQueue[nX].tTarget);
						}
						else
							fvPush("/" + this.tRequestQueue[nX].sApp + this.tRequestQueue[nX].sPage, this.tRequestQueue[nX].tTarget, this.tRequestQueue[nX].bSilentLoadingIndicator);					
					}
					else if(this.tRequestQueue[nX].sType == "app")
					{						
						if( this.tRequestQueue[nX].bSilent == false)	
						{	
							//Retain the currently loaded app / page						
							this.fvSwitchApp(this.tRequestQueue[nX].sApp);
							this.sCurrentAppPage = this.tRequestQueue[nX].sPage;
							
							OpenURL(sAppBasePath + "/?load=" + this.tRequestQueue[nX].sApp + "&page=" + this.tRequestQueue[nX].sPage, this.tRequestQueue[nX].tTarget);
						}
						else
							fvPush(sAppBasePath + "/?load=" + this.tRequestQueue[nX].sApp + "&page=" + this.tRequestQueue[nX].sPage, this.tRequestQueue[nX].tTarget, this.tRequestQueue[nX].bSilentLoadingIndicator);
					}
					else if(this.tRequestQueue[nX].sType == "raw")
					{						
						if(this.tRequestQueue[nX].sPage.indexOf("?") == -1)
							this.tRequestQueue[nX].sPage += "?";
												
						if( this.tRequestQueue[nX].bSilent == false)	
						{	
							OpenURL(this.tRequestQueue[nX].sPage, this.tRequestQueue[nX].tTarget);
						}
						else
							fvPush(this.tRequestQueue[nX].sPage, this.tRequestQueue[nX].tTarget, this.tRequestQueue[nX].bSilentLoadingIndicator);
					}					
				}
				
				this.bInProcess = false;
				this.nReqs = 0;
			}
		}

		//Check the focus timer
		if(this.bEventOnFocus == true)
		{
			if(divFocus == this.sTargetFocus)
			{
				//Focus achieved
				this.bEventOnFocus = false;
				this.sTargetFocus = "";
				
				eval(this.sCodeOnFocus);
				
				this.sCodeOnFocus = "";
			}
		}
		
	
		for(var nX in this.aWaitForVar)
		{		
			if(this.bVarBlock == false)
			{
					
				if(this.aWaitForVar[nX] != null)
				{
					try
					{
						if(eval(this.aWaitForVar[nX][0]) == this.aWaitForVar[nX][1])
						{
							//Block this from getting executed again
							this.bVarBlock = true;
				
							eval(this.aWaitForVar[nX][2]);
							this.aWaitForVar[nX] = null;
							this.nVarFlags --;

							this.bVarBlock = false;
						}
					} catch (e) {}
				}
				
				
			}//end if
		}//end for
	
			
	}
	
	this.fvSwitchApp = function(p_sApp)
	{
		if(p_sApp.toLowerCase() != this.sCurrentApp.toLowerCase())
		{
			try
			{
				//Clear the menu left by the previous app
				oResponseDiv = this.sCurrentApp + "-lg-submenu";
				oResponseDiv2 = this.sCurrentApp + "-lg-submenu-x";
		
				document.getElementById(oResponseDiv).innerHTML = "";
				document.getElementById(oResponseDiv).style.borderBottom = "none";
				document.getElementById(oResponseDiv).style.marginBottom = "0px";		
			} catch (e) {}
		}
		else
		{
			
		}
			
		//Revert previously launched app
		if(this.sCurrentApp != "" && (p_sApp != this.sCurrentApp))
		{
			try
			{
				document.getElementById(this.sCurrentApp + "-launcher").style.backgroundColor = "#ffffff";
				document.getElementById(this.sCurrentApp + "-launcher").style.borderTop = "1px solid #ffffff";
				document.getElementById(this.sCurrentApp + "-launcher").style.borderBottom = "1px solid #ffffff";		
			} catch (e) {}
		}
		
		this.sCurrentApp = p_sApp;
		
		//Change styling
		if(p_sApp != "")
		{
			try
			{		
				document.getElementById(p_sApp + "-launcher").style.backgroundColor = "#efefef"; 	
				document.getElementById(p_sApp + "-launcher").style.borderTop = "1px solid #cccccc";
				document.getElementById(p_sApp + "-launcher").style.borderBottom = "1px solid #cccccc";		
			} catch (e) {}
			
		}
		
	}
	

	//Refreshes LG
	this.fvRefreshLG = function()
	{
		this.fvRawRequest("/inc/applications.php", "installed-apps", true, false);
	}	
	
	
	this.fvRevertBeansCSS = function()
	{
		if(this.sBeans!= "")
		{
			$("#" + this.sCurrentApp + "-beanCounter").removeClass("appBeanCounter_Empty");
			$("#" + this.sCurrentApp + "-beanCounter").addClass("appBeanCounter");
		}
	
		try
		{	
			document.getElementById(this.sCurrentApp + '-beanCounter').innerHTML = this.sBeans;	
		} catch (e) {}
	}
			
	//Used for popping a submenu under the looking glass app loader
	this.fvOpenLGSubmenu = function(p_sApp, sPage, p_bRoot)
	{
		this.fvSwitchApp(p_sApp);
		
		if(p_bRoot == null)
			p_bRoot = false;
			
		oResponseDiv = this.sCurrentApp + "-lg-submenu-x";	
		oResponseDiv2 = this.sCurrentApp + "-lg-submenu";
		
		try
		{
			this.sBeans = document.getElementById(this.sCurrentApp + "-beanCounter").innerHTML; //Save beans
		}
		catch (e)
		{
			this.sBeans = null;
		}
		
		if(this.sBeans == null)
			this.sBeans = "";

		$("#" + this.sCurrentApp + "-beanCounter").removeClass("appBeanCounter");
		$("#" + this.sCurrentApp + "-beanCounter").addClass("appBeanCounter_Empty");	
				
		try
		{		
			document.getElementById(this.sCurrentApp + "-beanCounter").innerHTML = '<img src="/images/loading_smallbars.gif" style="vertical-align: middle">';
		} catch (e) {}
		
		var xmlHttp = getXMLHttp();
		
		xmlHttp.onreadystatechange = function()
		{
			if(xmlHttp.readyState == 4)
			{
				HandleResponseSilent(xmlHttp.responseText, oResponseDiv);		  
				document.getElementById(oResponseDiv2).innerHTML = document.getElementById(oResponseDiv).innerHTML;
				
				setTimeout("Navigation.fvRevertBeansCSS();", 2000);
			}
		}
	
		try
		{
			//Add styling
			document.getElementById(oResponseDiv2).style.borderBottom = "1px dotted #cccccc";
			document.getElementById(oResponseDiv2).style.marginBottom = "5px";	
			document.getElementById(oResponseDiv2).style.paddingLeft = "40px";
		} catch (e) {}
		
		if(p_bRoot == false)
		{
			xmlHttp.open("GET", sAppBasePath + "/?load=" + this.sCurrentApp + "&page=" + sPage + "&ms=" + new Date().getTime(), true); 
		}
		else
		{
			xmlHttp.open("GET", "/" + this.sCurrentApp + "/" + sPage + "?ms=" + new Date().getTime(), true); 
		}
		
		xmlHttp.send(null);
	}
	
	this.fvToggleLGSubmenu = function(p_sApp, p_sHost, p_bRoot)
	{
		if(p_bRoot == null)
			p_bRoot = false;
					
		 oResponseDiv = p_sApp + "-lg-submenu";
		 oResponseDiv2 = p_sApp + "-lg-submenu-x";
		 
		 if( document.getElementById(oResponseDiv).innerHTML != "")
		 {
			 //Hide menu
			 document.getElementById(oResponseDiv).innerHTML = "";
			 document.getElementById(oResponseDiv).style.borderBottom = "none";
			 document.getElementById(oResponseDiv).style.marginBottom = "0px";
		 }
		 else
		 {
			if(document.getElementById(oResponseDiv2).innerHTML != "")
			{
				//Show menu
				document.getElementById(oResponseDiv).innerHTML = document.getElementById(oResponseDiv2).innerHTML; 
				document.getElementById(oResponseDiv).style.borderBottom = "1px dotted #cccccc";
				document.getElementById(oResponseDiv).style.marginBottom = "5px";
				document.getElementById(oResponseDiv).style.paddingLeft = "40px";
			}
			else
			{
				//App is not loaded, load the app first
				this.fvSwitchApp(p_sApp);
				
				if(p_sHost != null)
					sAppend = "&host=" + p_sHost;
				else
					sAppend = "";
					
				if(p_bRoot == false)
					this.fvRequestApp(p_sApp, "main.php", divBody);
				else
					this.fvRequestRoot(p_sApp, "index.php", divBody)
			}
		 }
		 
	}

		
	
}

function TRequest(p_sApp, p_sPage, p_tTarget, p_sType, p_bSilent, p_bSilentLoadingIndicator)
{
	this.sApp = p_sApp;
	this.sPage = p_sPage;
	this.tTarget = p_tTarget;
	this.sType = p_sType;
	this.bSilent = p_bSilent;
	this.bSilentLoadingIndicator = p_bSilentLoadingIndicator;
}

Navigation = new TNavigation();







//--------------------------- SCRIPT/CSS LOADING FUNCTIONS ------------------------------//
//Adds a css into the document, very useful for calling from VM
function fvLoadCSS(p_sCSS)
{
	var headID = document.getElementsByTagName("head")[0];  
	var newcss = p_sCSS + '?' + "ms=" + new Date().getTime();
	
	if(goLastCSS != null)
	{       
		//Replace last css
		headID.removeChild(goLastCSS)
	}
	
	var cssNode = document.createElement('link');
	cssNode.type = 'text/css';
	cssNode.rel = 'stylesheet';
	cssNode.href = newcss;
	cssNode.media = 'screen';
	headID.appendChild(cssNode);
		
	goLastCSS = cssNode;
}

//Loads JS into the document
function fvLoadJS(p_sJS)
{
	var headID = document.getElementsByTagName("head")[0];
	var newscript =  p_sJS + '?' + "ms=" + new Date().getTime();
		
	if(goLastScript != null)
	{
		try
		{
			//Run the cleanup routine on the last script
			fvCleanupAppJS();
		}
		catch (e) {}
		
		headID.removeChild(goLastScript)
	}
	
	var newScript = document.createElement('script')
	newScript.type = 'text/javascript';
	newScript.src = newscript
	headID.appendChild(newScript);	
	goLastScript = newScript;
}

//JS connector for the comet server
function fvConnectJS()
{
	var headID = document.getElementsByTagName("head")[0];
	var newscriptC =  "http://bc.bizsp.in:82/check_messages/loader=" + fvGetCookie(G_LOADER) + "&type=" + G_TYPE + "&origin=" + document.domain + "&?" + "ms=" + new Date().getTime();
		
	if(goLastScriptC != null)
	{
		headID.removeChild(goLastScriptC)
	}
	
	var newScriptC = document.createElement('script')
	newScriptC.type = 'text/javascript';
	newScriptC.src = newscriptC;
	headID.appendChild(newScriptC);	
	goLastScriptC = newScriptC;
}


//Loads JS into the document permanently until refresh
function fvPLoadJS(p_sJS)
{
	var headID = document.getElementsByTagName("head")[0];
	var newscript =  p_sJS + '?' + "ms=" + new Date().getTime();
	var newScript = document.createElement('script')
	newScript.type = 'text/javascript';
	newScript.src = newscript
	headID.appendChild(newScript);	
}

//------------------------- APP NAVIGATION FUNCTIONS ----------------------------------//




//Pops/unpops the app submenu



//------------------------ URL OPENING / NAVIGATION FUNCTIONS -----------------------------------//

//Push URL function (refreshes divs in silence)
function fvPush(sURL, oResponseDiv, p_bLoadingIndicator)
{
	
	if(p_bLoadingIndicator == null)
		p_bLoadingIndiactor = false;
		
	var xmlHttp = getXMLHttp();

	if(p_bLoadingIndicator == true)
		if(oResponseDiv == divSubPage && divFocus != divSubPage)
		{
			bSubPage = true;
			$('#' + divBody).showLoading();
		}
		else
		{
			bSubPage = false;
			$('#' + oResponseDiv).showLoading();
		}
		  
 	xmlHttp.onreadystatechange = function()
 	{	
		if(xmlHttp.readyState == 4)
		{
			//Save the current URL loaded into the div
			Navigation.aCurrentPages[oResponseDiv] = sURL;
			
			HandleResponseSilent(xmlHttp.responseText, oResponseDiv);	
	
			if(oResponseDiv == divSubPage)
			{   	
				//Show the div and black out the background
				document.getElementById(divSubPage).style.visibility = 'visible';		
				divFocus = divSubPage;	
				fvShowShadow(divSubPage);
			}
				
			//Hide loading image
			if(p_bLoadingIndicator == true)
				if(bSubPage == true)
					$('#' + divBody).hideLoading();
				else
					$('#' + oResponseDiv).hideLoading();		  
   		}
  	}

  xmlHttp.open("GET", sURL + "&ms=" + new Date().getTime(), true); 
  xmlHttp.send(null);
 
}


//Opens a URL, while showing a loading image
//Intelligent and aware of divSubPage and its needed actions
function OpenURL(sURL, oResponseDiv)
{
	if((sURL.substr(0,7)).toLowerCase() == "http://" || (sURL.substr(0,8)).toLowerCase() == "https://")
		window.location = sURL;
	else
	{
		var xmlHttp = getXMLHttp();
	  
		//Loading image
		if(oResponseDiv == divSubPage && divFocus != divSubPage)
		{
			bSubPage = true;
			$('#' + divBody).showLoading();
		}
		else
		{
			bSubPage = false;
			$('#' + oResponseDiv).showLoading();
		}
					 	
		xmlHttp.onreadystatechange = function()
		{
			if(xmlHttp.readyState == 4)
			{
				//Save the current URL loaded into the div
				Navigation.aCurrentPages[oResponseDiv] = sURL;
							
				HandleResponse(xmlHttp.responseText, oResponseDiv);
				
				if(oResponseDiv == divSubPage)
				{
			    	
					//Show the div and black out the background
					document.getElementById(divSubPage).style.visibility = 'visible';
					fvShowShadow(divSubPage);				
					divFocus = divSubPage;	
					
				}
	
				//Destroy loading image	
				if(bSubPage == true)
					$('#' + divBody).hideLoading();
				else
					$('#' + oResponseDiv).hideLoading();
					
				//Report to google analytics
				if(gbGoogleAnalytics)
					_gaq.push(['_trackPageview', 'sURL']);
		
			}
		}
	
	
		if(sURL != "#")
		{
			xmlHttp.open("GET", sURL + "&ms=" + new Date().getTime(), true); 
			xmlHttp.send(null);	
		}
		else
		{
			//Destroy loading image
			//document.getElementById(divLoading).innerHTML = "";			
			$("#" + oResponseDiv).hideLoading();	
		}
	}
	
}
//-----------------------------------------------------------------------------------------//





//------------------------- FORM SUBMISSION FUNCTIONS --------------------------------------//
//Submits a form based on GET, specify form name, submission URL and return DIV
function SubmitFormGet(sFormName, sURL, oResponseDiv, btnSubmit, bDiscard)
{
	if(bDiscard == null)
		var sFormData = "?";
	else
		var sFormData = "";
				
	for(i=0; i<document.forms[sFormName].length; i++)
	{
			
		//Verify checkbox
		if(document.forms[sFormName].elements[i].type != "checkbox" && document.forms[sFormName].elements[i].type != "radio")
		{
			sFormData += "&";
			sFormData += document.forms[sFormName].elements[i].name;
			sFormData += "=";
			sFormData += escape(document.forms[sFormName].elements[i].value); 
		}
		else
		{		
			//Make sure its checked
			if(document.forms[sFormName].elements[i].checked == true)
			{
				sFormData += "&";
				sFormData += document.forms[sFormName].elements[i].name;
				sFormData += "=";
				sFormData += escape(document.forms[sFormName].elements[i].value); 					
			}
		}
	}
	

	MakeRequest((sURL + sFormData), oResponseDiv, btnSubmit);
}

//Submits a form based on GET, specify form name, submission URL and return DIV ... appends to existing url, discards ?
function SubmitFormGetApp(sFormName, sURL, oResponseDiv, btnSubmit)
{
	SubmitFormGet(sFormName, sURL, oResponseDiv, btnSubmit, true);
}


//Same as above except the method is post
function SubmitFormPost(sFormName, sURL, oResponseDiv, btnSubmit)
{
		
	var sFormData = "?";
	var xmlHttp = getXMLHttp();
	
	 //Disable submit button
 	if(btnSubmit)
	{
	  	btnSubmit.disabled=true;
 	}
	
	for(i=0; i<document.forms[sFormName].length; i++)
	{
			
		//Verify checkbox
		if(document.forms[sFormName].elements[i].type != "checkbox" && document.forms[sFormName].elements[i].type != "radio")
		{
			sFormData += "&";
			sFormData += document.forms[sFormName].elements[i].name;
			sFormData += "=";
	
			if ( document.forms[sFormName].elements[i].name.indexOf("CKEDITOR") > -1 )
			{
				//Provision for CKEditor
				try
				{
					sFormData += escape( eval("CKEDITOR.instances." + document.forms[sFormName].elements[i].name + ".getData()") );
				} catch (e)
				{
					sFormData += "NOT_LOADED";
				}
			}
			else
			{
				//Process normally
				sFormData += escape(document.forms[sFormName].elements[i].value);							
			}
			
		}
		else
		{		
			//Make sure its checked
			if(document.forms[sFormName].elements[i].checked == true)
			{
				sFormData += "&";
				sFormData += document.forms[sFormName].elements[i].name;
				sFormData += "=";
				sFormData += escape(document.forms[sFormName].elements[i].value); 					
			}
		}
	}
	
	
	xmlHttp.open("POST", sURL, true);
	
	//Send the proper header information along with the request
	xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
	xmlHttp.setRequestHeader("Content-length", sFormData.length);
	xmlHttp.setRequestHeader("Cache-Control", "no-store, no-cache, must-revalidate");
	xmlHttp.setRequestHeader("Cache-Control", "post-check=0, pre-check=0");
	xmlHttp.setRequestHeader("Pragma", "no-cache");
	xmlHttp.setRequestHeader("Connection", "close");


	 //Loading image
	 //document.getElementById(divLoading).innerHTML = "<br /><img src='" + imgLoading.src + "'>";
	$("#" + oResponseDiv).showLoading();
	
	xmlHttp.onreadystatechange = function()
  	{
    	if(xmlHttp.readyState == 4)
    	{	
   		   	HandleResponse(xmlHttp.responseText, oResponseDiv);
	
			//Enable submit button
		 	if(btnSubmit)
 			{
				btnSubmit.disabled=false;
			}	
	
			//Destroy loading image
  			//document.getElementById(divLoading).innerHTML = "";
			$("#" + oResponseDiv).hideLoading();
    	}
  	}
	
	
	xmlHttp.send(sFormData);

}

//Same as above except the post is "silent"
function SilentFormPost(sFormName, sURL, oResponseDiv, btnSubmit, divOrigin)
{
	var sFormData = "?";
	var xmlHttp = getXMLHttp();

	if(oResponseDiv == divBG)
		if(divOrigin == null)
			divOrigin = "subBody";
	
	 //Disable submit button
 	if(btnSubmit)
	{
	  	btnSubmit.disabled=true;
 	}
	
	for(i=0; i<document.forms[sFormName].length; i++)
	{
			
		//Verify checkbox
		if(document.forms[sFormName].elements[i].type != "checkbox" && document.forms[sFormName].elements[i].type != "radio")
		{
			sFormData += "&";
			sFormData += document.forms[sFormName].elements[i].name;
			sFormData += "=";
	
			if ( document.forms[sFormName].elements[i].name.indexOf("CKEDITOR") > -1 )
			{
				//Provision for CKEditor
				try
				{
					sFormData += escape( eval("CKEDITOR.instances." + document.forms[sFormName].elements[i].name + ".getData()") );
				} catch (e)
				{
					sFormData += "NOT_LOADED";
				}
			}
			else
			{
				//Process normally
				sFormData += escape(document.forms[sFormName].elements[i].value);							
			}
			
		}
		else
		{		
			//Make sure its checked
			if(document.forms[sFormName].elements[i].checked == true)
			{
				sFormData += "&";
				sFormData += document.forms[sFormName].elements[i].name;
				sFormData += "=";
				sFormData += escape(document.forms[sFormName].elements[i].value); 					
			}
		}
	}
	
	xmlHttp.open("POST", sURL, true);
	
	//Send the proper header information along with the request
	xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
	xmlHttp.setRequestHeader("Content-length", sFormData.length);
	xmlHttp.setRequestHeader("Cache-Control", "no-store, no-cache, must-revalidate");
	xmlHttp.setRequestHeader("Cache-Control", "post-check=0, pre-check=0");
	xmlHttp.setRequestHeader("Pragma", "no-cache");
	xmlHttp.setRequestHeader("Connection", "close");


	 //Loading image
	 //document.getElementById(divLoading).innerHTML = "<br /><img src='" + imgLoading.src + "'>";
	if(divOrigin == null)
		 $("#" + oResponseDiv).showLoading();
	else
		 $("#" + divOrigin).showLoading();
	 
	xmlHttp.onreadystatechange = function()
  	{
    	if(xmlHttp.readyState == 4)
    	{	
   		   	HandleResponseSilent(xmlHttp.responseText, oResponseDiv);
	
			//Enable submit button
		 	if(btnSubmit)
 			{
				btnSubmit.disabled=false;
			}	
	
			//Destroy loading image
  			//document.getElementById(divLoading).innerHTML = "";
			if(divOrigin == null)
				 $("#" + oResponseDiv).hideLoading();
			else
				 $("#" + divOrigin).hideLoading();
    	}
  	}
	
	
	xmlHttp.send(sFormData);

}

//SubimitFormUpload, dummy function mostly
function SubmitFormUpload(sFormName, sURL, oResponseDiv, btnSubmit)
{
	
	var sFormData = "?";
	var xmlHttp = getXMLHttp();
	
	 //Disable submit button
 	if(btnSubmit)
	{
	  	btnSubmit.disabled=true;
 	}

	 //Loading image
	 //document.getElementById(divLoading).innerHTML = "<br /><img src='" + imgLoading.src + "'>";
	$("#" + oResponseDiv).showLoading();

	//Submit form
	document.forms[sFormName].submit();
	
}





///----------------------- Popup elements showing / hiding functions ----------------------------------//

//Shows a shadow on a popup element
function fvCenterDiv(p_sDiv)
{
	nBodyLeft = $("#" + divMasterBody).offset().left;
	nBodyWidth = $("#" + divBody).outerWidth();
	nBodyHeight = $("#" + divBody).outerHeight();
	nDivWidth = $("#" + p_sDiv).outerWidth();
	nSpan = (nBodyLeft + nBodyWidth/2) - (nDivWidth/2);
	nVSpan = nBodyHeight / 4;
	 
	$("#" + p_sDiv).css("top", nVSpan + "px");
	$("#" + p_sDiv).css("left", nSpan + "px");
}

function fvShowShadow(p_sDiv)
{		
	//Remove existing shadows
	$("#" + divShadow + "_" +  p_sDiv).remove();
	
	$(document.body).append("<div id='divShadow_" + p_sDiv + "' class='divShadow'></div>");
	document.getElementById(divShadow + "_" + p_sDiv).style.visibility = 'visible';	
	$("#" + divShadow + "_" + p_sDiv).css("width", $("#" + p_sDiv).outerWidth()+30 + "px");
	$("#" + divShadow + "_" + p_sDiv).css("height", $("#" + p_sDiv).outerHeight()+30 + "px");
	$("#" + divShadow + "_" + p_sDiv).css("left", $("#" + p_sDiv).offset().left-15);
	$("#" + divShadow + "_" + p_sDiv).css("top", $("#" + p_sDiv).offset().top-15);
	$("#" + divShadow + "_" + p_sDiv).css("z-index", ($("#" + p_sDiv).css("z-index")-1));
	$("#" + divShadow + "_" + p_sDiv).corner();	
}

function fvHideShadow(p_sDiv)
{
	$("#" + divShadow + "_" +  p_sDiv).remove();
}

//Error, information & debug reporting functions
function showInfo(sInfo)
{
	document.getElementById("infobox").innerHTML += "<br>";
	document.getElementById("infobox").innerHTML += sInfo;	
	document.getElementById('infobox').style.visibility = 'visible';
	
	fvCenterDiv("infobox");
	fvShowShadow("infobox");
}

function showError(sInfo)
{
	document.getElementById("errorbox").innerHTML += "<br>";
	document.getElementById("errorbox").innerHTML += sInfo;	
	document.getElementById('errorbox').style.visibility = 'visible';
	
	fvCenterDiv("errorbox");
	fvShowShadow("errorbox");
}

function showDebug(sInfo)
{
	document.getElementById("debugbox").innerHTML += "<br>";
	document.getElementById("debugbox").innerHTML += sInfo;	
	document.getElementById('debugbox').style.visibility = 'visible';

	fvCenterDiv("debugbox");
	fvShowShadow("debugbox");
}

function hideInfo()
{
	document.getElementById('infobox').style.visibility = 'hidden';
	
	//Only unhide the blackbox if a subpage is not visible
	//if(document.getElementById(divSubPage).style.visibility != 'visible')
	fvHideShadow("infobox");
			
	//Clear stored error
	document.getElementById("infobox").innerHTML = '<a href="#" onclick="hideInfo();"><img src="/images/cross.gif"></a>';
}

function hideError()
{
	document.getElementById('errorbox').style.visibility = 'hidden';
	
	//Only unhide the blackbox if a subpage is not visible
	//if(document.getElementById(divSubPage).style.visibility != 'visible')
	fvHideShadow("errorbox");
		
	//Clear stored error
	document.getElementById("errorbox").innerHTML = '<a href="#" onclick="hideError();"><img src="/images/cross.gif"></a>';
	
}

function hideDebug()
{
	document.getElementById('debugbox').style.visibility = 'hidden';

	//Only unhide the blackbox if a subpage is not visible
	//if(document.getElementById(divSubPage).style.visibility != 'visible')
	fvHideShadow("debugbox");
	
	//Clear stored error
	document.getElementById("debugbox").innerHTML = '<a href="#" onclick="hideDebug();"><img src="/images/cross.gif"></a>';
	
}

function showSubPage()
{
	document.getElementById(divSubPage).style.visibility = 'visible';	
	fvShowShadow(divSubPage);
			
	//Restore focus to main page
	divFocus = divSubPage;
}


function hideSubPage()
{
	fvHideShadow(divSubPage);
	document.getElementById(divSubPage).style.visibility = 'hidden';	
		
	//Restore focus to main page
	divFocus = divBody;
}




//------------------------------------- GRID FUNCTIONS ----------------------------------------//

//Allows reenabling of grid
function fvGridDoubleClicked(tItem)
{
		tItem.style.border = "1px solid";
		bCancelGridInput = false;
		
		//Save the value of the item
		sInputTemp = tItem.value;
}

//Disable grid and submit form / update
function fvGridDisable(tItem, sFormName, sURL)
{
	//Ensure its editable first
	if(bCancelGridInput == false)
	{
		tItem.style.border = "0px";
		bCancelGridInput = true;
		
		//Compare value to see if it has changed, if not then don't submit
		if(sInputTemp != tItem.value)
			SubmitFormGetApp(sFormName, sURL, divFocus,tItem);
	}
	
	sInputTemp = "";
}

//Disable grid and submit form / update
function fvGridUpdate(tItem, sFormName, sURL)
{
	//Ensure its editable first
	SubmitFormGetApp(sFormName, sURL, divFocus,tItem);
	
	sInputTemp = "";
}


//Function to allow or disallow grid input
function fbCancelGridInput()
{
		if(bCancelGridInput == true)
			return true;
		else
			return false;
}




//------------------------- PUSH NOTIFICATION MANAGEMENT FUNCTIONS -----------------------------//
//Shows a notification in the looking glass
function fvPushNotification(p_sMsg)
{
		sRand = fsGenRandID();
		document.getElementById(divNotifications).innerHTML += "<div class=\"divNotify\" id=\"" + sRand + "\"><div class=\"divNotifyX\"><a href=\"#\" onclick='fvRemoveNotification(\"" + sRand + "\")'><img src=\"/images/cross.gif\"></a></div><div class=\"divNotifyTxt\">" + p_sMsg + "</div></div>";
		setTimeout("fvRemoveNotification(\"" + sRand + "\")", 300000);
}

//Removes a notification from the looking glass
function fvRemoveNotification(p_sDiv)
{
	//wD=document.getElementById(p_sDiv);
	//wD.parentNode.removeChild(wD);
	$("#" + p_sDiv).slideUp();
}




//------------------------- XML/HTTP REQUEST FUNCTIONS -------------------------------------//
//Returns an XML Http Object
function getXMLHttp()
{
	var xmlHttp


	try
	{
		//Firefox, Opera 8.0+, Safari
		xmlHttp = new XMLHttpRequest();
	}
	catch (e)
	{
		//Internet Explorer
		try
		{
		 	xmlHttp = new ActiveXObject("Msxml2.XMLHTTP"); 
		}
		catch(e)
		{
			try
		  	{
				xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
			}
		 	catch(e)
		  	{
				alert("Your browser does not support AJAX!")
				return false;
		  	}
		}
	}
  
	return xmlHttp;
}

//Opens a URL and returns the content into the given DIV
function MakeRequest(sURL, oResponseDiv, btnSubmit)
{		
  var xmlHttp = getXMLHttp();
  
 	//Disable submit button
 	if(btnSubmit)
	{
	  	btnSubmit.disabled=true;
 	}
  
 	//Loading image
 	//document.getElementById(divLoading).innerHTML = "<br /><img src='" + imgLoading.src + "'>";
	$("#" + oResponseDiv).showLoading();

 	xmlHttp.onreadystatechange = function()
 	{
    		if(xmlHttp.readyState == 4)
    		{
      			HandleResponse(xmlHttp.responseText, oResponseDiv);
			  
			//Destroy loading image
 			//document.getElementById(divLoading).innerHTML = "";
			$("#" + oResponseDiv).hideLoading();
					
			//Enable submit button
		 	if(btnSubmit)
 			{
				btnSubmit.disabled=false;
			}
			
   		}
  	}

  xmlHttp.open("GET", sURL, true); 
  xmlHttp.send(null);
  
}

//Transfers a response into a div
function TransferResponse(response, oResponseDiv)
{
	document.getElementById(oResponseDiv).innerHTML = ""; //Clear div
	
	//if(sSession != "" && divFocus != divSubPage)
	//	document.getElementById(divMenu).innerHTML = ""; //Clear menu bar
	
  	document.getElementById(oResponseDiv).innerHTML = response;
	
	//Destroy loading image
	//document.getElementById(divLoading).innerHTML = "";
	$("#" + oResponseDiv).hideLoading();
}

//Transfers a response into a div and also executes the scripts in the response
function HandleResponse(response, oResponseDiv)
{	
	//Clear out the div
	document.getElementById(oResponseDiv).innerHTML = ""; //Clear div
	
	if(divFocus != divSubPage)
		Layout.fvClearMenu();
	
	if(oResponseDiv == divBody)
		Layout.fvResetDivs();	

  	document.getElementById(oResponseDiv).innerHTML += response;


	if(oResponseDiv == divSubPage)
	{
		fvShowShadow(divSubPage);
		//Okay this is a sub page, we must prepend the close button
		//document.getElementById(oResponseDiv).innerHTML = '<a href="#" onclick="hideSubPage();" class="subPageX"><img src="/images/cross.gif"></a><br>';	
	}
	
				


	//For internet explorer
	if(navigator.userAgent.indexOf("MSIE") != -1)
	{
		try
		{
			tags = response.split("<script");
						
			for(i=1;i<tags.length;i++)
			{

				sScript = tags[i].substr( tags[i].indexOf(">")+1, tags[i].length);
				tags2 = sScript.split("</script>");		
				
	
				eval(tags2[0]);				
			}
		
	
		} catch(e) { }
		
	}
	else
	{
		//execute script tags
		var x = document.getElementById(oResponseDiv).getElementsByTagName("SCRIPT"); 
	
		for(var i=0;i<x.length;i++)  
		{  
			eval(x[i].text);  
		} 		
	}	

	//Refresh tooltips
	if(oResponseDiv == divBody || oResponseDiv == divSubPage)
		JT_init();
}

//Same as above but doesn't show the loading indicator (hence silent)
function HandleResponseSilent(response, oResponseDiv)
{
	
	document.getElementById(oResponseDiv).innerHTML = ""; //Clear div

	if(oResponseDiv == divSubPage)
	{
		//Okay this is a sub page, we must prepend the close button
		//document.getElementById(oResponseDiv).innerHTML = '<a href="#" onclick="hideSubPage();" class="subPageX"><img src="/images/cross.gif"></a><br>';	
	}
		
  	document.getElementById(oResponseDiv).innerHTML += response;
     

	//For internet explorer
	if(navigator.userAgent.indexOf("MSIE") != -1)
	{
		try
		{
			tags = response.split("<script language=");
						
			for(i=1;i<tags.length;i++)
			{

				sScript = tags[i].substr( tags[i].indexOf(">")+1, tags[i].length);
				tags2 = sScript.split("</script>");		
				
	
				eval(tags2[0]);				
			}
		
	
		} catch(e) { }
	}
	else
	{
		//execute script tags
		var x = document.getElementById(oResponseDiv).getElementsByTagName("SCRIPT"); 
	
		for(var i=0;i<x.length;i++)  
		{  
				eval(x[i].text);  
		} 		
	}	
	
	//Refresh tooltips
	if(oResponseDiv == divBody)
		JT_init();	
}

//Adds to the existing content in a div instead of clearing it first
function HandleResponseRetain(response, oResponseDiv)
{
	
  	document.getElementById(oResponseDiv).innerHTML += "<br>";
  	document.getElementById(oResponseDiv).innerHTML += response;
   
	//For internet explorer
	if(navigator.userAgent.indexOf("MSIE") != -1)
	{
		try
		{
			tags = response.split("<script language=");
						
			for(i=1;i<tags.length;i++)
			{

				sScript = tags[i].substr( tags[i].indexOf(">")+1, tags[i].length);
				tags2 = sScript.split("</script>");		
				
	
				eval(tags2[0]);				
			}
		
	
		} catch(e) { }		
	}
	else
	{
		//execute script tags
		var x = document.getElementById(oResponseDiv).getElementsByTagName("SCRIPT"); 
	
		for(var i=0;i<x.length;i++)  
		{  
				eval(x[i].text);  
		} 		
	}	
	
	//Refresh tooltips
	if(oResponseDiv == divBody)
		JT_init();	
}




//---------------------- MISCELLANEOUS AND UNCLASSIFIED FUNCTIONS --------------------------//

function fvGetCookie(c_name)
{
	var i,x,y,ARRcookies=document.cookie.split(";");
	for (i=0;i<ARRcookies.length;i++)
	{
	  x=ARRcookies[i].substr(0,ARRcookies[i].indexOf("="));
	  y=ARRcookies[i].substr(ARRcookies[i].indexOf("=")+1);
	  x=x.replace(/^\s+|\s+$/g,"");
	  if (x==c_name)
		{
		return unescape(y);
		}
	 }
}

function fvSetCookie(c_name,value,exdays)
{
	var exdate=new Date();
	exdate.setDate(exdate.getDate() + exdays);
	var c_value=escape(value) + ((exdays==null) ? "" : "; expires="+exdate.toUTCString());
	document.cookie=c_name + "=" + c_value;
}

//Generates a random ID / string
function fsGenRandID()
{
	var sList = new Array;
	sList[0] = "a";
	sList[1] = "b";
	sList[3] = "c";
	sList[4] = "d";
	sList[5] = "e";
	sList[6] = "f";
	sList[7] = "g";
	sList[8] = "h";
	sList[9] = "i";

	var randomnumber1=Math.floor(Math.random()*9);
	var randomnumber2=Math.floor(Math.random()*9);
	var randomnumber3=Math.floor(Math.random()*9);
	var randomnumber4=Math.floor(Math.random()*9);
	var randomnumber5=Math.floor(Math.random()*9);
	var randomnumber6=Math.floor(Math.random()*9);
	var randomnumber7=Math.floor(Math.random()*9);
	var randomnumber8=Math.floor(Math.random()*9);	
	var randomnumber9=Math.floor(Math.random()*9);

	
	sRandString = (sList[randomnumber1] + randomnumber9.toString()) + (sList[randomnumber2] + randomnumber8.toString()) + (sList[randomnumber3] + randomnumber7.toString())  + (sList[randomnumber4] + randomnumber6.toString()) + (sList[randomnumber5] + randomnumber5.toString())  + (sList[randomnumber6] + randomnumber4.toString())  + (sList[randomnumber7] + randomnumber3.toString()) + (sList[randomnumber8] + randomnumber2.toString())  + (sList[randomnumber9] + randomnumber1.toString()); 
	
	return sRandString;
}

//Returns version # of the MSIE agent
function msieversion()
{
  var ua = window.navigator.userAgent
  var msie = ua.indexOf ( "MSIE " )

  if ( msie > 0 )      // If Internet Explorer, return version number
	 return parseInt (ua.substring (msie+5, ua.indexOf (".", msie )))
  else                 // If another browser, return 0
	 return 0;

}


function fvPopupInput(p_sType, p_sDefaultValue, p_sText, p_sPostURL)
{
	sInnerBody = "";
	p_sDefaultValue = Base64.decode(p_sDefaultValue);
		
	if(p_sType == "text")
	{
		sInnerBody = p_sText + " <input type=\"text\" name=\"sPopupInput\" id=\"sPopupInput\" class=\"inputPopupInput\">";
	}
	
	sBody = "<div class=\"inputPopupControls\"><form onsubmit=\"return false\" name=\"frmPopupInput\">" + sInnerBody + "<br /><input type=\"button\" value=\"Save\" onclick=\"SubmitFormPost('frmPopupInput', '" + p_sPostURL + "', divFocus, this);fvHideShadow('inputPopup');$('#inputPopup').remove();\"> <input type=\"button\" value=\"Cancel\" onclick=\"fvHideShadow('inputPopup');$('#inputPopup').remove();\"></form></div>";
	
	
	$(document.body).append("<div id=\"inputPopup\" class=\"inputPopup\"><div class=\"inputPopupTitle\">Please enter the requested information</div><div class=\"inputPopupBody\">" + sBody + "</div></div>");
	fvCenterDiv("inputPopup");
	fvShowShadow("inputPopup");
	$("#sPopupInput").val(p_sDefaultValue);
}



/**
*
*  Base64 encode / decode
*  http://www.webtoolkit.info/
*
**/
 
var Base64 = {
 
	// private property
	_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
 
	// public method for encoding
	encode : function (input) {
		var output = "";
		var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
		var i = 0;
 
		input = Base64._utf8_encode(input);
 
		while (i < input.length) {
 
			chr1 = input.charCodeAt(i++);
			chr2 = input.charCodeAt(i++);
			chr3 = input.charCodeAt(i++);
 
			enc1 = chr1 >> 2;
			enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
			enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
			enc4 = chr3 & 63;
 
			if (isNaN(chr2)) {
				enc3 = enc4 = 64;
			} else if (isNaN(chr3)) {
				enc4 = 64;
			}
 
			output = output +
			this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
			this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
 
		}
 
		return output;
	},
 
	// public method for decoding
	decode : function (input) {
		var output = "";
		var chr1, chr2, chr3;
		var enc1, enc2, enc3, enc4;
		var i = 0;
 
		input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
 
		while (i < input.length) {
 
			enc1 = this._keyStr.indexOf(input.charAt(i++));
			enc2 = this._keyStr.indexOf(input.charAt(i++));
			enc3 = this._keyStr.indexOf(input.charAt(i++));
			enc4 = this._keyStr.indexOf(input.charAt(i++));
 
			chr1 = (enc1 << 2) | (enc2 >> 4);
			chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
			chr3 = ((enc3 & 3) << 6) | enc4;
 
			output = output + String.fromCharCode(chr1);
 
			if (enc3 != 64) {
				output = output + String.fromCharCode(chr2);
			}
			if (enc4 != 64) {
				output = output + String.fromCharCode(chr3);
			}
 
		}
 
		output = Base64._utf8_decode(output);
 
		return output;
 
	},
 
	// private method for UTF-8 encoding
	_utf8_encode : function (string) {
		string = string.replace(/\r\n/g,"\n");
		var utftext = "";
 
		for (var n = 0; n < string.length; n++) {
 
			var c = string.charCodeAt(n);
 
			if (c < 128) {
				utftext += String.fromCharCode(c);
			}
			else if((c > 127) && (c < 2048)) {
				utftext += String.fromCharCode((c >> 6) | 192);
				utftext += String.fromCharCode((c & 63) | 128);
			}
			else {
				utftext += String.fromCharCode((c >> 12) | 224);
				utftext += String.fromCharCode(((c >> 6) & 63) | 128);
				utftext += String.fromCharCode((c & 63) | 128);
			}
 
		}
 
		return utftext;
	},
 
	// private method for UTF-8 decoding
	_utf8_decode : function (utftext) {
		var string = "";
		var i = 0;
		var c = c1 = c2 = 0;
 
		while ( i < utftext.length ) {
 
			c = utftext.charCodeAt(i);
 
			if (c < 128) {
				string += String.fromCharCode(c);
				i++;
			}
			else if((c > 191) && (c < 224)) {
				c2 = utftext.charCodeAt(i+1);
				string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
				i += 2;
			}
			else {
				c2 = utftext.charCodeAt(i+1);
				c3 = utftext.charCodeAt(i+2);
				string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
				i += 3;
			}
 
		}
 
		return string;
	}
 
}




