/**
 ******************************************************************************
 * (c) Copyright 2001-2008. EMC Corporation.  All Rights Reserved.
 ******************************************************************************
 *
 * Project        WDK Forms
 * File           events.js
 * Description    WDK Forms Eventing Mechanism - requires locate.js
 * Created on     21 May 2001
 * Tab width      3
 *
 ******************************************************************************
 *
 * PVCS Maintained Data
 *
 * Revision       $Revision: 64$
 * Modified on    $Date: 5/19/2008 1:24:03 AM$
 *
 * Log at EOF
 *
 ******************************************************************************
 */

/**
* Private Implementation
*
*/

/**
* Event Handler Constructor
*
* @param  eventKey  event identifier (typically, source form and event name)
* @param  eventHandler  function pointer to event handler
*/
function EventHandler(eventKey, fnEventHandler)
{
   this.m_eventKey = eventKey;
   this.m_fnHandler = fnEventHandler;
} // EventHandler


/**
* Get Event Key
*
* @return  the event key
*/
EventHandler.prototype.getEventKey = function()
{
   return this.m_eventKey;
} // getEventKey


/**
* Get Event Handler
*
* @return   the event handler function pointer
*/
EventHandler.prototype.getHandler = function()
{
   return this.m_fnHandler;
} // getHandler


/**
* Event Handler Registry Constructor
*/
function HandlerRegistry()
{
   this.m_handlers = new Array();
} // HandlerRegistry


/**
* Register an Event Handler
*
* @param  strSrcFormName  the source form name
* @param  strEventName   the event name
* @param  fnEventHandler  the event handler function pointer
*/
HandlerRegistry.prototype.registerEventHandler = function(strSrcFormName, strEventName, fnEventHandler)
{
   var fnExistingHandler = this.getEventHandler(strSrcFormName, strEventName);
   if (fnExistingHandler != null)
   {
      // throw exception if already register
      throwError("An Event handler for form " + strSrcFormName + " and event " + strEventName + " already registered");
      return;
   }
   var fnEventHandler = new EventHandler(this.getEventKey(strSrcFormName, strEventName), fnEventHandler);
   this.m_handlers[this.m_handlers.length] = fnEventHandler;
} // registerEventHandler


/**
* Reregister an Event Handler
* - If no existing event handler is found then it will register one.
*
* @param  strSrcFormName  the source form name
* @param  strEventName   the event name
* @param  fnEventHandler  the event handler function pointer
*/
HandlerRegistry.prototype.reregisterEventHandler = function(strSrcFormName, strEventName, fnEventHandler)
{
   var strEventKey = this.getEventKey(strSrcFormName, strEventName);

   // overwrite existing event handler with new one
   var bIsHandlerAlreadyRegistered = false;
   for (var iHandler = 0; iHandler < this.m_handlers.length; iHandler++)
   {
      var eventHandler = this.m_handlers[iHandler];
      if (eventHandler.getEventKey() == strEventKey)
      {
         var fnEventHandler = new EventHandler(strEventKey, fnEventHandler);
         this.m_handlers[iHandler] = fnEventHandler;
         bIsHandlerAlreadyRegistered = true;
         break;
      }
   }

   if (bIsHandlerAlreadyRegistered == false)
   {
      this.registerEventHandler(strSrcFormName, strEventName, fnEventHandler);
   }

} // reregisterEventHandler


/**
* Get the Event Handler for the specified source Form and Event
*
* @param  strSrcFormName  the source form name
* @param  strEventName   the event name
* @return  the event handler function pointer
*/
HandlerRegistry.prototype.getEventHandler = function(strSrcFormName, strEventName)
{
   // look for specific handler
   var fnEventHandler = null;
   var strEventKey = this.getEventKey(strSrcFormName, strEventName);
   for (var iHandler = 0; iHandler < this.m_handlers.length; iHandler++)
   {
      var eventHandler = this.m_handlers[iHandler];
      if (eventHandler.getEventKey() == strEventKey)
      {
         fnEventHandler = eventHandler.getHandler();
         break;
      }
   }

   // look for generic handler
   if (fnEventHandler == null)
   {
      strEventKey = this.getEventKey(null, strEventName);
      for (var iHandler = 0; iHandler < this.m_handlers.length; iHandler++)
      {
         var eventHandler = this.m_handlers[iHandler];
         if (eventHandler.getEventKey() == strEventKey)
         {
            fnEventHandler = eventHandler.getHandler();
            break;
         }
      }
   }

   return fnEventHandler;
} // getEventHandler


