// $Header: /usr/local/cvsroot/AA210/WebRoot/Static/js/AA22004_IPUtil.js,v 1.1 2009/08/25 08:24:05 rtm Exp $
// Copyright (c) 2002 Xippix Inc.
// Copyright (c) 2003, 2004, 2005 TerraGrafica, Inc.
// Copyright (c) 2005,2006,2007,2008 ABIS Technologies, Inc.
// All Rights Reserved.
//
// JavaScript utility code.
// Included in all JSPs via Common HeadTop.jsp.
// XXX00:20031222rtm:name dates back to "IPViewer util", now general. Should rename to more generic, maybe just util.js.
var ipUtilIncluded = true;

// The constructor function: creates a Cookie object for the specified
// document, with a specified name and optional attributes.
// Arguments:
//   document: The Document object for which the cookie is stored. Required.
//   name:     A string that specifies a name for the cookie. Required.
//   hours:    An optional number that specifies the number of hours from now
//             after which the cookie should expire.
//   path:     An optional string that specifies the cookie path attribute.
//   domain:   An optional string that specifies the cookie domain attribute.
//   secure:   An optional boolean value that, if true, requests a secure cookie.
//
function Cookie(document, name, hours, path, domain, secure)
{
    // All the predefined properties of this object begin with '$'
    // to distinguish them from other properties, which are the values to
    // be stored in the cookie
    this.$document = document;
    this.$name = name;
    if (hours)
        this.$expiration = new Date((new Date()).getTime(  ) + hours*3600000);
    else this.$expiration = null;
    if (path) this.$path = path; else this.$path = null;
    if (domain) this.$domain = domain; else this.$domain = null;
    if (secure) this.$secure = true; else this.$secure = false;
}

// This function is the store(  ) method of the Cookie object
Cookie.prototype.store = function (  ) {
    // First, loop through the properties of the Cookie object and
    // put together the value of the cookie. Since cookies use the
    // equals sign and semicolons as separators, we'll use colons
    // and ampersands for the individual state variables we store
    // within a single cookie value. Note that we escape the value
    // of each state variable, in case it contains punctuation or other
    // illegal characters.
    var cookieval = "";
    for(var prop in this) {
        // Ignore properties with names that begin with '$' and also methods
        if ((prop.charAt(0) == '$') || ((typeof this[prop]) == 'function'))
            continue;
         if (cookieval != "") cookieval += '&';
	cookieval += prop + ':' + escape(this[prop]);	// bz6395 colon is illegal char here
//	cookieval += prop + '!' + escape(this[prop]);	// bz6395 simple fix (after 209, or for dev)
    }

    // Now that we have the value of the cookie, put together the
    // complete cookie string, which includes the name and the various
    // attributes specified when the Cookie object was created
    var cookie = this.$name + '=' + cookieval;
    if (this.$expiration)
        cookie += '; expires=' + this.$expiration.toGMTString(  ); // bz6405
    if (this.$path) cookie += '; path=' + this.$path;
    if (this.$domain) cookie += '; domain=' + this.$domain;
    if (this.$secure) cookie += '; secure';

    //alert(cookie);

    // Now store the cookie by setting the magic Document.cookie property
    this.$document.cookie = cookie;
}

// This function is the load(  ) method of the Cookie object
Cookie.prototype.load = function(  ) {
    // First, get a list of all cookies that pertain to this document
    // We do this by reading the magic Document.cookie property
    var allcookies = this.$document.cookie;
    if (allcookies == "") return false;

    // Now extract just the named cookie from that list
    var start = allcookies.indexOf(this.$name + '=');
    if (start == -1) return false;   // Cookie not defined for this page
    start += this.$name.length + 1;  // Skip name and equals sign
    var end = allcookies.indexOf(';', start);
    if (end == -1) end = allcookies.length;
    var cookieval = allcookies.substring(start, end);

    // XXX0000000000:20080328rtm:CLEANUP: Not sure whose rules these are... probably just "ours", not standard JS (I hope)
    // Now that we've extracted the value of the named cookie, we
    // must break that value down into individual state variable
    // names and values. The name/value pairs are separated from each
    // other by ampersands, and the individual names and values are
    // separated from each other by colons. We use the split(  ) method
    // to parse everything.
    var a = cookieval.split('&');    // Break it into an array of name/value pairs
    for(var i=0; i < a.length; i++)  // Break each pair into an array
	a[i] = a[i].split(':');	// bz6395 colon is illegal char here
//	a[i] = a[i].split('!');	// bz6395 simple fix (after 209, or for dev)

    // Now that we've parsed the cookie value, set all the names and values
    // of the state variables in this Cookie object. Note that we unescape(  )
    // the property value, because we called escape(  ) when we stored it.
    for(var i = 0; i < a.length; i++) {
        this[a[i][0]] = unescape(a[i][1]);
    }

    // We're done, so return the success code
    return true;
}

