function EventUtil() 
{
  this.current=null;
  
  if(typeof EventUtil.__initialized=="undefined")
  {
    EventUtil.prototype.push=function(dispatcher)
    {
      if(dispatcher!=null&&(!(dispatcher instanceof EventDispatcher))) throw new Error("only EventDispatcher may be pushed on event stack");
      var result=this.current;
      this.current=dispatcher; 
      return result; 
    }  
    EventUtil.prototype.addEventListener=function(obj,type,listener,useCapture)
    {  
      if(typeof type!='string') throw new Error("type must contain a string");
      if(typeof listener=='object'&&typeof listener.handleEvent!='function') throw new Error("listener must have a handleEvent method");    
      var tt=type.toLowerCase();
      if(obj.addEventListener)
        obj.addEventListener(tt,listener,useCapture);
      else if(obj.attachEvent)
      {
        if(useCapture) throw new Error("useCapture not supported");
        obj.attachEvent('on'+tt,listener);
      }
    }
    EventUtil.prototype.removeEventListener=function(obj,type,listener,useCapture)
    {  
      if(typeof type!='string') throw new Error("type must contain a string");
      var tt=type.toLowerCase();
      if(obj.removeEventListener)
        obj.removeEventListener(tt,listener,useCapture);
      else if(obj.detachEvent)
      {
        if(useCapture) throw new Error("useCapture not supported");
        obj.detachEvent(tt,listener);
      }
    }
    EventUtil.prototype.dispatchEvent=function(obj,evt)
    {
      if (!evt) var evt=window.event;
      if(obj.dispatchEvent)
        obj.dispatchEvent(evt)
      else if(obj.fireEvent)
      {
        obj.fireEvent('on'+evt.type, evt);
      }
    }
    EventUtil.prototype.stopPropagation=function(evt)
    {
      if(evt.stopPropagation)evt.stopPropagation()
      else evt.cancelBubble=true;
    }
    EventUtil.prototype.preventDefault=function(evt)
    {
      if(evt.preventDefault)evt.preventDefault()
      else evt.returnValue=false;
    }
    EventUtil.prototype.getTarget=function(evt)
    {
      return (evt.srcElement)?evt.srcElement:evt.target;
    }
    EventUtil.__initialized=true;
  }
}
var EventUtil=new EventUtil();

function EventDispatcher(owner,handler)
{
  this.owner=owner;
  this.handler=handler;
  this.suspended=false;
  this.captorCount=0;
  this.captors=null;
  this.listenerCount=0;
  this.listeners=null;
  
  if(typeof EventDispatcher.__initialized=="undefined")
  {
    EventDispatcher.prototype.addListener=function(listener,useCapture)
    {
      if(typeof listener=='object'&&typeof listener.handleEvent!='function') 
        throw new Error("listener must have a handleEvent function");
      if(useCapture)
      {
        if(!this.captors)this.captors=new Array();
        this.captors[this.captorCount++]=listener;
      }
      else
      {
        if(!this.listeners)this.listeners=new Array();
        this.listeners[this.listenerCount++]=listener;
      }
    }
    EventDispatcher.prototype.removeListener=function(listener,useCapture)
    {
      var i;
      if(useCapture)
      {
        if(this.captors)
        {
          for(i=0;i<this.captorCount;++i)
          {      
            if(this.captors[i]==captor) break;      
          }
          if(i<this.captorCount)
          {
            this.captors.splice(i,1);
            this.captorCount--;
          }
        }

      }
      else if(this.listeners)
      {
        for(i=0;i<this.listenerCount;++i)
        {      
          if(this.listeners[i]==listener) break;      
        }
        if(i<this.listenerCount)
        {
          this.listeners.splice(i,1);
          this.listenerCount--;
        }
      }
    }
    EventDispatcher.prototype.suspend=function()
    {
      this.suspended=true;
    }
    EventDispatcher.prototype.resume=function()
    {
      this.suspended=false;
    }
    EventDispatcher.prototype.handleEvent=function(evt)
    {
      function notify(l)
      {
        if(typeof l=='function')
          l(evt);
        else if(typeof l=='string')
          eval(l);
        else if(typeof l=='object')
          l.handleEvent(evt);      
      }
      var stack;
      if(!this.suspended)
      { 
        stack=EventUtil.push(this);
        try
        {
          if(typeof this.handler=='string'&&this.owner[this.handler])
            this.owner[this.handler](evt);
          for(i=this.captorCount-1;i>=0;--i)
            notify(this.captors[i]);
          for(i=0;i<this.listenerCount;++i)
            notify(this.listeners[i]);
        }
        catch (err) 
        { 
          throw err;
        }
        finally
        {
          if(EventUtil.push(stack)!=this)
            throw new Error("Event stack corruption");
        }
      }
    }
    EventDispatcher.prototype.dispatchEvent=EventDispatcher.prototype.handleEvent;    
    
    EventDispatcher.__initialized=true;
  }
}

function EventTarget()
{
  if(typeof EventTarget.__initialized=="undefined")
  {
    EventTarget.prototype.addEventListener=function(type,listener,useCapture)
    {  
      if(typeof type!='string') throw new Error("type must contain a string");
      if(typeof listener=='object'&&typeof listener.handleEvent!='function') throw new Error("listener must have a handleEvent function");    
      var tt=type.toLowerCase();
      if(typeof this[tt]=="undefined") throw new Error("event not supported: "+tt);  
      
      this[tt].addListener(listener,useCapture);
    }
    EventTarget.prototype.removeEventListener=function(type,listener,useCapture)
    {  
      if(typeof type!='string') throw new Error("type must contain a string");
      var tt=type.toLowerCase();  
      if(typeof this[tt]!=undefined)
      {
        this[tt].removeListener(listener,useCapture);
      }
    }
    EventTarget.prototype.dispatchEvent=function(evt)
    {
      if (!evt) var evt=window.event;
      var dispatcher=this['on'+evt.type];
      if(!dispatcher) throw new Error("invalid event");
      dispatcher.dispatchEvent(evt);
    }
    EventTarget.__initialized=true;
  }
}