/**
* Get an Event Key for a source Form Name and Event
*
* @param  strSrcFormName  the source form name
* @param  strEventName   the event name
* @return   the event key
*/
HandlerRegistry.prototype.getEventKey = function(strSrcFormName, strEventName)
{
   if (strSrcFormName == null )
   {
      strSrcFormName = "";
   }
   return strSrcFormName + "." + strEventName;
} // getEventKey


/* is Netscape, Mac, IE on Mac? */

/**
 * @deprecated Use ClientInfo JS Object for client side detection
 */
var isNav = (navigator.appName == "Netscape");
var isMac = (navigator.platform.toLowerCase().indexOf("mac")!=-1)
var isMacIE = isMac&&!isNav;

var g_include_event;

if (g_include_event != "true")
{
   /** ensure Trace_CLIENTEVENT is defined */
   if (typeof(Trace_CLIENTEVENTS) == "undefined")
   {
      Trace_CLIENTEVENTS = false;
   }

  /** Indicate that the file has been included */
  g_include_event = "true";

  /** safe call timer variable */
  var g_safeCallTimer = null;

  /**
  * Client-side Event Handling
  *
  */

  /** The Event Handler Registry */
  var g_handlerRegistry = null;

  /** current event key code */
  var g_current_event_keycode = null;

  /** current event name */
  var g_current_event_name = null;


  /**
   * Register an Event Handler
   *
   * @param  strSrcFormName  optional source form name
   * @param  strEventName    the event name
   * @param  fnEventHandler  the event handler function pointer
   */
  function registerClientEventHandler(strSrcFormName, strEventName, fnEventHandler)
  {
     if (g_handlerRegistry == null)
     {
        g_handlerRegistry = new HandlerRegistry();
     }
     g_handlerRegistry.registerEventHandler(strSrcFormName, strEventName, fnEventHandler);

     if (Trace_CLIENTEVENTS) events_trace("registered handler " + fnEventHandler.toString() +
        " for event " + strEventName + " (form " + strSrcFormName + ")");
  } // registerClientEventHandler

  /**
   * Register a Presubmit client Event Handler
   *
   * @param  strSrcFormName  optional source form name
   * @param  strEventName    the event name
   * @param  fnEventHandler  the event handler function pointer
   */
  function registerPreSubmitClientEventHandler(strSrcFormName, strEventName, fnEventHandler)
  {
     registerClientEventHandler(strSrcFormName, strEventName, fnEventHandler);
  } // registerPreSubmitClientEventHandler

  /**
   * Reregister a Presubmit client Event Handler
   *
   * @param  strSrcFormName  optional source form name
   * @param  strEventName    the event name
   * @param  fnEventHandler  the event handler function pointer
   */
  function reregisterPreSubmitClientEventHandler(strSrcFormName, strEventName, fnEventHandler)
  {
     reregisterClientEventHandler(strSrcFormName, strEventName, fnEventHandler);
  }

  /**
   * Reregisters an Event Handler
   *
   * @param  strSrcFormName  optional source form name
   * @param  strEventName    the event name
   * @param  fnEventHandler  the event handler function pointer
   */
  function reregisterClientEventHandler(strSrcFormName, strEventName, fnEventHandler)
  {
     if (g_handlerRegistry == null)
     {
        g_handlerRegistry = new HandlerRegistry();
     }
     g_handlerRegistry.reregisterEventHandler(strSrcFormName, strEventName, fnEventHandler);

     if (Trace_CLIENTEVENTS) events_trace("reregistered handler " + fnEventHandler.toString() +
        " for event " + strEventName + " (form " + strSrcFormName + ")");
  }

  /**
   * Fire an event
   *
   * @param  strEventName  the event to fire
   *
   * Note: Additional parameters may be specified which are then passed onto the
   *       event handler as event parameters
   */
   function fireClientEvent(strEventName)
   {
      if (Trace_CLIENTEVENTS) events_trace("firing event " + strEventName);

      var winWithHandler = findClientEventHandlerDispatchWindow(strEventName);
      if (winWithHandler != null)
      {
         // Locate event handler within window
         var fnEventHandler = winWithHandler.g_handlerRegistry.getEventHandler(this.name, strEventName);
         if (fnEventHandler != null)
         {
            var args = new Array(fireClientEvent.arguments.length);
            for (var i = 0; i < fireClientEvent.arguments.length; i++)
            {
               args[i] = fireClientEvent.arguments[i];
            }

            // Append key press arguments - set by setKeys()
            if (typeof(getTopLevelWnd().shiftKeyPressed) != "undefined" && getTopLevelWnd().shiftKeyPressed)
            {
               args[args.length] = "shiftKeyPressed";
            }

            if (typeof(getTopLevelWnd().ctrlKeyPressed) != "undefined" && getTopLevelWnd().ctrlKeyPressed)
            {
               args[args.length] = "ctrlKeyPressed";
            }

            if (typeof(getTopLevelWnd().altKeyPressed) != "undefined" && getTopLevelWnd().altKeyPressed)
            {
               args[args.length] = "altKeyPressed";
            }

            // execute safe call
            winWithHandler.safeCallEx(fnEventHandler, args, 1);
         }
      }
   } // fireClientEvent

  /**
   * Fire an presubmit client event
   *
   * @param  strEventName  the event to fire
   *
   * Note: Additional parameters may be specified which are then passed onto the
   *       event handler as event parameters
   */
   function firePreSubmitClientEvent(strEventName)
   {
      fireClientEvent(strEventName);
   } // firePreSubmitClientEvent

   /**
    * Tests if a handler for the given client event has been registered.
    *
    * @param strEventName event name
    * @return true if one has been registered
    */
   function isClientEventHandlerRegistered(strEventName)
   {
      if (Trace_CLIENTEVENTS) events_trace("testing for handler for " + strEventName);
      var winWithHandler = findClientEventHandlerDispatchWindow(strEventName);
      return (winWithHandler != null);
   }

   /**
    * Finds a registered event handler for given event.
    *
    * @param strEventName name of event
    * @return window where event handler found or null
    */
   function findClientEventHandlerDispatchWindow(strEventName)
   {
      if (Trace_CLIENTEVENTS) events_trace("getting dispatch window for handler for " + strEventName);

      var winWithHandler = null;
      var winDispatch = this;
      while (winDispatch != null && isDispatchableWindow(winDispatch) == true)
      {
         if (Trace_CLIENTEVENTS) events_trace("... checking window " + winDispatch.location);

         if (winDispatch.g_handlerRegistry != null)
         {
            // Locate event handler within window
            var fnEventHandler = winDispatch.g_handlerRegistry.getEventHandler(this.name, strEventName);
            if (fnEventHandler != null)
            {
               // event handler found - we're done
               winWithHandler = winDispatch;
               if (Trace_CLIENTEVENTS) events_trace("... dispatch window found ");
               break;
            }
         }

         // Find the next available parent (or opener) window
         var winOpener = winDispatch.opener;
         var winParent = (winDispatch == winDispatch.parent) ? null : winDispatch.parent;
         winDispatch = (winOpener == null) ? winParent : winOpener;
      }

      if (Trace_CLIENTEVENTS)
      {
         if (winWithHandler == null) events_trace("... dispatch window cannot be found ");
      }
      return winWithHandler;
   } //findClientEventHandlerDispatchWindow

   /**
    * execute safe call
    *
    * @param fnFunction    Function to call
    * @param ...           Arguments
    */
   function safeCall(fnFunction)
   {
      if(g_current_event_keycode == "32" && g_current_event_name == "keypress")
      {
         return;
      }

      safeCallEx(fnFunction, safeCall.arguments, 1);
   }


   /**
    * execute safe call
    *
    * @param fnFunction    Function to call
    * @param args          Function arguments
    * @param nSkipArgs     Number of args to ignore
    */
   function safeCallEx(fnFunction, args, nSkipArgs)
   {
      // Queue the call and execute it using a timer.  This ensures that the DOM is loaded correctly
      if (typeof(g_safeCallQueue) == "undefined")
      {
         g_safeCallQueue = [];
      }
      g_safeCallQueue[g_safeCallQueue.length] = new SafeCall(fnFunction, args, nSkipArgs);

      if (g_safeCallTimer != null)
      {
         clearTimeout(g_safeCallTimer);
      }

      g_isSafeCallInvoked = true;

      if (isWindowInitialised(window) == false)
      {
         if (Trace_CLIENTEVENTS) events_trace("Postponing dispatchQueuedSafeCalls by 10ms");

         g_safeCallTimer = setTimeout("dispatchQueuedSafeCalls()", 10);
      }
      else
      {
         dispatchQueuedSafeCalls();
      }
   }
   
   var g_isSafeCallInvoked = false;

   function resetIsSafeCallInvoked()
   {
      g_isSafeCallInvoked = false;
   }

   function isSafeCallInvoked()
   {
      return g_isSafeCallInvoked;
   }



   /**
    * Dispatch all queued safe calls
    */
   function dispatchQueuedSafeCalls()
   {
      if (isWindowInitialised(window) == false)
      {
         if (Trace_CLIENTEVENTS) events_trace("Postponing dispatchQueuedSafeCalls by 10ms");
         
         g_safeCallTimer = setTimeout("dispatchQueuedSafeCalls()", 10);
      }
      else if (typeof(g_safeCallQueue) != "undefined")
      {
         // If Mac IE, don't use shift()
         if (g_clientInfo.isPlatform(ClientInfo.MACOS) && g_clientInfo.isBrowser(ClientInfo.MSIE))
         {
            // for each queued call
            for (var i = 0; i < g_safeCallQueue.length; i++)
            {
               var fnCall = g_safeCallQueue[i];
               fnCall.execute();
            }
            g_safeCallQueue = [];
         }
         else
         {
            // for each queued call
            while (g_safeCallQueue.length > 0)
            {
               var fnCall = g_safeCallQueue.shift();
               fnCall.execute();
            }
         }
      }
   }

   /**
   * Safe call constructor
   *
   * @param fnFunction  Function
   * @param arguments   Arguments
   * @param nSkipArgs     Number of args to ignore
   */
   function SafeCall(fnFunction, args, nSkipArgs)
   {
      this.fnFunction = fnFunction;
      this.args = args;
      this.nSkipArgs = nSkipArgs;
      this.execute = function()
      {
         // SAFARI FIX - If current scope for 'this' is not the same as the
         // function's scope, call the function in it's actual scope [ the correct one ]
         if(this != arguments.callee._originalScope)
         {
            if (Trace_CLIENTEVENTS) events_trace("SafeCall has incorrect Scope. Resetting Scope");
            return arguments.callee.apply(arguments.callee._originalScope, arguments);
         }

         // Build argument string
         var strArgs = "";
         for (var iArg = this.nSkipArgs; iArg < this.args.length; iArg++)
         {
            if (iArg > 1)
            {
               strArgs += ",";
            }
            strArgs += "this.args[" + iArg + "]";
         }

         if (Trace_CLIENTEVENTS)
         {
            events_trace("... calling " + this.fnFunction.toString());
            for (var iArg = this.nSkipArgs; iArg < this.args.length; iArg++)
            {
               events_trace("... arg " + (iArg - this.nSkipArgs) + ": " + this.args[iArg]);
            }
         }

         // execute call
         if (typeof(this.fnFunction) == "string")
         {
            eval(this.fnFunction + "(" + strArgs + ");");
         }
         else
         {
            eval("this.fnFunction(" + strArgs + ");");
         }

      }

      // Hold onto reference for correct scope of SafeCall - the one present when SafeCall is created
      // 'this' scope may get lost when SafeCall called via setTimeout()
      this.execute._originalScope = this;
   }

  /**
   * Web Form server-side Event Handling
   *
   */

  var g_arrXId = new Object();
  var g_arrYId = new Object();

  /**
   * Initialise Web Form
   *
   * @param  strId   id of this Form
   */
  function setServerForm(strId, strHiddenXId, strHiddenYId)
  {
     if (strId == null || strId == "" || (typeof strId == "undefined"))
     {
        throwError("setForm: strId is a mandatory parameter");
        return;
     }
     if (strHiddenXId == null || strHiddenXId == "" || (typeof strHiddenXId == "undefined"))
     {
        throwError("setForm: strHiddenXId is a mandatory parameter");
        return;
     }
     if (strHiddenYId == null || strHiddenYId == "" || (typeof strHiddenYId == "undefined"))
     {
        throwError("setForm: strHiddenYId is a mandatory parameter");
        return;
     }

     g_arrXId[strId] = strHiddenXId;
     g_arrYId[strId] = strHiddenYId;

     if (Trace_CLIENTEVENTS) events_trace("setServerForm: id = " + strId);
  } // setServerForm

   // Private : Global event posting lock. Use access methods below
   var g_serverEventLock = 0;

   /**
    * Acquires the event posting lock for the window, which stops other threads from posting server events until it is
    * released.
    *
    * @return - true if the lock was successfully acquired, false if lock could not be acquired (is already acquired by
    * another thread)
    */
   function acquireEventPostingLock()
   {
      if (g_serverEventLock++ != 0)
      {
         return false;
      }
      return true;
   }

   /**
    * Releases the event posting lock for the window, (re)enabling other threads to post server events.
    *
    * NOTE: Since access to the lock is not thread safe due to javascript limitations, other threads can release a
    * lock acquired in a seperate thread.
    */
   function releaseEventPostingLock()
   {
      g_serverEventLock = 0;
   }

   /**
    * Checks if event posting lock is currently held, without attempting to acquire it.
    *
    * @return true, if event posting is currently locked, false if not
    */
   function isEventPostingLocked()
   {
      return (g_serverEventLock > 0);
   }

   /**
    * Post a Server-side Web Form Event
    *
    * @param  strFormId         id of the form to submit. If null, the first form
    *                           on the page is assumed.
    * @param  strSrcCtrl        id of control firing event (optional)
    * @param  strHandlerCtrl    id of control handling the event (default => form)
    * @param  strHandlerMethod  method name of event handler
    * @param  strEventArgName   event argument name
    * @param  strEventArgValue  event argument value
    *
    * Note: Multiple argument names and values may be specified.
    */

   function postServerEvent(strFormId, strSrcCtrl, strHandlerCtrl, strHandlerMethod, strEventArgName, strEventArgValue)
   {
      // Sanity Check
      if (strHandlerMethod == null || strHandlerMethod == "" || (typeof strHandlerMethod == "undefined"))
      {
         throwError("postFormEvent: strHandlerMethod is a mandatory parameter");
         return;
      }

      // Test and acquire the event posting lock in a single statement
      if (acquireEventPostingLock() == false)
      {
         return;
      }

      // Get Form to Post : Either from strFormId if it exists, or look for the first form on the page.
      if (strFormId == null)
      {
         // If form doesn't exist, Safari returns NULL, other browsers return type 'undefined'. This check covers both.
         if (document.forms && document.forms[0])
         {
            strFormId = document.forms[0].name;
         }
      }

      var formElement = null;
      var preSubmitHandler = null;

      if (strFormId != null)
      {
         try
         {
            formElement = eval("document." + strFormId);
            preSubmitHandler = eval(strFormId + "_preSubmitForm");
         }
         catch(e)
         {
            // Ignore. Catches case where eval for preSubmitForm fails when preSubit handler
            // has not yet been rendered on the page, in which case if check below will re-schedule postServerEvent
         }
      }

      var functionArgs = arguments;

      // Ensure form and preSubmitHandler are defined [ done loading ], otherwise wait.
      if (formElement && preSubmitHandler)
      {
         // Establish default handler control, if required
         if (strHandlerCtrl == null || strHandlerCtrl == "" || (typeof strHandlerCtrl == "undefined"))
         {
            strHandlerCtrl = strFormId;
         }

         // Set event fields
         formElement.__dmfAction.value = strFormId + "_" + strHandlerMethod;
         formElement.__dmfHandler.value = strFormId + "_" + strHandlerCtrl;
         if (typeof(strSrcCtrl) != "undefined" && strSrcCtrl != null && strSrcCtrl != "")
         {
            formElement.__dmfControl.value = escapeUnicodeString(strFormId + "_" + strSrcCtrl);
         }
         else
         {
            formElement.__dmfControl.value = "";
         }

         // Generate Event Arguments
         var strHandlerArgs = "";
         var EVENTARG_OFFSET = 4;

         for (var iArg = EVENTARG_OFFSET; iArg < functionArgs.length; iArg+=2)
         {
            var strEventName = functionArgs[iArg];
            if (strEventName != null)
            {
               var strEventValue = functionArgs[iArg+1];
               if (typeof(strEventValue) != "undefined" && strEventValue != null)
               {
                  if (strHandlerArgs != "")
                  {
                     strHandlerArgs += "&";
                  }
                  strHandlerArgs += escapeUnicodeString(strEventName) + "=" + escapeUnicodeString(strEventValue);
               }
            }
         }

         // Append key press arguments - set by setKeys()
         if (typeof(getTopLevelWnd().shiftKeyPressed) != "undefined" && getTopLevelWnd().shiftKeyPressed)
         {
            if (strHandlerArgs != "")
            {
               strHandlerArgs += "&";
            }
            strHandlerArgs += "shiftKeyPressed=true";
         }

         if (typeof(getTopLevelWnd().ctrlKeyPressed) != "undefined" && getTopLevelWnd().ctrlKeyPressed)
         {
            if (strHandlerArgs != "")
            {
               strHandlerArgs += "&";
            }
            strHandlerArgs += "ctrlKeyPressed=true";
         }

         if (typeof(getTopLevelWnd().altKeyPressed) != "undefined" && getTopLevelWnd().altKeyPressed)
         {
            if (strHandlerArgs != "")
            {
               strHandlerArgs += "&";
            }
            strHandlerArgs += "altKeyPressed=true";
         }

         formElement.__dmfHandlerArgs.value = strFormId + "_" + strHandlerArgs;

         if (Trace_CLIENTEVENTS)
         {
            events_trace("posting form event");
            events_trace("... action = " + formElement.__dmfAction.value);
            events_trace("... handler = " + formElement.__dmfHandler.value);
            events_trace("... handlerArgs = " + formElement.__dmfHandlerArgs.value);
            events_trace("... source control = " + formElement.__dmfControl.value);
         }

         // Store the current scroll position
         storeScrollPosition(strFormId, g_arrXId[strFormId], g_arrYId[strFormId]);

         var strControlId = null;
         if ( strSrcCtrl != null )
      	 {
            var elements = document.getElementsByName(strSrcCtrl);
            if ( elements && elements.length > 0 )
            {
               strControlId = elements[0].id;
            }
          }

         // Fire Generic Pre Submit. Handlers can implement presubmit behaviour common to all forms
         firePreSubmitClientEvent(postServerEvent.GENERIC_PRE_SUBMIT);

         // Call the preSubmitHandler for this Web Form
         preSubmitHandler(strFormId, strControlId);

         var popupEnabled = (formElement.__dmfModalPopupEnabled.value == "true");
         var openPopup = popupEnabled && (formElement.__dmfUseModalPopup.value == "true");
         formElement.__dmfUseModalPopup.value = openPopup;
         if (openPopup)
         {
            // encode the nest depth into the popupwindow name
            var depth = formElement.__dmfDepth.value;
            var popupWindowName = getPopupWindowName(window, depth);
            formElement.__dmfTargetWindowName.value = popupWindowName;

            // get the size, construct the URL and open the modal popup window
            var size = formElement.__dmfModalPopupWindowSize.value;
            var strUrl = g_virtualRoot + "/wdk/popupContent.htm";
            openModalPopupWindow(window, strFormId, size, popupWindowName, strUrl);
         }
         else
         {
            // Submit the Web Form
            if (window.getWindowOpener() != null)
            {
               formElement.target = window.name;
            }
            //in case of submitting from modal window, show wait cursor
            if(window.isModalPopup())
            {
               window.document.body.style.cursor = "wait";
            }
            formElement.submit();
         }
      }
      else
      {
         if(Trace_CLIENTEVENTS)
         {
            events_trace("postServerEvent for " + ((strFormId != null) ? strFormId : "forms[0]")
                           + " in window '" + window.name + "', Form not found. Delaying Call by "
                              + postServerEvent.DELAY_PERIOD + "ms");
         }

         if ( postServerEvent.m_delayCount++ < postServerEvent.MAX_DELAY_COUNT )
         {
            // Haven't reached the max delay attempt limit, so try delaying [again]
            var delayed = _postServerEventClosure.apply(this, functionArgs);
            return setTimeout(delayed, postServerEvent.DELAY_PERIOD);
         }
         else
         {
            // If giving up, reset count and free lock.
            g_serverEventLock = 0;
            postServerEvent.m_delayCount = 0;

            if (Trace_CLIENTEVENTS)
            {
               events_trace("postServerEvent for " + ((strFormId != null) ? strFormId : "forms[0]")
                              + " in window '" + window.name + "', ABORTING. Form not found after "
                                 + postServerEvent.MAX_DELAY_COUNT * postServerEvent.DELAY_PERIOD + "ms");
            }
         }
      }
   } // postServerEvent

   /**
    * Post a Server-side Web Form Event
    *
    * @param  strFormId         id of the form to submit. If null, the first form
    *                           on the page is assumed.
    * @param  prefs             inline request preferences object
    * @param  strSrcCtrl        id of control firing event (optional)
    * @param  strHandlerCtrl    id of control handling the event (default => form)
    * @param  strHandlerMethod  method name of event handler
    * @param  strEventArgName   event argument name
    * @param  strEventArgValue  event argument value
    *
    * Note: Multiple argument names and values may be specified.
    */
   function postServerEvent2(strFormId, prefs, strSrcCtrl, strHandlerCtrl, strHandlerMethod, strEventArgName, strEventArgValue)
   {
      if (typeof prefs == "undefined" || prefs == null)
      {
         // Some browsers don't like messing with 'arguments', so make a copy.
         var args = new Array(arguments.length - 1);
         args[0] = arguments[0];
         for (var i = 1; i < arguments.length - 1; i++)
         {
            args[i] = arguments[i+1];
         }
         postServerEvent.apply(this, args);
      }
      else
      {
         postInlineServerEvent.apply(this, arguments);
      }
   }

   // Scoped variables for delay management
   postServerEvent.m_delayCount = 0;
   postServerEvent.MAX_DELAY_COUNT = 600;
   postServerEvent.DELAY_PERIOD = 100; //ms, max delay of MAX_DELAY_COUNT x DELAY_PERIOD before giving up.

   postServerEvent.GENERIC_PRE_SUBMIT = "genericPreSubmit";

   /**
    * Private. Not for public use.
    *
    * Wrapper (Closure) for postServerEvent, to be used when postServerEvent needs to delay itself,
    * using setTimeout/setInterval. Maintains arguments across the delay, without the need to globalize arguments
    * or covert them to/from strings. See {@link postServerEvent}
    */
   function _postServerEventClosure()
   {
      var functionArgs = arguments;
      return function()
      {
         g_serverEventLock = 0;
         postServerEvent.apply(this, functionArgs);
      };
   }

   /**
   * Set keys gobals (used when events are fired)
   *
   * @param Netscape event object, or null
   */
   function setKeys(event)
   {
      if (event != null)
      {
         getTopLevelWnd().shiftKeyPressed = event.shiftKey;
         getTopLevelWnd().ctrlKeyPressed = event.ctrlKey;
         getTopLevelWnd().altKeyPressed = event.altKey;
      }

      setCurrentEventKeyInfo(event);
      return false;
   }

   function setCurrentEventKeyInfo(event)
   {
      if (event != null)
      {
         g_current_event_keycode = event.which;
         if (!event.which)
         {
            g_current_event_keycode = event.keyCode;
         }
         g_current_event_keycode = g_current_event_keycode + "";
         g_current_event_name = event.type;
      }
      else
      {
         g_current_event_keycode = null;
         g_current_event_name = null;
      }
   }

   /**
    * Gets Key Code set by setCurrentEventKeyInfo(event)
    */
   function getCurrentEventKeyCode() {
      return g_current_event_keycode;
   }


   /**
   * Throw an error
   *
   * @param  strErrMsg  the error message
   */
   function throwError(strErrMsg)
   {
      events_trace("Exception: " + strErrMsg);
      alert("events.js: Exception: " + strErrMsg);
   } // throwError


   /**
   * Trace Client Events
   *
   * @param  strErrMsg  the trace message
   */
   function events_trace(strMsg)
   {
      Trace_println("events.js: " + strMsg);
   } // events_trace



   // decimal to hex lookup: decimal number as the index, hex number as the value
   var g_arrDecimalToHex = new Array("0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F");

   /**
   * Escape a unicode string
   *
   * @param  str  the string to escape
   * @return the escaped string
   */
   function escapeUnicodeString(str)
   {
      var strescaped;
      if (g_clientInfo.isBrowser(ClientInfo.NETSCAPE) == false)
      {
         // IE handles unicode correctly
         strescaped = escape(str);
      }
      else
      {
         strescaped = "";
         for(var idxch=0; idxch<str.length; idxch++)
         {
            var ch = str.charCodeAt(idxch);
            var highbyte = ch & 0xFF00;
            if (highbyte == 0)
            {
               var highbit = ch & 0xFF80;
               if (highbit == 0)
               {
                  strescaped += escape(str.substring(idxch, idxch+1));
               }
               else
               {
                  strescaped +="%";
                  for(var idxdigit=0; idxdigit < 2; idxdigit++)
                  {
                     var decimaldigit = (ch >>> (4 - idxdigit * 4)) & 0x0F ;
                     strescaped += g_arrDecimalToHex[decimaldigit];
                  }
               }
            }
            else
            {
               strescaped +="%u";
               for(var idxdigit=0; idxdigit < 4; idxdigit++)
               {
                  var decimaldigit = (ch >>> (12 - idxdigit * 4)) & 0x0F ;
                  strescaped += g_arrDecimalToHex[decimaldigit];
               }
            }
         }
      }

      return strescaped;
   } //escapeUnicodeString(str)

   if (getTopLevelWnd() == this)
   {
      // register generic java-script eval event handler
      function onEvalJavaScript(strScript)
      {
         if (strScript != null)
         {
            eval(strScript);
         }
      }

      function wdkGenericPreSubmit()
      {
         // Currently NOOP for WDK
      }

      registerClientEventHandler(null, "evalJavaScript", onEvalJavaScript);
      registerPreSubmitClientEventHandler(null, postServerEvent.GENERIC_PRE_SUBMIT, wdkGenericPreSubmit);
   }
} // End If

/**
* Post an AJAX event
*
* @param  ajaxURL  to-be-post URL
* @param  async   true/false
*/
function postAJAXEvent(ajaxURL, async)
{
   url = addBrowserIdToURL(ajaxURL);
   var isNative = false;
   var msVers = ["Msxml2.XMLHTTP", "Microsoft.XMLHTTP"];
   var req = null;

   if (typeof window.XMLHttpRequest != 'undefined')
   {
      isNative = true;
      req = new XMLHttpRequest();
   }
   else
   {
      for (var i = 0; i < msVers.length; i++)
      {
         try
         {
            req = new ActiveXObject(msVers[i]);
            break;
         }
         catch(e)
         {
            req = null;
         }
      }
   }

   // async fire and forget (not interested in client return)
   req.open("POST", url, async);
   req.send((isNative) ? "" : null);
}