// This function is the remove(  ) method of the Cookie object
Cookie.prototype.remove = function(  ) {
    var cookie;
    cookie = this.$name + '=';
    if (this.$path) cookie += '; path=' + this.$path;
    if (this.$domain) cookie += '; domain=' + this.$domain;
    cookie += '; expires=Fri, 02-Jan-1970 00:00:00 GMT'; // bz6405
    this.$document.cookie = cookie;
}

// Update browser info cookie and reload the page (iff dim changed), after short timeout.
// This is used from onResize by pages that use server-side layout based on page size, for example.
// The timeout is there because:
// 1. On windows IE, the resize event is fired repeatedly during drag, appears no way to know when it finishes.
// 2. On Mac OS 9 the values are only updated after the event is handled, so we have to return then take
//	action later, from the timeout.
var pageResizeTimeout = 0;
function setBrowserInfoAndReloadAfterTimeout() {

    clearTimeout(pageResizeTimeout);
    pageResizeTimeout=setTimeout("clearTimeout(pageResizeTimeout);setBrowserInfo(true);", 400);
}

// put browser width and height in a cookie for server to use
// does a reload iff the info changes
// XXX00:20031217rtm: This seems like an awful hack, but empirically it seems that the new
// XXX00:20031217rtm:    cookie value doesn't get sent on the very next get. Specifically, failing to
// XXX00:20031217rtm:    do the reload on change meant that going from Login to Gallery could miss
// XXX00:20031217rtm:    a dim change, even though the cookie was being set properly in the Login page. Annoying.
function setBrowserInfo(mayReload) {

    var docWidth = -1;
    var docHeight= -1;

    if (document.all) {
	// IE case, document.all is undefined otherwise
        docWidth  = document.body.clientWidth;  //XXX0:20031125iah: was offsetWidth/Height, not sure what's right
        docHeight = document.body.clientHeight;
    } else {
	docWidth  = window.innerWidth;
	docHeight = window.innerHeight;
    }
    setBrowserInfoCookie(docWidth, docHeight, mayReload);
}

function setBrowserInfoCookie(docWidth, docHeight, mayReload) {
    var browserInfo = new Cookie(document, "TGI_browserInfo", 240, '/'); // 10 days expiration

    // update values
    if (   ! browserInfo.load()
        ||   docWidth == -1
	|| !(browserInfo.docWidth  == docWidth)
	|| !(browserInfo.docHeight == docHeight)) {

	browserInfo.docWidth  = docWidth;
	browserInfo.docHeight = docHeight;
	browserInfo.store();
	//alert('storing cookie with doc size '+ docWidth +' x ' + docHeight);

	// reload page if requested
	if (mayReload) {
	    if (document.getElementById("Gallery") != null) {
		SubmitGalleryForm("Gallery","ResizeBrowser");
	    } else if (document.getElementById("ViewerForm") != null) {
		SubmitViewerForm();
	    } else if (document.getElementById("PublishViewerForm") != null) {
		SubmitViewerForm("PublishViewer");
	    } else if (document.getElementById("AnimatorViewerForm") != null) {
		window.location = animatorUrl;
	    } else {
		// reload the page, but strip the size override params (used on login)
		// XXX000000:20040608iah: currently these params must be at the end of the URL, otherwise other params will be stripped
		var loc = "" + window.location;
		if (loc.indexOf("widthOverride") > 0) {
		    loc = loc.substring(0, loc.indexOf("&widthOverride"));
		}
		window.location = loc;
	    }
	}
    }
}

var loadingMessage = '<html><body bgcolor="#444444" scroll="no"><table width="100%" height="100%"><tr><td align="center"><font face="arial" color="white">Loading...</font></td></tr></table></body></html>';

function showLoadingMessage() { // XXX0000:20031121iah: causes probs, not used for now
	document.body.innerHTML = loadingMessage;
}

function reloadPage() {	// XXX00:20040807rtm: grep says unused, but too close to release to mess with it...
        window.location = window.location;
}

var fullscreenwindow = 0;

function goFullScreen() {

    if (document.all) {
        fullscreenWindow = window.open("","FullscreenWindow","fullscreen");
        fullscreenWindow.document.write(loadingMessage);
        fullscreenWindow.focus();
        fullscreenWindow.resizeTo(window.screen.availWidth, window.screen.availHeight);
	//setBrowserInfoCookie(window.document.body.offsetWidth, window.document.body.offsetHeight);
	//setTimeout("fullscreenWindow.location = window.location",500);
	fullscreenWindow.location = window.location;
   } else {

        window.open(url,"FullscreenWindow","");
	// XXX0000000000:20080330rtm: if pursue this, consider window.focus() also

	// XXX00000:20031121iah: need to handle properly under non-ie browser

	// XXX00000:20040109sg: quick hack for full screen Mozilla XXX00000:20040123iah: same window, so should handle close differently
	//	window.moveTo(0,0);
        //window.resizeTo(screen.availWidth,screen.availHeight);
    }
}

