///<reference path="../TESCO.js" />
///<reference path="event.js" />
///<reference path="exception.js" />

// manager takes a {1..n} list of event names that must be registered before use
/*
	var myObj = {}
	TESCO.system.event.manager.call(myObj, "hide", "show");
	myObj.addEventListener("hide",
		function() {
			//	
		}
	);

	myObj.dispatchEvent("hide");
*/
TESCO.$("system.event").manager = function() {
    ///	<summary>custom events to allow decoupling of classes</summary>	

    var oEvents = [];

    function register(args) {
        // Register the available events...
        for (var i = 0; i < args.length; i++) {
            oEvents[args[i]] = [];
        }
    }
    
    register(arguments);

    this.addEventListener = function(eventName, functionPointer) {
        var oEvent = oEvents[eventName];
        if (!oEvent) {
            throw new Error("TESCO.system.event.manager.addEventListener: '" + eventName + "' is not a registered event");
        } else {
            oEvent[oEvent.length] = functionPointer;
        }
    }

    this.removeEventListener = function(eventName, functionPointer) {
        var oEvent = oEvents[eventName];
        if (!oEvent) {
            throw new Error("TESCO.system.event.manager.removeEventListener: '" + eventName + "' is not a registered event");
        } else {
            for (var i = 0; i < oEvent.length; i++) {
                if (oEvent[i] === functionPointer) {
                    delete oEvent[i];
                    oEvent.splice(i, 1);
                    break;
                }
            }
        }
    }

    this.dispatchEvent = function(eventName, e, cancelable) {
        var oEvent = oEvents[eventName];
        if (oEvent) {
            if (!e) {
                e = {};
            }
            if (!e.type) {
                e.type = eventName;
            }
            if (!e.timeStamp && e.timeStamp !== 0) {
                e.timeStamp = new Date().getTime();
            }
            if (!e.cancelEvent) {
                e.cancelEvent = false;
            }
            if (!e.cancelBubble) {
                e.cancelBubble = false;
            }
            e.returnValue = true;
            if (!e.target) {
                e.target = this;
            }
            e.canceldisabled = (cancelable ? false : true);
            //	examine length property each iteration as eventlisteners maybe be removed by oEvent[i](e), eg in dialogues
            for (var i = 0; i < oEvent.length && !e.cancelBubble; i++) {
                oEvent[i](e);
            }
        } else {
            throw new Error("TESCO.system.event.manager.dispatchEvent: '" + eventName + "' is not a registered event");
        }

        return e;
    }
}

/*
	Example:
	
	TESCO.system.event.document.addEventListener("beforeload",
		function() {
			//	document.body has begun loading, and can be appended to
		}        
	);
	TESCO.system.event.document.addEventListener("load",
		function() {
			//	document.body has completed loading
		}        
	);
*/
TESCO.system.event.document = new function() {
	///	<summary>static object which dispatches events to track the loaded status of the body</summary>	

	var _document = this;

	TESCO.system.event.manager.call(this, "beforeload", "load");

	//	called directly after opening body tag
	this.beforeload = function() {
		_document.dispatchEvent("beforeload");
	}

	//	called directly before closing body tag
	this.load = function() {
		_document.dispatchEvent("load");
	}
}