function EventListener(func, invoker, params)
{
  this.listenerFunction = func;
  this.invoker = invoker;
  this.params = params;
  
  this.call = function(e)
  {
    this.listenerFunction(e, this.invoker, this.params);
  }
}

function EventMultiHandler()
{
  this.element = null;
  this.previousHandler = null;
  this.listeners = new Array();
  
  this.addListener = function(func, invoker, params)
  {
    return this.listeners.push(new EventListener(func, invoker, params)) - 1;
  }
  
  this.removeListener = function(ID)
  {
    if (ID >= this.listeners.length)
      return;
    
    if (ID == this.listeners.length - 1)
    {
      this.listeners.pop();
    }
    else
    {
      this.listeners[ID] = null;
    }
  }
  
  this.run = function(e)
  {
    for (var i = 0; i < this.listeners.length; i++)
    {
      if (this.listeners[i] != null)
        this.listeners[i].call(e);
    }
    
    if (this.previousHandler != null && this.previousListener != undefined)
      this.previousHandler(e);
  }
}

function MouseAdapter(event)
{
  this.bindEvent = function(event)
  {
    if (!event) event = window.event;
  
    this.event = event;
  }
  
  this.getButton = function(defaultValue)
  {
    if (this.event.button != undefined)
      return this.event.button;
    
    return defaultValue;
  }
  
  this.getScreenX = function(defaultValue)
  {
    if (this.event.sceenX)
      return this.event.screenX;
    
    return defaultValue;
  }
  
  this.getScreenY = function(defaultValue)
  {
    if (this.event.screenY)
      return this.event.screenY;
      
    return defaultValue;
  }
  
  this.getClientX = function(defaultValue)
  {
    if (this.event.clientX)
      return this.event.clientX;
    
    return defaultValue;
  }
  
  this.getClientY = function(defaultValue)
  {
    if (this.event.clientY)
      return this.event.clientY;
    
    return defaultValue;
  }
  
  this.getPageX = function(defaultValue)
  {
    if (this.event.pageX)
      return this.event.pageX;
    
    var x = this.getClientX();
    
    if (x == undefined)
      return defaultValue;
    
    return x + document.body.scrollLeft + document.documentElement.scrollLeft;
  }
  
  this.getPageY = function(defaultValue)
  {
    if (this.event.pageY)
      return this.event.pageY;
    
    var y = this.getClientY();
    
    if (y == undefined)
      return defaultValue;
    
    return y + document.body.scrollTop + document.documentElement.scrollTop;
  }
  
  this.bindEvent(event);
}

function MouseMotionTracker()
{
  this.mouseAdapter = new MouseAdapter();
  
  this.previousX = 0;
  this.previousY = 0;
  this.currentX = 0;
  this.currentY = 0;
  
  this.initialized = false;
  
  this.initialize = function(event)
  {
    this.mouseAdapter.bindEvent(event);
    
    this.currentX = this.mouseAdapter.getPageX(0);
    this.currentY = this.mouseAdapter.getPageY(0);
    this.initialized = true;
  }
  
  this.reset = function()
  {
    this.initialized = false;
  }
  
  this.update = function(event)
  {
    if (!this.initialized)
      this.initialize(event);

    this.mouseAdapter.bindEvent(event);
    
    this.previousX = this.currentX;
    this.previousY = this.currentY;
    
    this.currentX = this.mouseAdapter.getPageX(this.previousX);
    this.currentY = this.mouseAdapter.getPageY(this.previousY);
  }
  
  this.getMotionX = function()
  {
    return this.currentX - this.previousX;
  }
  
  this.getMotionY = function()
  {
    return this.currentY - this.previousY;
  }
}