function writeFullScreenHRef() {
	//document.write('document.body.offsetWidth=' + document.body.offsetWidth + ', window.screen.availWidth='+ window.screen.availWidth);
	//document.write('document.body.offsetHeight=' + document.body.offsetHeight + ', window.screen.availHeight='+ window.screen.availHeight);
	if (document.body.offsetWidth  >= window.screen.availWidth &&
	    document.body.offsetHeight >= window.screen.availHeight) {
		document.write('<a class=button style="width:60px;height:20px;" href="javascript:window.close()">i18nText:Button_Close<a>');
	} else {
		document.write('<A class=button style="width:60px;height:20px;" href="javascript:goFullScreen()">i18nText:GalleryTopBarButtonFullScreen</a>');
	}
}


//returns the value of the checked radio button or the empty string if no radio button is checked
//this function is helpful because calling rb.value doesn't work on IE
function getRadioVal(rb){
  var L=rb.length;
  var ret="";
  for (var i = 0 ; i< L ; i++) {
    if(rb[i].checked) {
      ret=rb[i].value;
      break;
    }
  }
  return(ret);
}

var lastInfo = '';

// standard info (tooltipish) display XXX0:20031118iah: finish,doc
// XXX00:20040125rtm:demo feature, disable until dust settles (leave folder summary)
// XXX00:20050917rtm: probably time to remove this; upshot was that having info text changing in a fixed location was mainly distracting
function showInfo(newHtml) {
//	lastInfo = document.getElementById("infoBar").innerHTML;
//	document.getElementById("infoBar").innerHTML = newHtml;
}

function resetInfoBar() {
//	document.getElementById("infoBar").innerHTML = lastInfo;
}

// XXX:20050822rtm: converted remaining usage to FormSubmit; delete soon
//	function xxxSubmitForm(formName, page, act) {
//	    if (page != null && (typeof(page) != 'undefined')) {
//			document.forms[formName].page.value   = page;
//	    } else {
//			document.forms[formName].page.value   = "";	 // bz2717 - gallery toolbar launching wrong action
//	    }
//	    if (act != null && (typeof(act) != 'undefined')) {
//			document.forms[formName].action.value = act;
//	    } else {
//			document.forms[formName].action.value = "";	// bz2717 - gallery toolbar launching wrong action
//	    }
//	    document.forms[formName].submit();
//	}


// Submit form on the page, with optional params, and optional form id.
//
// The form id defaults to "primaryForm", to support typical usage by convention.
// Params are passed as name,value pairs, with the optional formId always last, if passed.
// The names correspond to the form name attributes of the form entries, not their element ids, if any. (bz2857)
//
// Examples:
// 	FormSubmit()					default submit with current form values
//	FormSubmit('action','Edit')			submit for Edit
//	FormSubmit('page','Elsewhere')			submit to a different page handler than the default
//	FormSubmit('itemId','17', 'action','remove')	remove item 17...
//	FormSubmit('thing','foo', 'specialForm')	submit special form with thing=foo
//
// LIMITATION: A form can have multiple entries with the same name, in which case they are
// sent multiply, e.g. as foo=v1&foo=v2 etc. Such same-named multiple entries cannot be
// overridden with this function. So far we don't have any need for that sort of thing,
// and such usage would be special enough to warrant a custom function.
function FormSubmit() {
    submitOnNewWindow = false;  // XXX000:20050919gil: default submit target is the current window
    SubmitFormWithArguments(arguments);
}

// Set this to use FormSubmit and SubmitFormWithArguments  (XXX:20050822rtm:ref bz2627: use with care, not general)
var primaryFormId = "primaryForm";
var submitOnNewWindow = false;

// lower level entry point, called from higher level form submissions functions, 
// do not call directly from HTML!
function SubmitFormWithArguments(args) {
    var numPairs, formId;
    if (args.length % 2 == 0) { // even number of arguments
    	numPairs = (args.length/2);
	formId = primaryFormId;
    } else {
	// we have an odd arg at the end, it's the formId
	numPairs = ((args.length-1)/2);
	formId = args[args.length-1];
    }
    var form = document.getElementById(formId);
    for (i=0; i<numPairs; ++i) {
	name = args[i*2];
	val  = args[i*2+1];
	if (typeof(val) != 'undefined') { // XXX0:20071027rtm:CLEANUP: probably should default to blank, rather than no-op (bz5993)
	    eval("form." + name + ".value = val");
	}
    }
    if (submitOnNewWindow) {
	// XXX00:20070914rtm:bz5875: This approach (form.target=) is currently only used for "email pop-up" for admin,
	// XXX00:20070914rtm:bz5875: but the same can probably be used for download. It migth fail on OS9, in which case
	// XXX00:20070914rtm:bz5875: OS9 may have to continue with the URL limit...
	// XXX00000:20050919gil: For now, we set the attributes statically but they probably should be delivered
	var windowProperties    = "width=700,height=300,resizable=1,menubar=0,toolbar=0,statusbar=0,scrollbars=1";
	var newWindow 	        = window.open("","popup",windowProperties);
//	newWindow.focus(); // bz6384 (consider for AA2)
	form.target             = "popup";
    } else {
	form.target             = "_self";
    }
    form.submit();
}

