/****************************************************************
@name: /htdocs/js/lib/oggetti/EventBroadcaster.js
@desc: Classe helper per il dispatch di eventi tra gli oggetti
@authors: Marco Biondi
@lastauthor: Marco Biondi

INFO:
Classe staticaa che abilita le funzioni di dispatch su un determinato oggetto.

UTILIZZO:
Invocare nel costruttore dell'oggetto EventBroadcaster.initialize(this);
Si ottengono i metodi addListener, delListener e dispatchEvent per
l'istanza specificata.

SINTASSI:
addListener(eventName:String, target:Object)
	Aggancia l'oggetto specificato alla coda di notifica dell'evento
	specificato. Lo scatenarsi dell'evento richiama il metodo "handleEvent"
	o eventName dell'oggetto indicato con un parametro (l'oggetto evento).

delListener(eventName:String, target:Object)
	Rimuove l'oggetto specificato dalla coda dell'evento specificato.

dispatchEvent(objEvt:Object)
	Scatena l'evento descritto da objEvt.
	objEvt ha due campi OBBLIGATORI:
	type : nome dell'evento
	target : un riferimento a chi ha scatenato l'evento (la funzione aggiunge this di default se non specificato)

	Altri eventuali campi significativi per l'evento dipendono
	dall'oggetto che lo lancia e dal tipo di evento.

HISTORY:
	28/03/2007 - Aggiustata gestione errori durante il dispatch
	10/03/2006 - Fissato problema di compatibilità con Prototype 1.4.0
	27/06/2006 - Aggiunta gestione inserimento/cancellazione listener durante un dispatch: le variazioni hanno effetto alla fine del dispatch.
*****************************************************************/

var EventBroadcaster =  {
	initialize: function(obj) {
		obj.addListener = EventBroadcaster.addListener;
		obj.delListener = EventBroadcaster.delListener;
		obj.dispatchEvent = EventBroadcaster.dispatchEvent;
		obj.__evtq__ = new Object();
	},

	addListener: function(eventName, target) {
		if(!this.__evtq__[eventName])
		{
			this.__evtq__[eventName] = {r: false, a: [], d: []};
		}

		if(!this.__evtq__[eventName].r)
		{
			this.delListener(eventName, target);
			this.__evtq__[eventName].a.push(target);
		}
		else
		{
			this.__evtq__[eventName].d.push({a: 'a', n: eventName, t: target});
		}
	},

	delListener: function(eventName, target) {
		if(this.__evtq__[eventName])
		{
			if(!this.__evtq__[eventName].r)
			{
				var i,len;
				len = this.__evtq__[eventName].a.length;
				for(i = 0; i < len; i++)
				{
					if(this.__evtq__[eventName].a[i] == target)
					{
						this.__evtq__[eventName].a.splice(i,1);
						return;
					}
				}
			}
			else
			{
				this.__evtq__[eventName].d.push({a: 'd', n: eventName, t: target});
			}
		}
	},

	dispatchEvent: function(objEvt) {
		if(!objEvt.target)
			objEvt.target = this;
		var q = this.__evtq__[objEvt.type];
		if(q)
		{
			try
			{
				q.r = true;
				var i,t,k;
				k = q.a.length;
				for(i=0; i<k; i++)
				{
					t = q.a[i];
					if(typeof(t) == "object")
					{
						if(t.handleEvent)
							t.handleEvent(objEvt);
						else if(t[objEvt.type])
							t[objEvt.type](objEvt);
					}
					else
					{
						t.apply(this, [objEvt]);
					}
				}
			}
			catch(err)
			{
				throw(err);
			}
			finally
			{
				q.r = false;

				while(q.d.length)
				{
					var i = q.d.pop();
					if(i.a == 'd')
					{
						this.delListener(i.n, i.t);
					}
					else
					{
						this.addListener(i.n, i.t);
					}
				}
			}
		}
	}
}