/**
 ******************************************************************************
 *
 * Confidential Property of Documentum, Inc.
 * (c) Copyright Documentum, Inc. 2001.
 * All Rights reserved.
 * May not be used without prior written agreement
 * signed by a Documentum corporate officer.
 *
 ******************************************************************************
 *
 * Project        WDK Forms
 * File           events.js
 * Description    WDK Forms Eventing Mechanism
 * Created on     21 May 2001
 * Tab width      3
 *
 ******************************************************************************
 *
 * PVCS Maintained Data
 *
 * Revision       $Revision: 38$
 * Modified on    $Date: 12/4/03 11:58:40 PM$
 *
 * Log at EOF
 *
 ******************************************************************************
 */

// is Netscape, Mac, Mac IE?
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

  /**
   * 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

   /**
    * 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 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_safeCallTimer = setTimeout("dispatchQueuedSafeCalls()", 10);
   }

   /**
    * Dispatch all queued safe calls
    */
   function dispatchQueuedSafeCalls()
   {
      if (isWindowInitialised(window) == false)
      {
         g_safeCallTimer = setTimeout("dispatchQueuedSafeCalls()", 250);
      }
      //shift() doesn't work for mac ie  //dam
      else if (typeof(g_safeCallQueue) != "undefined" && !isMacIE)
      {
         // for each queued call
         while (g_safeCallQueue.length > 0)
         {

            var fnCall = g_safeCallQueue.shift();

            // Build argument string
            var strArgs = "";
            for (var iArg = fnCall.nSkipArgs; iArg < fnCall.args.length; iArg++)
            {
               if (iArg > 1)
               {
                  strArgs += ",";
               }
               strArgs += "fnCall.args[" + iArg + "]";
            }

            // trace
            if (Trace_CLIENTEVENTS)
            {
               events_trace("... calling " + fnCall.fnFunction.toString());
               for (var iArg = fnCall.nSkipArgs; iArg < fnCall.args.length; iArg++)
               {
                  events_trace("... arg " + (iArg - fnCall.nSkipArgs) + ": " + fnCall.args[iArg]);
               }
            }

            // execute call
            if (typeof(fnCall.fnFunction) == "string")
            {
               eval(fnCall.fnFunction + "(" + strArgs + ");");
            }
            else
            {
               eval("fnCall.fnFunction(" + strArgs + ");");
            }
         }
      }
      else if (typeof(g_safeCallQueue) != "undefined")
      {
         // for each queued call
         for (var i = 0; i < g_safeCallQueue.length; i++)
         {
            var fnCall = g_safeCallQueue[i];

            // Build argument string
            var strArgs = "";
            for (var iArg = fnCall.nSkipArgs; iArg < fnCall.args.length; iArg++)
            {
               if (iArg > 1)
               {
                  strArgs += ",";
               }
               strArgs += "fnCall.args[" + iArg + "]";
            }

            // trace
            if (Trace_CLIENTEVENTS)
            {
               events_trace("... calling " + fnCall.fnFunction.toString());
               for (var iArg = fnCall.nSkipArgs; iArg < fnCall.args.length; iArg++)
               {
                  events_trace("... arg " + (iArg - fnCall.nSkipArgs) + ": " + fnCall.args[iArg]);
               }
            }

            // execute call
            if (typeof(fnCall.fnFunction) == "string")
            {
               eval(fnCall.fnFunction + "(" + strArgs + ");");
            }
            else
            {
               eval("fnCall.fnFunction(" + strArgs + ");")
            }
         }

         g_safeCallQueue = [];
      }

   }

   /**
   * 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;
   }

  /**
   * 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


  // Global event posting lock
  var 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)
   {
      // Test and acquire the event posting lock in a single statement
      if (g_serverEventLock++ != 0)
      {
         return;
      }

      if (strFormId == null)
      {
         if ( typeof document.forms != "undefined" &&
               typeof document.forms[0] != "undefined" )
         {
            strFormId = document.forms[0].name;
         }
      }

      // make sure we have found a valid webform to post the event to
      if (strFormId != null)
      {
         if (strHandlerMethod == null || strHandlerMethod == "" || (typeof strHandlerMethod == "undefined"))
         {
            throwError("postFormEvent: strHandlerMethod is a mandatory parameter");
            return;
         }

         // Establish default handler control, if required
         if (strHandlerCtrl == null || strHandlerCtrl == "" || (typeof strHandlerCtrl == "undefined"))
         {
            strHandlerCtrl = strFormId;
         }

         // Retrieve the client-side Form and set event fields
         var formElement = eval("document." + strFormId);
         formElement.__dmfAction.value = strHandlerMethod;
         formElement.__dmfHandler.value = strHandlerCtrl;
         if (typeof(strSrcCtrl) != "undefined" && strSrcCtrl != null && strSrcCtrl != "")
         {
            formElement.__dmfControl.value = escapeUnicodeString(strSrcCtrl);
         }

         // Generate Event Arguments
         var strHandlerArgs = "";
         var EVENTARG_OFFSET = 4;
         var functionArgs = postServerEvent.arguments;
           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)
               {
                  // append argument on URL
                  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 = 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]);

         // Submit the Web Form
         formElement.submit();
      }
   } // postServerEvent

   /**
   * Set keys gobals (used when events are fired)
   *
   * @param Netscape event object, or null
   */
   function setKeys(event)
   {
      getTopLevelWnd().shiftKeyPressed = event.shiftKey;
      getTopLevelWnd().ctrlKeyPressed = event.ctrlKey;
      getTopLevelWnd().altKeyPressed = event.altKey;
      setCurrentEventKeyInfo(event);

      return false;
   }

   function setCurrentEventKeyInfo(event)
   {
      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;
   }


   /**
   * 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


   /**
   * Re-register an Event Handler
   *
   * @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)
   {
      // unregister existing event handler - if it exists
      var strEventKey = this.getEventKey(strSrcFormName, strEventName);

      // overwrite existing event handler with new one
      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;
            break;
         }
      }

   } // 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


   /**
   * 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 (navigator.appName != "Netscape")
      {
         // 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);
         }
      }

      registerClientEventHandler(null, "evalJavaScript", onEvalJavaScript);
   }

} // End If