// Submit form and sends the result to a new page. Besides being opened on a new window, This function is similar 
// to FormSubmit() . See more details in FormSubmit() documentation
function FormSubmitOnNewWindow() {
    submitOnNewWindow = true;
    SubmitFormWithArguments(arguments);
}

// composes a query string based on given list if IDs and their corresponding values
// the expected list of args are the IDs of HTML INPUT elements which may carry a value. For more details, take a look
// at openNewWindowWithArgs() documentation.
function composeQueryString(args) {
    var queryString = "";
    for (i=0; i<args.length; ++i) {
	id      = args[i];
	obj     = document.getElementById(id);
	if (obj != null) {
	    val          = obj.value;
	    if (val != null && val.length >0) {
	       queryString += id + '=' + val + urlSeparator;
	    }
	}
    }
    return queryString;
}

// XXX0:20051110jmg:CLEANUP: There are many javascript functions for opening a new window including:
// XXX0:20051110jmg:CLEANUP: openNewWindow, openNewWindowWithSpecifiedSize, openNewWindowWithArgs,
// XXX0:20051110jmg:CLEANUP: openNewWindowUrl, openNewWindowUrlWithSpecifiedSize, openCSHWindow,
// XXX0:20051110jmg:CLEANUP: openCSHWindow_bz1464, openCurrUrlOnNewWindow.
// XXX0000000000:20071020rtm:CLEANUP: Consolidate to just one with width,height,url. Scrollbars can be hacked just for IE.
// XXX0000000000:20071020rtm:CLEANUP: Width/height depend on the content and usage.

var DEFAULT_WINDOW_WIDTH  = 757;
var DEFAULT_WINDOW_HEIGHT = 623 + 85;	// bz7012 add 85 more pixels of height; this is only used for MUL/HF (ugh)

// forwards a url using the ControllerServlet to a new window.
function openNewWindow(page,action,windowName) {
    var width            = 775 ;
    var height           = 600 ; // @bugid 1096
    var scrollbars       = "1" ; // 'auto' doesnt work -LS
    var titleHeight      = 40  ;
    // @bugid 656 - add vertical scroll bar if screen height too small
    if( screen.availHeight < height + titleHeight ) {
        height = screen.availHeight - titleHeight ;
        scrollbars ="1" ;
        width += 30 ; // add vertical scroll to width
    }
    var url 		 = "/AA/servlet/ControllerServlet?page=" + page + urlSeparator + "action=" + action;
    var windowProperties = "width=" + width + ",height=" + height + ",resizable=1,menubar=0,toolbar=0,statusbar=0,scrollbars=" + scrollbars ;
    var newWindow 	 = window.open(url,windowName,windowProperties);
//  newWindow.focus(); // bz6384 (consider for AA2)
}

// XXX000:20050504gil:  bz1841 - a more flexible signature to openNewWindow(...) which uses a hard coded dimension.
// forwards a url using the ControllerServlet to a new window.
function openNewWindowWithSpecifiedSize(page,action,windowName,width, height,scrollbars) {
    var titleHeight      = 40  ;

    // @bugid 656 - add vertical scroll bar if screen height too small
    if( screen.availHeight < height + titleHeight ) {
        height = screen.availHeight - titleHeight ;
        scrollbars ="1" ;
        width += 30 ; // add vertical scroll to width
    }

    // XXX00:20070920rtm:CLEANUP: Careful, dashboard usage (i18n__AllAssets.jsp) passes general query tacked onto 'action'.
    var url 		 = "/AA/servlet/ControllerServlet?page=" + page + urlSeparator + "action=" + action;
    var windowProperties = "width=" + width + ",height=" + height + ",resizable=1,menubar=0,toolbar=0,statusbar=0,scrollbars=" + scrollbars ;
    var newWindow 	 = window.open(url,windowName,windowProperties);
//  newWindow.focus(); // bz6384 (consider for AA2)
}

