/**
  * a base type for all events.
  */
function Event(source, type, data) {
	this.type = type;
	this.source = source;
	this.data = data;
	return this;
}

/**
  * an OnLoadEvent that adds type information throgh the 'type' property
  * don't you love variant languages ... @#$@!#$
  */
function InitEvent(source, data) {
	// setup the type hierarchy
	this.inheritFrom = Event;
	// call the superclass constructor
	this.inheritFrom(source, "init", data);

	// return this instance
	return this;
}

/**
  * an OnLoadEvent that adds type information throgh the 'type' property
  * don't you love variant languages ... @#$@!#$
  */
function OnLoadEvent(source, data) {
	// setup the type hierarchy
	this.inheritFrom = Event;
	// call the superclass constructor
	this.inheritFrom(source, "onload", data);

	// return this instance
	return this;
}

function EventSupport() {

	// map of Event.type to List of event handlers
	this._eventMap = new Array();
	
	// add an event of the specified eventType (should match Event.type)
	//
	// this way sendEvent(event) will only be sent to event handlers who have
	// registered with this event type
	//
	this.addEventListener = function(eventType, eventListener) {
		eventListForType = this._eventMap[eventType];
		if (eventListForType == null) {
			eventListForType = new List();
			this._eventMap[eventType] = eventListForType;
		}
		eventListForType.add(eventListener);
	}
	
	// send an event to all listeners that are registered for events of type event.type
	this.sendEvent = function(event) {
		var eventListForType = this._eventMap[event.type];
		if (eventListForType == null) {
			return;
		}
		var i = eventListForType.iterator();
		while (i.hasNext()) {
			var listener = i.next();
			if (typeof listener == "function") {
				listener(event);
			} else {
				listener.onEvent(event);
			}
		}	
	}
	
	return this;	
}

// a simple add only list that supports an iterator
// and getting the items as an array
function List() {
	this._items = new Array();	

	this.size = function () {
		return this._items.length;
	}
	this.add = function(item) {
		this._items[this._items.length] = item;
	}
	this.iterator = function () {
		return new Iterator(this);	
	}
	
	this.getItems = function() {
		return this._items;
	}
	
	return this;
}

// a simple hasNext/next iterator
//
// DO NOT modify the contents of the list while using this !!
//
function Iterator(list) {
	this.index = 0;
	this.list = list;
	
	this.hasNext = function() {
		return (this.index < this.list.size());
	}
	
	this.next = function() {
		return this.list.getItems()[this.index++];
	}
	
	return this;	
}

//
// A page container for supporting dynamic registration of page event listeners
function Page() {
	
	this._loads = new List();
	this._inits = new List();
	
	this.addInitListener = function(eventListener) {
		this._inits.add(eventListener);
	}

	this.addLoadListener = function(funct) {
		this._loads.add(funct);
	}

	this.onload = function() {

		// signal inits
		i = this._inits.iterator();
		while (i.hasNext()) {
			var o = i.next();
			var event = new InitEvent(this);
			if (typeof o == "function") {
				o(event);
			} else {
				o.onEvent(event);
			}
		}
		
		// signal onloads
		i = this._loads.iterator();
		while (i.hasNext()) {
			var o = i.next();
			var event = new OnLoadEvent(this);
			if (typeof o == "function") {
				o(event);
			} else {
				o.onEvent(event);
			}
				
		}

	}
	return this;
}


// make a default instance of page availible
page = new Page();
