/******** CONSTANTS ******************/

/** GLOBAL EVENT TYPE **/
var EVENT_PAGE_LOAD   = "onLoad";
var EVENT_MOUSE_MOVE  = "onMouseMove";
var EVENT_MOUSE_UP    = "onMouseUp";
var EVENT_MOUSE_DOWN  = "onMouseDown";
var EVENT_RESIZE      = "onResize";
var EVENT_SCROLL      = "onScroll";
var EVENT_KEY_PRESS   = "onKeyPress";

/** EVENT MOUSE CLICK **/
var EVENT_CLICK_LEFT  = 0x00000001;
var EVENT_CLICK_MIDDLE= 0x00000002;
var EVENT_CLICK_RIGHT = 0X00000004;

/** EVENT KEY PRESSED **/
var EVENT_KEY_ENTER   = 13;

/******** GLOBAL VARIABLES **********/

/**
 * Hash of Event Type / Event List
 */ 
var goEvents      = new Object();
var goSavedEvents = new Array();

var gbBubble = true;

/*********** STRUCTURES *************/

/**
 * Event structure
 */ 
function EventStr()
{
  this.fnCallback = null;
  this.oContext   = null;
}

/**
 * 
 */
function SavedEventStr()
{
    this.oElement   = null;
    this.sType      = null;
    this.fnCallback = null;
}

/*********** FUNCTIONS *************/

/**
 * List of EventStr (all the list will be associated to an event type)
 */ 
function EventList()
{
  this.oList;
}

function Event_False()
{
    return false;
}

/**
 * Register an event callback
 */ 
function Event_AddAction(_sEventName, _fnCallback, _oContext)
{
  // Try to get the event list
  var oEventList = goEvents[_sEventName];
  
  // Not valid ?
  if((oEventList == TOOLS_UNDEFINED_VALUE)
  || (oEventList == null))
  {
    oEventList        = new EventList();
    oEventList.oList  = new Array();
    goEvents[_sEventName] = oEventList;
  }
  
  // Adds the action to the list if it not already exists
  var bFound = false;
  for(var i=0; !bFound && i<oEventList.oList.length; i++)
  {
    var oEvent = oEventList.oList[i];
    if((oEvent.fnCallback == _fnCallback)
    && (oEvent.oContext == _oContext))
    {
      // The event has already been registered !
      bFound = true;
    }
  }
  
  // Can we add the action to the list ?
  if(!bFound)
  {
    var oEvent = new EventStr();
    oEvent.fnCallback = _fnCallback;
    oEvent.oContext   = _oContext;
    oEventList.oList.push(oEvent);
  }
}

/**
 * Remove a callback
 */ 
function Event_RemoveAction(_sEventName, _fnCallback)
{
  // Try to get the event list
  var oEventList = goEvents[_sEventName];
  
  // valid ?
  if((oEventList != null)
  && (oEventList.oList != null))
  {
    var oNewList = new Array();
    for (var i=0; i<oEventList.oList.length; i++)
    {
      // Gets event
      var oEvent = oEventList.oList[i];
      
      // Valid ?
      if((oEvent != null)
      && (oEvent.fnCallback != _fnCallback))
      {
        // Copy the event to keep
        oNewList.push(oEvent);
      }
    }
    
    // Set new list
    oEventList.oList = oNewList;
  }
}

/**
 * Executes all the callback register for an event
 */
function Event_Execute(_sEventName, _oEvent, _oContext)
{
  // Default return value
  var bRet = true;
    
  // Get the event list associated the the event name
  var oEventList = goEvents[_sEventName];
  
  // Valid ?
  if((oEventList != null)
  && (oEventList.oList != null))
  {
    // Loop on all registered event
    for(var i=0; i<oEventList.oList.length; i++)
    {
      // Gets event
      var oEvent = oEventList.oList[i];
      
      // Valid ?
      if(oEvent != null)
      {
        // Executes it
        var bCb = oEvent.fnCallback(oEvent.oContext, _oEvent, _oContext);
        
        // Undefined return ? set it as true by default
        if(bCb == TOOLS_UNDEFINED_VALUE)
        {
            bCb = true;
        }
        
        bRet = (bRet && bCb);
      }
    }
  }
  
  // Returns global callback bubbling for this event
  return bRet;
}