// composes a URL which is based on a list of args and forwards it to a new window.
// the expected list of args are the IDs of HTML INPUT elements which may carry a value
// e.g. : Assumming we have a form with the following input entries:
// <input type="hidden" id="page" value="Foo">
// <input type="hidden" id="action" value="Soup">
// <input type="hidden" id="restaurantName" value="Subway">
// when calling javascript:openNewWindowWithArgs('page', 'action', 'restaurantName')  (from the same JSP page)
// The URL that to which we will be forwarded to would look like:
// http://172.27.6.65/AAS/servlet/ContollerServlet?page=Foo&action=Soup&'restaurantName'=Subway
function openNewWindowWithArgs() {
    var width = 775;
    if (gpvIsIE) {	// XXX:20071020rtm: Major hassles with auto scrollbars, just add pad for grayed out vertical bar.
	width += 15;
    }
    var height = 600;
    var maxHeight = screen.availHeight - 40;	// margin
    if (height > maxHeight) {
        height = maxHeight;
    }
    var query            = composeQueryString(arguments);
    var url 		 = "/AA/servlet/ControllerServlet?" + query;
    var windowProperties = "width=" + width
			 + ",height=" + height
			 + ",resizable=1,menubar=0,toolbar=0,statusbar=0,scrollbars=1"
			 + aaGjsDiagPopUpTopLeft;
    var newWindow 	 = window.open(url,'_blank',windowProperties);
//  newWindow.focus(); // bz6384 (consider for AA2)
}

// open passed URL in new windows with default size
function openNewWindowUrl(url, windowName ) {
    // XXX0:20090804rtm: with IE8 it's possible that using "_blank" causes security troubles. Still not fully confirmed.
    openNewWindowUrlWithSpecifiedSize(url, windowName, DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT);
}

// open passed URL in new windows with default size
function openNewWindowUrlWithSpecifiedSize(url, windowName, width, height) {
    var maxHeight = screen.availHeight - 40;	// margin
    if (height > maxHeight) {
        height = maxHeight;
    }
    var windowProperties = "width="   + width
			 + ",height=" + height
			 + ",resizable=1,menubar=0,toolbar=0,statusbar=0,scrollbars=1"
			 + aaGjsDiagPopUpTopLeft;
    var newWindow = window.open(url,windowName,windowProperties);
    newWindow.focus(); // bz6384 (this one specifically for MUL; verified empirically)
}

// open window for CSH (help)
// Start small and offscreen, and RoboHelp resizes/repositions the window
function openCSHWindow(url) {
    var windowProperties = "left="+screen.width+",top="+screen.height+",width=100,height=100,resizable=1,menubar=0,toolbar=0,statusbar=0";
    var newWindow = window.open(url,"AA_CSH_Window",windowProperties);
//  newWindow.focus(); // bz6384 (consider for AA2)
}

// open window for CSH (help) -- bz1464 simplification
function openCSHWindow_bz1464(url) {
    var width  = 780;	// per bz1464
    var height = 520;
    var windowProperties = "left="+(screen.width-width-50)+",top=50,width="+width+",height="+height+",resizable=1,menubar=0,toolbar=0,statusbar=0";
    var newWindow = window.open(url,"AA_CSH_Window",windowProperties);
//  newWindow.focus(); // bz6384 (consider for AA2)
}

// opens the current url on a new window. XXX0000:20071008rtm:CLEANUP:MAIN: no refs in js or java
function openCurrUrlOnNewWindow() {
    var url 		 = window.location;
    var windowProperties = "width=750,height=875,resizable=1,menubar=0,toolbar=0,statusbar=0";
    var newWindow 	 = window.open(url,"_blank",windowProperties);
//  newWindow.focus(); // bz6384 (consider for AA2)
}

// submit a form if enter pressed
function submitIfEnterPressed(myform) {
  // XXX00:20040128iah: IE only?
  if (window.event && window.event.keyCode == 13) {
    myform.submit();
  } else {
    return true;
  }
}

// focus an element if enter pressed
function focusIfEnterPressed(element) {
  // XXX00:20040128iah: IE only?
  if (window.event && window.event.keyCode == 13) {
    element.focus();
  } else {
    return true;
  }
}

// pulldown functionality
// XXX0:20040330iah: not sure where this came from, but it could do with a rework or replacement to clarify the way it works

var pulldownRemember  = new Array();
var pulldownRemember2 = new Array();
var pulldownHideTimeout;

var DHTML = (document.getElementById || document.all || document.layers);

function pulldownShow(name,lvl,obj)
{
	if (!DHTML) return;
	pulldownHide(60000);
	if (pulldownRemember[lvl] && pulldownRemember[lvl] == name) return;
	if (pulldownRemember[lvl])
	{
		pulldownCloseAll(lvl);
	}
	if (name)
	{
		var x =  document.getElementById(name).style;
		x.display = 'block';
	}
	pulldownRemember[lvl] = name;
	if (obj.parentNode) y = obj.parentNode;
	else if (obj.parentElement) y = obj.parentElement;
	else return;
	if (y.className) return;
	y.className = 'over';
	if (pulldownRemember2[lvl]) pulldownRemember2[lvl].className = '';
	pulldownRemember2[lvl] = y;
}

function pulldownCloseAll(lvl)
{
	for (i=pulldownRemember.length - 1;i>=lvl;i--)
	{
		if (pulldownRemember[i]) //IE4 Mac
		{
			var x = document.getElementById(pulldownRemember[i]).style;
			x.display = 'none';
		}
		pulldownRemember[i] = null;
		if (pulldownRemember2[i])
		{
			pulldownRemember2[i].className = '';
			pulldownRemember2[i] = null;
		}
	}
}

