/**
 * A special Ext.util.Event subclass that adds support for capture (top-down propagation)
 * listeners, and non-delegated (directly attached to the dom) listeners.
 *
 * An Ext.Element will have one instance of this class per event type that is being listened
 * for.  The ElementEvent instance provides a single point for attaching event listeners
 * and abstracts away important details on the timing and ordering of event firing.
 * Internally this class manages up to 3 separate Ext.util.Event instances.  These represent
 * separate stacks of listeners that may be invoked during different phases of event propagation.
 *
 * - `captures` - tracks listeners that should fire during the "capture" phase of the
 * standard delegated model (listeners attached using capture:true)
 * - `direct` - tracks directly attached listeners, that is listeners that should fire
 * immediately when the event is dispatched to the dom element, before the event bubbles
 * upward and delegated listener processing begins
 * (listeners attached using delegated:false)
 * - `directCaptures` - tracks directly attached capture listeners (only works in IE10+)
 *
 * For more detail on the timing of when these event stacks are dispatched please see
 * Ext.event.publisher.Dom
 *
 * @private
 */
Ext.define('Ext.dom.ElementEvent', {
    extend: 'Ext.util.Event',
 
    addListener: function(fn, scope, options, caller, manager) {
        var me = this,
            added = false,
            name = me.name,
            isDirectEvent = Ext.event.publisher.Dom.instance.directEvents[name],
            captures, directs, directCaptures;
 
        options = options || {};
 
        if (options.delegated === false || isDirectEvent) {
            if (isDirectEvent && options.delegate) {
                options.capture = true;
            }
 
            if (options.capture) {
                directCaptures = me.directCaptures ||
                    (me.directCaptures = new Ext.util.Event(me.observable, name));
                added = directCaptures.addListener(fn, scope, options, caller, manager);
            }
            else {
                directs = me.directs || (me.directs = new Ext.util.Event(me.observable, name));
                added = directs.addListener(fn, scope, options, caller, manager);
            }
        }
        else if (options.capture) {
            captures = me.captures || (me.captures = new Ext.util.Event(me.observable, name));
            added = captures.addListener(fn, scope, options, caller, manager);
        }
        else {
            added = me.callParent([fn, scope, options, caller, manager]);
        }
 
        return added;
    },
 
    removeListener: function(fn, scope) {
        var me = this,
            captures = me.captures,
            directs = me.directs,
            directCaptures = me.directCaptures,
            removed = false,
            index = me.findListener(fn, scope);
 
        if (index !== -1) {
            removed = me.callParent([fn, scope, index]);
        }
        else {
            if (directs) {
                index = directs.findListener(fn, scope);
            }
 
            if (index !== -1) {
                removed = directs.removeListener(fn, scope, index);
            }
            else {
                if (captures) {
                    index = captures.findListener(fn, scope);
                }
 
                if (index !== -1) {
                    removed = captures.removeListener(fn, scope, index);
                }
                else if (directCaptures) {
                    index = directCaptures.findListener(fn, scope);
 
                    if (index !== -1) {
                        removed = directCaptures.removeListener(fn, scope, index);
                    }
                }
            }
        }
 
        return removed;
    },
 
    clearListeners: function() {
        var me = this,
            directCaptures = me.directCaptures,
            directs = me.directs,
            captures = me.captures;
 
        if (directCaptures) {
            directCaptures.clearListeners();
        }
 
        if (directs) {
            directs.clearListeners();
        }
 
        if (captures) {
            captures.clearListeners();
        }
 
        me.callParent();
    },
 
    suspend: function() {
        var me = this,
            directCaptures = me.directCaptures,
            directs = me.directs,
            captures = me.captures;
 
        if (directCaptures) {
            directCaptures.suspend();
        }
 
        if (directs) {
            directs.suspend();
        }
 
        if (captures) {
            captures.suspend();
        }
 
        me.callParent();
    },
 
    resume: function() {
        var me = this,
            directCaptures = me.directCaptures,
            directs = me.directs,
            captures = me.captures;
 
        if (directCaptures) {
            directCaptures.resume();
        }
 
        if (directs) {
            directs.resume();
        }
 
        if (captures) {
            captures.resume();
        }
 
        me.callParent();
    }
 
});