/********* PRIVATE FUNCTIONS ***************/
function _private_Event_AddEvent(_oElement, _sType, _fCallBack, _bUseCapture)
{
  // Can we use the function ?
  if (_oElement.addEventListener)
  {
    // Add a listener
    _oElement.addEventListener(_sType, _fCallBack, _bUseCapture);
  }
  // Browser compatible with attachEvent ?
  else if (_oElement.attachEvent)
  {
    // Add a listener
    _oElement.attachEvent("on" + _sType, _fCallBack);
  }
}

function _private_Event_RemoveEvent(_oElement, _sType, _fCallBack, _bUseCapture)
{
  // Can we use the function ?
  if (_oElement.removeEventListener)
  {
    // Add a listener
    _oElement.removeEventListener(_sType, _fCallBack, _bUseCapture);
  }
  // Browser compatible with attachEvent ?
  else if (_oElement.detachEvent)
  {
    // Add a listener
    _oElement.detachEvent("on" + _sType, _fCallBack);
  }
}

/**
 * Event on Load
 */
function _private_Event_OnLoad()
{
  // Register new events when the document is loaded
  document.onmouseup   = _private_Event_OnMouseUp;
  document.onmousedown = _private_Event_OnMouseDown;
  document.onmousemove = _private_Event_OnMouseMove;
  _private_Event_AddEvent(document, 'keypress', _private_Event_OnKeyPress);

  // Executes the onLoad Event
  return Event_Execute(EVENT_PAGE_LOAD);
}

/**
 * Event on mouse move
 */
function _private_Event_OnMouseMove(_oEvent)
{
  // Executes the onLoad Event
  Event_Execute(EVENT_MOUSE_MOVE, _oEvent);
  
  return gbBubble;
}

/**
 * Event on Mouse UP
 */
function _private_Event_OnMouseUp(_oEvent)
{
  // Gets event
  if(!_oEvent)
  {
      _oEvent = window.event;
  }
  
  // Select button according to the browser
  if(_oEvent.which)
  {
      // Old netscape model
      
      // Left ?
      if(_oEvent.which == 1)
      {
          Tools_gxMouseB &= ~EVENT_CLICK_LEFT;
      }
      // Middle ?
      else if(_oEvent.which == 2)
      {
          Tools_gxMouseB &= ~EVENT_CLICK_MIDDLE;
      }
      // Right ?
      else if(_oEvent.which == 3)
      {
          Tools_gxMouseB &= ~EVENT_CLICK_RIGHT;
      }
  }
  // W3C model
  else if(_oEvent.button)
  {
      // W3C have set a different assignment on button...
      // The IE definition seems to be more inteligent here(it uses a mask).
      // on W3C, no possibility to have severals state at the same time,
      // no way to have no button pressed value. (left = 0)
      // The Current method allows to save the multiple button state
      // ref : http://www.quirksmode.org/js/events_properties.html
      
      // IE ?
      if(Tools_IsIE4)
      {
          // LEFT = 1, MIDDLE = 4, RIGHT = 2

          // Left ?
          if((_oEvent.button & 1) == 1)
          {
              Tools_gxMouseB &= ~EVENT_CLICK_LEFT;
          }
          // Middle ?
          else if((_oEvent.button & 4) == 4)
          {
              Tools_gxMouseB &= ~EVENT_CLICK_MIDDLE;
          }
          // Right ?
          else if((_oEvent.button & 2) == 2)
          {
              Tools_gxMouseB &= ~EVENT_CLICK_RIGHT;
          }
      }
      else
      {
          // LEFT = 0, MIDDLE = 1, RIGHT = 2

          // Left ?
          if(_oEvent.button == 0)
          {
              Tools_gxMouseB &= ~EVENT_CLICK_LEFT;
          }
          // Middle ?
          else if(_oEvent.button == 1)
          {
              Tools_gxMouseB &= ~EVENT_CLICK_MIDDLE;
          }
          // Right ?
          else if(_oEvent.button == 2)
          {
              Tools_gxMouseB &= ~EVENT_CLICK_RIGHT;
          }
      }
  }

    // Executes the onLoad Event
    return Event_Execute(EVENT_MOUSE_UP, _oEvent);
}