// hides the pulldown in delay milliseconds, resetting any previous delays
function pulldownHide(delay)
{
	if (pulldownHideTimeout) clearTimeout(pulldownHideTimeout);
	pulldownHideTimeout = setTimeout('pulldownCloseAll(1)', delay);
}

// A simple utility to enable or disable an element
// disable: a boolean that specifies whether the element should be enabled (true) or disabled (false)
// element: the element to change

function changeEnabledStatus( enable, element ) {
    document.getElementById( element ).disabled = !enable;
}

// prints the time stamp in HH:MM:SS:MS format.
// this function is useful for performance testing, e.g. : checking the gap between server request and client response.
function printTimeStamp() {
    var currentTime = new Date();
    var hours = currentTime.getHours();
    var minutes = currentTime.getMinutes();
    var seconds = currentTime.getSeconds();
    var millis  = currentTime.getMilliseconds();
    if (minutes < 10) {
	minutes = "0" + minutes;
    }
    alert("Time: " + hours + ":" + minutes + ":" + seconds + ":" + millis);
}

// For use in the System Properties page
// Updates the port text box whenever the security checkbox is clicked.
function updatePort() {
    // auto update port if default values used
    if (document.propsForm.secureLoginRequired.checked && document.propsForm.webPort.value == "80") {
	document.propsForm.webPort.value = "443";
    } else if (!document.propsForm.secureLoginRequired.checked && document.propsForm.webPort.value == "443") {
	document.propsForm.webPort.value = "80";
    } else {
	// if using a non-standard value, focus the field as the user will almost certainly need to update it manually
	document.propsForm.webPort.select();
    }
}

// bz1744 - 1093 - ImagePump Parameters

// on button-click pop a 'confirm' window and if confirmed - launch a url

function WidgetButton_confirm( text , url ) {
if ( confirm ( text ) ) {
    window.location = url ;
    }
}

// class for accumulating text
function jsStringBuffer() {
	this.text = new Array();		//array to store the string
	this.write = function (str) { this.text[this.text.length] = str; }
	this.writeln = function (str) { this.text[this.text.length] = str + "\n"; }
	this.toString = function () { return this.text.join(""); }
	this.clear = function () { delete this.text; this.text = null; this.text = new Array; }
}

/*************** Cycle Button *************/

// A cycle button is a button that can be in multiple states.
// A state consists of both appearance (icon and tooltip) and
// function (the javascript action that is executed when the button is pressed).
// When the button is pressed, it executes the function of its current
// state, and then transitions to the next state (i.e. the button's appearance
// will be set up in accordance with the next state).
// When the button is in its last unique state, it
// transitions back to its first state (i.e. it will continually cycle through all
// of its states).
// To use this kind of button,
// 1) Create an instance of a CycleButton
// 2) When defining the button in HTML, set the button's url to be:
//	javascript:<CycleButton instance>.nextState();
// 3) Call setState() to set the initial state of the button

/**
 * buttonImageId - the id of the HTML img tag that appears in the button
 * states - an array of CycleButton states.  Each element in the array should contain the following:
 *     - imageSrc (string): the src string of the image that should be displayed in this state
 *     - hoverSrc (string): the src string of the image that should be displayed in this state when the mouse hovers over the image
 *     - tooltip (string): the tool tip for the button in this state
 *     - func (javascript function name): the name of the function that should execute when the button is pressed
 * The CycleButton will cycle through the states in the same order that they appear in the array.
 */
function CycleButton(buttonImageId, states) {
    this.buttonImageId = buttonImageId;
    this.states = states;
    this.currentState = 0;
    this.setState = cycleButton_setState;
    this.nextState = cycleButton_nextState;
    this.mouseOver = cycleButton_mouseOver;
    this.mouseOut = cycleButton_mouseOut;
}

/**
 * Executes the function defined for the current state
 * and then changes the appearance of the button as per
 * the next state.
 */
function cycleButton_nextState() {
    this.states[this.currentState].func(arguments);

    var newState;
    if (this.currentState == this.states.length - 1) {
	newState = 0;
    } else {
	newState = this.currentState + 1;
    }
    this.setState(newState);
}

/**
 * Sets the current state of the button and
 * changes the appearance of the button as
 * defined by the state.
 */
function cycleButton_setState(newState) {
    this.currentState = newState;

    var img = document.getElementById(this.buttonImageId);
    var data = this.states[newState];
    img.src = data.imageSrc;
    img.alt = data.tooltip;
    img.title = data.tooltip;
}

/**
 * Handles the case in which the mouse hovers over the cycle button
 */
function cycleButton_mouseOver() {
    changeSrc(this.buttonImageId, this.states[this.currentState].hoverSrc);
}

/**
 * Handles the case in which the mouse stops hovering over the cycle button
 */
