/**
 * AkylaObserved
 *
 * Implements the subject class of the Observer pattern.
 * This class is used to inventarize the loaded Observers and incorporates stuff like
 * - Handling a stack of components Observers should empty in case they get created after
 *   a component already asked to be processed
 * - Message passing to loaded Observers. This is especially handy in case of widgets. 
 *   No real use for now, but enough real world uses can be given
 * - Make sure the Observers which are loaded by default (not internally with AJAX) gets
 *   their domLoaded function called.
 * - TODO : make sure that Observers which are loaded on the fly gets a fair treatment like this as well
 *   so they can initialize something which is in the document. Not sure if the Akyla object should handle this.
 */
var Akyla_Prototype_Observed = Class.create(
{
	/**
	 * intializes the subject and registers an js observer for the js dom:loaded event
	 */
	initialize : function()
	{
		this.domReady = false;
		this.observers = new $H({});
		this.componentStack = new $H({});
		Event.observe(document, "dom:loaded" ,this.domLoaded.bind(this));
	},
	/**
	 * Calls domLoaded function on all the Observer which are observing the subject if they have such a function.
	 *
	 * This is used to give the observers a fair chance to initialize the document content after they are loaded
	 * and having one js observer is better than having an js observer for every module.
	 */

	domLoaded : function ()
	{
		this.observers.each(function (pair)
		{
			if (typeof pair.value.domLoaded == "function")
			{
				pair.value.domLoaded();	
			}
		});
		this.domReady = true;
		Event.stopObserving(document, "dom:loaded", this.domLoaded.bind(this));
	},
	/**
	 * Registers an observer with its name. This function gets called by the observers themselves.
	 * Also makes sure to pass the component stack to the Observer if the registering Observer had
	 * componets to be processed.
	 *
	 * @param string name Name of the observer
	 * @param object observer Observer object which wants to observe the subject
	 */
	register : function (name,observer)
	{
		this.observers.set(name,observer);
		if (this.componentStack.get(name) !== null)
		{
			if (observer.processStack(this.componentStack.get(name)))
			{
				this.componentStack.unset(name);
			}
		}
		if (this.domReady)
		{
			observer.domLoaded();
		}
	},
	/**
	 * Unregisters an Observer
	 * @param string name Name of the observer to unregister
	 */
	unregister : function (name)
	{
		this.observers.unset(name);
	},
	/**
	 * Check if the Observer exists
	 * @param string name Name of the observer
	 * @return boolean True if the observer has registered with this Observed, false otherwise
	 */
	hasObserver : function (name)
	{
		return this.observers.get(name) !== null;
	},
	/**
	 * Notifies all the registered Observers with a message and data
	 * @param object message Message to be passed. Should at least contain a message 
	 * and optionally a data of the format { message : "message...", data : object}
	 */
	notify : function (message)
	{
		this.observers.each(function (pair)
		{
			pair.value.update(message);
		});
	}
});

/* Instantiate an Akyla.Observed */
Akyla.Observed = new Akyla_Prototype_Observed();

