/**
 * @class Ext.direct.PollingProvider
 *
 * Provides for repetitive polling of the server at distinct {@link #interval intervals}.
 * The initial request for data originates from the client, and then is responded to by the
 * server.
 *
 * All configurations for the PollingProvider should be generated by the server-side
 * API portion of the Ext.Direct stack.
 *
 * An instance of PollingProvider may be created directly via the new keyword or by simply
 * specifying `type = 'polling'`.  For example:
 *
 *     var pollA = Ext.create('Ext.direct.PollingProvider', {
 *         type:'polling',
 *         url: 'php/pollA.php'
 *     });
 *
 *     Ext.direct.Manager.addProvider(pollA);
 *     pollA.disconnect();
 *
 *     Ext.direct.Manager.addProvider({
 *         type:'polling',
 *         url: 'php/pollB.php',
 *         id: 'pollB-provider'
 *     });
 *
 *     var pollB = Ext.direct.Manager.getProvider('pollB-provider');
 */
Ext.define('Ext.direct.PollingProvider', {
    extend: 'Ext.direct.JsonProvider',
    alias: 'direct.pollingprovider',

    uses: ['Ext.direct.ExceptionEvent'],

    requires: ['Ext.Ajax', 'Ext.util.DelayedTask'],

    config: {
        /**
         * @cfg {Number} interval
         * How often to poll the server-side, in milliseconds.
         */
        interval: 3000,

        /**
         * @cfg {Object} baseParams
         * An object containing properties which are to be sent as parameters on every polling request.
         */
        baseParams: null,

        /**
         * @cfg {String/Function} url
         * The url which the PollingProvider should contact with each request. This can also be
         * an imported {@link Ext.Direct} method which will accept the `{@link #baseParams}` as its only argument.
         */
        url: null
    },

    /**
     * @event beforepoll
     * Fired immediately before a poll takes place, an event handler can return `false`
     * in order to cancel the poll.
     * @param {Ext.direct.PollingProvider} this
     */

    /**
     * @event poll
     * This event has not yet been implemented.
     * @param {Ext.direct.PollingProvider} this
     */

    /**
     * @inheritdoc
     */
    isConnected: function() {
        return !!this.pollTask;
    },

    /**
     * Connect to the server-side and begin the polling process. To handle each
     * response subscribe to the `data` event.
     */
    connect: function() {
        var me = this,
            url = me.getUrl(),
            baseParams = me.getBaseParams();

        if (url && !me.pollTask) {
            me.pollTask = setInterval(function() {
                if (me.fireEvent('beforepoll', me) !== false) {
                    if (Ext.isFunction(url)) {
                        url(baseParams);
                    } else {
                        Ext.Ajax.request({
                            url: url,
                            callback: me.onData,
                            scope: me,
                            params: baseParams
                        });
                    }
                }
            }, me.getInterval());
            me.fireEvent('connect', me);
        } else if (!url) {
            //<debug>
            Ext.Error.raise('Error initializing PollingProvider, no url configured.');
            //</debug>
        }
    },

    /**
     * Disconnect from the server-side and stop the polling process. The `disconnect`
     * event will be fired on a successful disconnect.
     */
    disconnect: function() {
        var me = this;

        if (me.pollTask) {
            clearInterval(me.pollTask);
            delete me.pollTask;
            me.fireEvent('disconnect', me);
        }
    },

    // @private
    onData: function(opt, success, response) {
        var me = this,
            i = 0,
            len,
            events;

        if (success) {
            events = me.createEvents(response);
            for (len = events.length; i < len; ++i) {
                me.fireEvent('data', me, events[i]);
            }
        } else {
            me.fireEvent('data', me, Ext.create('Ext.direct.ExceptionEvent', {
                data: null,
                code: Ext.direct.Manager.exceptions.TRANSPORT,
                message: 'Unable to connect to the server.',
                xhr: response
            }));
        }
    }
});