/**
 * A high-level event that abstracts away the details
 * of the browser native events.
 *
 * Not much here right now...
 */
function Event( target ) {
	this.target = target ;
	
	Event.prototype.getTarget = function() {
		return this.target ;
	}
}

/**
 * An abstraction for the browser/navigator that uses
 * the Singleton design pattern (implemented using delegation).
 * 
 * This class provides a high-level event registry that uses
 * the underlying browser native event system and provides
 * a means of using 'real' objects as event listeners.
 */
function Browser() {
	
	if ( this.delegate == null ) {
		this.delegate = new BrowserDelegate() ;
	}
	
	Browser.prototype.supportsDHTML = function() {
		return this.delegate.supportsDHTML() ;
	}
	
	Browser.prototype.getDocument = function() {
		return this.delegate.getDocument() ;
	}	
	
	Browser.prototype.getElementById = function( id ) {
		return document.getElementById( id ) ;
	}
	
	/**
	 * Given a string containing the id of an object
	 * the function returns the stylesheet of that object
	 * or false if it can't find a stylesheet.  Handles
	 * cross-browser compatibility issues.
	 */
	Browser.prototype.getStyleObject = function( objectId ) {
	  // checkW3C DOM, then MSIE 4, then NN 4.
	  //
	  if( document.getElementById && document.getElementById( objectId ) ) {
	        return document.getElementById( objectId ).style ;
	   } else if ( document.all && document.all( objectId ) ) {  
	        return document.all( objectId ).style ;
	   } else if ( document.layers && document.layers[ objectId ] ) { 
	        return document.layers[ objectId ] ;
	   } else {
	        return null ;
	   }
	}	

	/**
	 * Given an eventType, register to listen for the event on the target,
	 * binding the listener object to the eventType/target.
	 */
	Browser.prototype.registerEvent = function( eventType, target, listener ) {
		this.delegate.registerEvent( eventType, target, listener ) ;
	}
	
	/**
	 * This is the delegate to Browser of which there is never 
	 * more than one instance.
	 */
	function BrowserDelegate() {
	
		BrowserDelegate.listeners = [] ;
		
		BrowserDelegate.prototype.supportsDHTML = function() {
			if ( document.getElementById && document.createElement ) {
				return true ;
			} else {
				return false ;
			}
		}	
		
		BrowserDelegate.prototype.getDocument = function() {
			return new Document( document ) ;
		}
			
		// TODO: Move the following methods to an EventRegistry class.
		
		/**
		 * Dispatch a native browser event to an object-based listener.
		 */
		BrowserDelegate.prototype.eventHandler = function( nativeEvent ) {
			var target = null ;
			
			if ( window.event ) {
				// IE6 DOM
				//document.write( 'got event: ie6' ) ;
				// Instead of being an instance of Browser,
				// the variable 'this' is a reference to the
				// HTML element that called this function.
				target = this ;
				//window.alert( target ) ;		
			} else  {
				// W3C DOM
				//document.writeln( 'received event' )  ;
				target = nativeEvent.currentTarget ;			
			}
			var event = new Event( target ) ;
			for ( var i = 0 ; i < BrowserDelegate.listeners.length ; i++ ) {
				var entry = BrowserDelegate.listeners[ i ] ;
				if ( entry[ 0 ] == target ) {
					//document.write( 'found target event' )  ;
					eval( 'entry[ 1 ].' + 'clicked' + '( event )' ) ;
				}
			}
		}
		
		// Map listener to target and add this Browser as a listener
		// to the element event.
		//
		BrowserDelegate.prototype.registerEvent = function( eventType, target, listener ) {
			if ( target.addEventListener ) {
				// W3C Compatible.
				target.addEventListener( eventType, BrowserDelegate.prototype.eventHandler, false ) ;
			} else if ( target.attachEvent ) {
				// IE6+ Compatible.
				// Register event using 'traditional' model.  Only one
				// listener per target is allowed.  We use this model
				// because the handler will be called with 'this' set
				// to 'target'.  This is the only way to get a
				// reference to the element that the handler was
				// set on from within the handler function/method.
				if ( eventType == 'click' ) {				
					target.onclick = BrowserDelegate.prototype.eventHandler ;
				} else if ( eventType == 'change' ) {
					//alert( 'registered change event' ) ;
					target.onchange = BrowserDelegate.prototype.eventHandler ;
				}
			}
			var entry = new Array( 2 ) ;
			entry[ 0 ] = target ;
			entry[ 1 ] = listener ;
			BrowserDelegate.listeners.push( entry ) ;
		}
	}
}
