define(['lodash', 'core/eventifier', 'core/dataProvider/request', 'core/polling', 'css!ui/taskQueue/css/taskQueue.css'], function (_, eventifier, request, polling, taskQueue_css) { 'use strict';

    _ = _ && Object.prototype.hasOwnProperty.call(_, 'default') ? _['default'] : _;
    eventifier = eventifier && Object.prototype.hasOwnProperty.call(eventifier, 'default') ? eventifier['default'] : eventifier;
    request = request && Object.prototype.hasOwnProperty.call(request, 'default') ? request['default'] : request;
    polling = polling && Object.prototype.hasOwnProperty.call(polling, 'default') ? polling['default'] : polling;

    /**
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License
     * as published by the Free Software Foundation; under version 2
     * of the License (non-upgradable).
     *
     * This program is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     * GNU General Public License for more details.
     *
     * You should have received a copy of the GNU General Public License
     * along with this program; if not, write to the Free Software
     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
     *
     * Copyright (c) 2017 (original work) Open Assessment Technologies SA ;
     */
    var _defaults = {
      url: {}
    };

    /**
     * Builds a task queue management API
     *
     * @param {Object} config - the API config
     * @param {Object} [config.url] - The list of task queue endpoints
     * @param {String} [config.url.status] - the get status endpoint
     * @param {String} [config.url.remove] - the remove task endpoint
     * @returns {taskQueueApi}
     */
    function taskQueueApi(config) {
      config = _.defaults(config || {}, _defaults);
      const pollingIntervals = [{
        iteration: 10,
        interval: 1000
      }, {
        iteration: 10,
        interval: 10000
      }, {
        iteration: 10,
        interval: 30000
      }, {
        iteration: 0,
        interval: 60000
      }];
      let poll;
      const api = eventifier({
        /**
         * Get the status of a task identified by its unique task id
         *
         * @param {String} taskId - unique task identifier
         * @returns {Promise}
         */
        getStatus: function getStatus(taskId) {
          let status;
          if (!config.url || !config.url.status) {
            throw new TypeError('config.url.status is not configured while getStatus() is being called');
          }
          status = request(config.url.status, {
            taskId: taskId
          }).then(function (taskData) {
            //check taskData
            if (taskData && taskData.status) {
              return Promise.resolve(taskData);
            }
            return Promise.reject(new Error('failed to get task data'));
          });
          status.catch(function (err) {
            api.trigger('error', err);
          });
          return status;
        },
        /**
         * Poll the status of a task
         *
         * @param {String} taskId - unique task identifier
         * @returns {taskQueueApi}
         */
        pollStatus: function pollStatus(taskId) {
          var loop = 0;
          if (!config.url || !config.url.status) {
            throw new TypeError('config.url.status is not configured while getStatus() is being called');
          }

          /**
           * gradually increase the polling interval to ease server load
           * @private
           * @param {Object} pollingInstance - a poll object
           */
          function _updateInterval(pollingInstance) {
            var pollingInterval;
            if (loop) {
              loop--;
            } else {
              pollingInterval = pollingIntervals.shift();
              if (pollingInterval && pollingInterval.iteration && pollingInterval.interval) {
                loop = pollingInterval.iteration;
                pollingInstance.setInterval(pollingInterval.interval);
              }
            }
          }
          api.pollStop();
          poll = polling({
            action: function action() {
              // get into asynchronous mode
              var done = this.async();
              api.getStatus(taskId).then(function (taskData) {
                if (taskData.status === 'finished') {
                  api.trigger('finished', taskData);
                  poll.stop();
                } else {
                  api.trigger('running', taskData);
                  _updateInterval(poll);
                  done.resolve();
                }
              }).catch(function () {
                done.reject();
              });
            }
          });
          _updateInterval(poll);
          poll.start();
          api.trigger('pollStart');
          return api;
        },
        /**
         * Stop the current polling
         *
         * @returns {taskQueueApi}
         */
        pollStop: function pollStop() {
          if (poll) {
            poll.stop();
            api.trigger('pollStop');
          }
          return api;
        },
        /**
         * Remove a task identified by its unique task id
         *
         * @param {String} taskId - unique task identifier
         * @returns {Promise}
         */
        remove: function remove(taskId) {
          let status;
          if (!config.url || !config.url.remove) {
            throw new TypeError('config.url.remove is not configured while remove is being called');
          }
          status = request(config.url.remove, {
            taskId: taskId
          }).then(function (taskData) {
            if (taskData && taskData.status === 'archived') {
              return Promise.resolve(taskData);
            } else {
              return Promise.reject(new Error('removed task status should be archived'));
            }
          });
          status.catch(function (res) {
            api.trigger('error', res);
          });
          return status;
        }
      });
      return api;
    }

    return taskQueueApi;

});