function cycleButton_mouseOut() {
    changeSrc(this.buttonImageId, this.states[this.currentState].imageSrc);
}

/**
 * Selects all HTML elements which share the same name.
 *  Usage Example:
 * <form name="myform" action="foo.asp" method="post">
 * <input type="checkbox" name="fooOptions" value="1">Java<br>
 * <input type="checkbox" name="fooOptions" value="2">Javascript<br>
 * <input type="checkbox" name="fooOptions" value="3">Active Server Pages<br>
 * <input type="button" onClick="javascript:selectAll(document.myform.fooOptions)">
 */
function selectAll(field) {
    for (i = 0; i < field.length; i++)
	field[i].checked = true ;
}
 
/**
 * Selects all HTML elements which their IDs are given in the list of arguments
 * Usage Example:
 * <form name="myform" action="foo.asp" method="post">
 * <input type="checkbox" name="fooOptions" id="foo1" value="1">Java<br>
 * <input type="checkbox" name="fooOptions" id="foo2" value="2">Javascript<br>
 * <input type="checkbox" name="fooOptions" id="foo3" value="3">Active Server Pages<br>
 * <input type="button" onClick="javascript:selectAllById('foo1', 'foo2', 'foo3')">
*  </form>
*  <h2> Click the button to select all checkboxes</h2>
 */
function selectAllById() {
    for ( i = 0 ; i < arguments.length ; i++) {
	var element = document.getElementById(arguments[i]);
	element.checked = true;
    }
}

/**
 * Changes the src for the specified element
 */
function changeSrc(elementId, newSrc) {
    var element = document.getElementById(elementId);
    if (element != null) {
	element.src = newSrc;
    }
}

/**
 * Replace an element on screen and set specified (form) param true.
 * This is used by WidgetImageWithButtonFormEntryData to do live element removal in a form,
 * as for the custom UI images.
 */
function removeCustomElement(displayId, formEntryId, replacementContent) {
    document.getElementById(displayId).innerHTML=replacementContent;
    document.getElementById(formEntryId).value = 'true';
}

// XXX00:20061128rtm:CLEANUP:MAIN: The following two should use the general function above...
function removeCustomLogo(replacementContent) {
    document.getElementById('customLogoDisplayId').innerHTML=replacementContent;
    document.getElementById('removeCustomLogoId').value = 'true';
}
function removeCustomWelcomeImage(replacementContent) {
    document.getElementById('customWelcomeImageDisplayId').innerHTML=replacementContent;
    document.getElementById('removeCustomWelcomeImageId').value = 'true';
}

/**
 * Sends the browser to the url specified in the value attribute
 * of the element specified by elementId.
 */
function goToUrlInValueAttribute(elementId) {
    var element = document.getElementById(elementId);
    if (element != null) {
	window.location = element.value;
    }
}

// XXX0:20051206jmg: The following functions are only used by the Add/Edit account/user and Preferences pages.
// XXX0:20051206jmg: They should be moved once we have a better mechanism for
// XXX0:20051206jmg: organizing page-specific JavaScript.

// Each of the following arrays contains the ids of checkboxes on the account page
// that must be checked in order for a particular checkbox to be enabled.

var constraintsAllowAddGuests		= new Array("canHaveUserAreas");

var constraintsEnableLightbox		= new Array("canHaveUserAreas");

var constraintsEnableEditProjectNotification = new Array("enableLightbox");

var constraintsAllowAddProjects		= new Array("canHaveUserAreas",
						    "enableLightbox");

var constraintsHasUserArea		= new Array("canHaveUserAreas");

var constraintsLoginAtRoot		= new Array("canHaveUserAreas",
						    "adminOwnFolder");

var constraintsAdminAllowAddProjects	= new Array("canHaveUserAreas",
						    "adminOwnFolder",
						    "enableLightbox",
						    "canCreateLightboxes");

var constraintsAdminAllowAddGuests	= new Array("canHaveUserAreas",
						    "adminOwnFolder",
						    "canCreateGuests");
// XXX00:20070219rtm:CLEANUP: naming should be one-to-one here: "foo", constraintsFoo. "canCreate..." vs. AllowAdd is confusing.
function updateCheckboxes() {
    updateCheckbox("canCreateGuests",		constraintsAllowAddGuests);
    updateCheckbox("enableLightbox",		constraintsEnableLightbox);
    updateCheckbox("canCreateLightboxes",	constraintsAllowAddProjects);
    updateCheckbox("enableEditProjectNotification", constraintsEnableEditProjectNotification);
    updateCheckbox("adminOwnFolder",		constraintsHasUserArea);
    updateCheckbox("adminLoginAtRoot",		constraintsLoginAtRoot);
    updateCheckbox("adminCanCreateLightboxes",	constraintsAdminAllowAddProjects);
    updateCheckbox("adminCanCreateGuests",	constraintsAdminAllowAddGuests);
}

