/**
 * @private
 */
Ext.define('Ext.event.publisher.ComponentSize', {

    extend: 'Ext.event.publisher.Publisher',

    requires: [
        'Ext.ComponentManager',
        'Ext.util.SizeMonitor'
    ],

    targetType: 'component',

    handledEvents: ['resize'],

    constructor: function() {
        this.callParent(arguments);

        this.sizeMonitors = {};
    },

    subscribe: function(target) {
        var match = target.match(this.idSelectorRegex),
            subscribers = this.subscribers,
            sizeMonitors = this.sizeMonitors,
            dispatcher = this.dispatcher,
            targetType = this.targetType,
            component;

        if (!match) {
            return false;
        }

        if (!subscribers.hasOwnProperty(target)) {
            subscribers[target] = 0;

            dispatcher.addListener(targetType, target, 'painted', 'onComponentPainted', this, null, 'before');

            component = Ext.ComponentManager.get(match[1]);

            //<debug error>
            if (!component) {
                Ext.Logger.error("Adding a listener to the 'resize' event of a non-existing component");
            }
            //</debug>

            sizeMonitors[target] = new Ext.util.SizeMonitor({
                element: component.element,
                callback: this.onComponentSizeChange,
                scope: this,
                args: [this, target]
            });
        }

        subscribers[target]++;
        return true;
    },

    unsubscribe: function(target, eventName, all) {
        var match = target.match(this.idSelectorRegex),
            subscribers = this.subscribers,
            dispatcher = this.dispatcher,
            targetType = this.targetType,
            sizeMonitors = this.sizeMonitors;

        if (!match) {
            return false;
        }

        if (!subscribers.hasOwnProperty(target) || (!all && --subscribers[target] > 0)) {
            return true;
        }

        sizeMonitors[target].destroy();
        delete sizeMonitors[target];

        dispatcher.removeListener(targetType, target, 'painted', 'onComponentPainted', this, 'before');

        delete subscribers[target];
        return true;
    },

    onComponentPainted: function(component) {
        var observableId = component.getObservableId(),
            sizeMonitor = this.sizeMonitors[observableId];

        sizeMonitor.refresh();
    },

    onComponentSizeChange: function(component, observableId) {
        this.dispatcher.doDispatchEvent(this.targetType, observableId, 'resize', [component]);
    }
});