/**
 * @class Publicis.Observable
 * @extends Object
 * Basic class for extensions. Implements observables for add listeners and fire events.
 * This calls eneblaes events independen of dom nodes
 * @constructor
 * Creates a new Observable
 * @param {Object} cfg Configuration options
 * @author Alexis Dorn
 */
Publicis.Observable = function (cfg){
	/**
     * @cfg {Object} listeners
     * must have a fn key and a scope key
     */

	/**
	 * Container for the registed Event Listeners
	 * @private
	 * @type Object
	 */
	this.PublicisObservableEvents = {};

	/**
	 * Container for presaved listeners on construction
	 * @private
	 * @type Object
	 */
	this.PublicisObservablePreSavedEvents =  {};

	/**
	 * Memory, is events should be suspended
	 * @private
	 * @type Boolean
	 */
	this.uppressEventsFlag = false;

	this.addPreListeners(cfg);
};

Publicis.extend(Publicis.Observable, Object, {
	//private adds cfg.listeners as listener
	addPreListeners: function (cfg){
		if (cfg && cfg.listeners){
			for (var i in cfg.listeners){
				this.PublicisObservablePreSavedEvents[i] = cfg.listeners[i];
			}
		}
	},
	emptyFn: function (){

	},
	/**
	 * Registers the Events. Must be called AFTER calling this.constructor in subclass constructor (e.g. Publicis.Components.SelectBox.superclass.constructor.call(this, cfg))!!!
	 * <br><br>
	 * Is a protected method, marked as private for not adding to documentation
	 * @param {Object} events
	 */
	registerEvent: function(events){
		for (var i = 0; i < events.length; i++) {
			this.PublicisObservableEvents[events[i]] = [];
		}
		for (i in this.PublicisObservablePreSavedEvents){
			var ev = this.PublicisObservablePreSavedEvents[i];
			var fn  = (typeof ev == "function") ? ev : (ev.fn && typeof ev.fn == "function") ? ev.fn : this.emptyFn;
			var scope  = (ev.scope) ? ev.scope : this;
			this.addListener(i, fn, scope);
		}
	},
	/**
	 * Adds a callback to a event
	 * @param {String} eventname
	 * @param {Function} callback The function that will be called as callback
	 * @param {Object} scope the this scope in callback function
	 */
	addListener: function(eventname, callback, scope){
		if (typeof this.PublicisObservableEvents[eventname] == "undefined") {
			return;
		}
		if (typeof callback != "function") {
			return;
		}

		this.PublicisObservableEvents[eventname].push({
			callback: callback,
			scope: (scope) ? scope : this
		});
	},
	/**
	 * Fires all callbacks, that are added to this eventname (e.g. addListener)
	 * From the second parameter of this method they will be applied to the callback function
	 * Is a protected method, marked as private for not adding to documentation
	 * @param {Object} eventname
	 * @return boolean if only one callback function will return false, this method will return false
	 */
	fireEvent: function(eventname){
		var i = 0, args = [], oCallback, fb = true;
		if (typeof this.PublicisObservableEvents[eventname] == "undefined") {
			return;
		}
		if (this.PublicisObservableEvents[eventname].length < 1) {
			return;
		}
		if (this.suppressEventsFlag){
			return;
		}
		for (i = 1; i < arguments.length; i++){
			args.push(arguments[i]);
		}

		for (i = 0; i < this.PublicisObservableEvents[eventname].length; i++){
			oCallback = this.PublicisObservableEvents[eventname][i];
			if (oCallback.callback.apply(oCallback.scope, args) === false){
				fb = false;
			}
		}
		return fb;
	},
	/**
	 * Disables firing of all Events, until you will call enableEvents again
	 */
	disableEvents: function (){
		this.suppressEventsFlag = true;
	},
	/**
	 * Enables firing of all Events, after you disableEvents has been called
	 */
	enableEvents: function (){
		this.suppressEventsFlag = false;
	},
	/**
	 * @param {Event} ev
	 * @param {Function} listeners
	 */
	removeListener : function( ev, listener ) {

		var index;

		if( this.PublicisObservableEvents[ ev ] == null ) {
			return;
		}

		index = Publicis.indexOf( listener, this.PublicisObservableEvents[ ev ] )

        if( index !== -1 ) {
            this.listeners[ ev ].splice( index, 1 );
        }
	},
	/**
	 * @param {Event} ev
	 * @param {Function} listeners
	 * @param {Object} scope [optional]
	 */
	once : function( ev, listener, scope ) {
		var wrapOnce = function () {
			this.removeListener( ev, wrapOnce );
			listener.apply( scope || this, arguments );
		}.bind( this ) ;

		this.addListener( ev, wrapOnce, scope );
	}

});

// aliased addListener
Publicis.Observable.prototype.on = Publicis.Observable.prototype.addListener;