// Each of the following arrays contains the ids of checkboxes on the user page
// that must be checked in order for a particular checkbox to be enabled.
// XXX0:20051206jmg:CLEANUP: The fields on the account and user pages are conceptually the same,
// XXX0:20051206jmg:CLEANUP: so they should use the same names (e.g. either "ownFolder" or "canHaveUserAreas"
// XXX0:20051206jmg:CLEANUP: should be used, but not both).

var constraintsUserLoginAtRoot		= new Array("ownFolder");

var constraintsUserAllowAddProjects	= new Array("ownFolder");

var constraintsUserAllowAddGuests	= new Array("ownFolder");

function updateUserCheckboxes() {
    updateCheckbox("loginAtUserArea",		constraintsUserLoginAtRoot);
    updateCheckbox("canCreateLightboxes",	constraintsUserAllowAddProjects);
    updateCheckbox("canCreateGuests",		constraintsUserAllowAddGuests);
}

// force checkboxId to false unless all of constraints are non-false (includes non-existant)
function updateCheckbox(checkboxId, constraints) {
    var isEnabled = true;
    for (var i = 0; i < constraints.length; i++) {
	var constraint = document.getElementById(constraints[i]);
	if (constraint != null && !constraint.checked && constraint.value != "true") {
	    isEnabled = false;
	    break;
	}
    }
    changeCheckbox(checkboxId, isEnabled);
}

// Enables/disables a checkbox.
// If the checkbox is disabled, the checkbox is typically unchecked.
// checkboxId is the id of a checkbox element
function changeCheckbox(checkboxId, enable) {
    var checkbox = document.getElementById(checkboxId);
    if (checkbox != null) {
	checkbox.disabled = !enable;
	if (!enable) {
	    if (checkboxId == "adminLoginAtRoot" || checkboxId == "loginAtUserArea") {
		checkbox.checked = true;
	    } else {
		checkbox.checked = false;
	    }
	}
    }
}

// Contains the ids of fields that are dependent on whether PDF is enabled
var dependentsEnablePdf = new Array("pdfMaxRes", "colorSpace",  // fields on the account page
				    "pdfMaxResolution",		// fields on the user page  XXX0:20051206jmg:CLEANUP: Rename to be consistent with account page
				    "pdfResolution", "pdfColorSpace");  // fields on the preferences page  XXX0:20051206:CLEANUP: Rename to be consistent

function updatePdfFields() {
    var pdfEnabledField = document.getElementById("enableConversionPdf");  // field on the account and preferences pages
    if (pdfEnabledField == null) {
	pdfEnabledField = document.getElementById("enablePDF");  // field on user page  XXX0:20051206jmg:CLEANUP: Rename to be consistent with account page
    }

    if (pdfEnabledField != null) {
	for (var i = 0; i < dependentsEnablePdf.length; i++) {
	    var field = document.getElementById(dependentsEnablePdf[i]);
	    if (field != null) {
		field.disabled = !pdfEnabledField.checked;
	    }
	}
    }
}

function updateAccountConfig() {
    updateCheckboxes();
    updatePdfFields();
}

function updateUserConfig() {
    updateUserCheckboxes();
    updatePdfFields();
}

// XXX0:20051206jmg: End of Add/Edit account/user and Preferences pages.

//     bz4327 Windows update: KB912945 conflicts with ActiveX Controls
//     Applets need to have their tag inserted in div via javascript to 
//     circumvent Microsoft security patch issues. 
function InsertTextAtDiv(id, text)
{
  var d = document.getElementById(id);
  d.innerHTML = text;
}

// This is only needed by the login page.
function login_openAboutWindow(url) {
    var pageWidth        = 700 ;  // bugid 1699
    var pageHeight       = 400 ;  // bugid 1699
    var windowProperties = "width=" + pageWidth + ",height=" + pageHeight + ",resizable=1,menubar=0,toolbar=0,statusbar=0"; // bugid 1699
    var windowName       = "About" ;
    var newWindow 	 = window.open(url,windowName,windowProperties);
//  newWindow.focus(); // bz6384 (consider for AA2)
}

// XXX:20090821rtm: trim funcs grabbed from Upload.jsp ... could probably be improved
function aaTrim(value) {
    if (value.length < 1) {
	return "";
    }
    value = aaRTrim(value);
    value = aaLTrim(value);
    return value;
}

function aaRTrim(value) {
    var w_space = String.fromCharCode(32);
    var strTemp = "";
    for (var i = value.length-1; i > -1; i--) {
	if (value.charAt(i) != w_space) {
	    strTemp = value.substring(0, i + 1);
	    break;
	}
    }
    return strTemp;
}

function aaLTrim(value) {
    var w_space = String.fromCharCode(32);
    var strTemp = "";
    for (var i = 0; i < value.length; i++) {
	if (value.charAt(i) != w_space) {
	    strTemp = value.substring(i, value.length);
	    break;
	}
    }
    return strTemp;
}

// EOF