/**
 * Event on Mouse DOWN
 */
function _private_Event_OnMouseDown(_oEvent)
{
  // Gets event
  if(!_oEvent)
  {
      _oEvent = window.event;
  }
  
  // Select button according to the browser
  if(_oEvent.which)
  {
      // Old netscape model
      
      // Left ?
      if(_oEvent.which == 1)
      {
          Tools_gxMouseB |= EVENT_CLICK_LEFT;
      }
      // Middle ?
      else if(_oEvent.which == 2)
      {
          Tools_gxMouseB |= EVENT_CLICK_MIDDLE;
      }
      // Right ?
      else if(_oEvent.which == 3)
      {
          Tools_gxMouseB |= EVENT_CLICK_RIGHT;
      }
  }
  // W3C model
  else if(_oEvent.button)
  {
      // W3C have set a different assignment on button...
      // The IE definition seems to be more inteligent here(it uses a mask).
      // on W3C, no possibility to have severals state at the same time,
      // no way to have no button pressed value. (left = 0)
      // The Current method allows to save the multiple button state
      // ref : http://www.quirksmode.org/js/events_properties.html
      
      // IE ?
      if(Tools_IsIE4)
      {
          // LEFT = 1, MIDDLE = 4, RIGHT = 2

          // Left ?
          if((_oEvent.button & 1) == 1)
          {
              Tools_gxMouseB |= EVENT_CLICK_LEFT;
          }
          // Middle ?
          else if((_oEvent.button & 4) == 4)
          {
              Tools_gxMouseB |= EVENT_CLICK_MIDDLE;
          }
          // Right ?
          else if((_oEvent.button & 2) == 2)
          {
              Tools_gxMouseB |= EVENT_CLICK_RIGHT;
          }
      }
      else
      {
          // LEFT = 0, MIDDLE = 1, RIGHT = 2

          // Left ?
          if(_oEvent.button == 0)
          {
              Tools_gxMouseB |= EVENT_CLICK_LEFT;
          }
          // Middle ?
          else if(_oEvent.button == 1)
          {
              Tools_gxMouseB |= EVENT_CLICK_MIDDLE;
          }
          // Right ?
          else if(_oEvent.button == 2)
          {
              Tools_gxMouseB |= EVENT_CLICK_RIGHT;
          }
      }
  }

  // Executes the onLoad Event
  Event_Execute(EVENT_MOUSE_DOWN, _oEvent);
  
  return gbBubble;
}

function _private_Event_OnResize(_oEvent)
{
  // Executes the onLoad Event
  return Event_Execute(EVENT_RESIZE, _oEvent);
}

function _private_Event_OnScroll(_oEvent)
{
  // Executes the onLoad Event
  return Event_Execute(EVENT_SCROLL, _oEvent);
}

function _private_Event_OnKeyPress(_oEvent)
{
  // Executes the onKeyPress Event
  return Event_Execute(EVENT_KEY_PRESS, _oEvent);
}

_private_Event_AddEvent(window, 'load', _private_Event_OnLoad);
_private_Event_AddEvent(window, 'resize', _private_Event_OnResize);
_private_Event_AddEvent(window, 'scroll', _private_Event_OnScroll);
