define(['lodash', 'i18n', 'ui/taskQueue', 'ui/component', 'ui/report', 'handlebars', 'lib/handlebars/helpers'], function (_, __, taskQueue, component, report, Handlebars, Helpers0) { 'use strict';

    _ = _ && Object.prototype.hasOwnProperty.call(_, 'default') ? _['default'] : _;
    __ = __ && Object.prototype.hasOwnProperty.call(__, 'default') ? __['default'] : __;
    taskQueue = taskQueue && Object.prototype.hasOwnProperty.call(taskQueue, 'default') ? taskQueue['default'] : taskQueue;
    component = component && Object.prototype.hasOwnProperty.call(component, 'default') ? component['default'] : component;
    report = report && Object.prototype.hasOwnProperty.call(report, 'default') ? report['default'] : report;
    Handlebars = Handlebars && Object.prototype.hasOwnProperty.call(Handlebars, 'default') ? Handlebars['default'] : Handlebars;
    Helpers0 = Helpers0 && Object.prototype.hasOwnProperty.call(Helpers0, 'default') ? Helpers0['default'] : Helpers0;

    if (!Helpers0.__initialized) {
      Helpers0(Handlebars);
      Helpers0.__initialized = true;
    }
    var Template = Handlebars.template(function (Handlebars,depth0,helpers,partials,data) {
      this.compilerInfo = [4,'>= 1.0.0'];
    helpers = this.merge(helpers, Handlebars.helpers);  


      return "<div class=\"task-queue-status\"></div>";
      });
    function statusTpl(data, options, asString) {
      var html = Template(data, options);
      return (asString || true) ? html : $(html);
    }

    if (!Helpers0.__initialized) {
      Helpers0(Handlebars);
      Helpers0.__initialized = true;
    }
    var Template$1 = Handlebars.template(function (Handlebars,depth0,helpers,partials,data) {
      this.compilerInfo = [4,'>= 1.0.0'];
    helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
      var buffer = "", stack1, helper, helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, functionType="function", self=this;

    function program1(depth0,data) {
      
      var buffer = "", stack1, helper, options;
      buffer += "\n        "
        + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Status of", options) : helperMissing.call(depth0, "__", "Status of", options)))
        + " <span class=\"task-name\">";
      if (helper = helpers.name) { stack1 = helper.call(depth0, {hash:{},data:data}); }
      else { helper = (depth0 && depth0.name); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
      buffer += escapeExpression(stack1)
        + "</span>\n    ";
      return buffer;
      }

    function program3(depth0,data) {
      
      var buffer = "", helper, options;
      buffer += "\n        "
        + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Status", options) : helperMissing.call(depth0, "__", "Status", options)))
        + "\n    ";
      return buffer;
      }

      buffer += "<div class=\"message\">\n    ";
      stack1 = helpers['if'].call(depth0, (depth0 && depth0.name), {hash:{},inverse:self.program(3, program3, data),fn:self.program(1, program1, data),data:data});
      if(stack1 || stack1 === 0) { buffer += stack1; }
      buffer += "\n    : <span class=\"task-status\">";
      if (helper = helpers.status) { stack1 = helper.call(depth0, {hash:{},data:data}); }
      else { helper = (depth0 && depth0.status); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
      buffer += escapeExpression(stack1)
        + "</span>\n</div>";
      return buffer;
      });
    function messageTpl(data, options, asString) {
      var html = Template$1(data, options);
      return (asString || true) ? html : $(html);
    }

    /**
     * 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 _status = {
      loading: __('Loading status'),
      created: __('Not started'),
      running: __('In progress'),
      finished: __('Completed')
    };
    var _defaults = {
      serviceUrl: '',
      taskId: '',
      taskStatus: _status.loading,
      showDetailsButton: true,
      actions: []
    };
    var statusComponent = {
      /**
       * Starts the task status polling
       * @returns {statusComponent}
       */
      start: function start() {
        if (this.taskQueueApi) {
          this.taskQueueApi.pollStatus(this.config.taskId);
        }
        return this;
      },
      /**
       * Stops the task status polling
       * @returns {statusComponent}
       */
      stop: function stop() {
        if (this.taskQueueApi) {
          this.taskQueueApi.pollStop();
        }
        return this;
      }
    };

    /**
     * Create a status checker for task queue
     *
     * @param {Object} config
     * @param {String} config.serviceUrl - the service be called in ajax to check the status of the task
     * @param {String} config.taskId - the id of the task
     * @param {Boolean} [config.showDetailsButton=true] - display the show/hide details toggle
     * @param {Array} [config.actions] - possibility to add more button controls on the report
     * @param {Object} [config.data] - directly set the task data if already available, in this case no polling required
     * @returns {*}
     */
    function taskQueueStatusComponent(config) {
      var taskQueueStatus;
      config = _.defaults(config || {}, _defaults);
      if (_.isEmpty(config.serviceUrl)) {
        throw new TypeError('The task queue status needs to be configured with a service url');
      }

      /**
       * Create a report
       *
       * @param {String} reportType - the top report type
       * @param {String} message - the top report message
       * @param taskReport
       * @returns {Object} a ui/report component
       * @private
       * @see ui/report
       * @fires reportComponent#showDetails
       * @fires reportComponent#hideDetails
       * @fires reportComponent#action
       * @fires reportComponent#action-{custom action name}
       */
      function createReport(reportType, message, taskReport) {
        let innerTaskReport;
        const reportData = {
          type: reportType,
          message: message
        };
        if (_.isPlainObject(taskReport) && taskReport.type && _.isArray(taskReport.children) && taskReport.children.length) {
          // strip the outer generic report that wraps the actual task report
          innerTaskReport = taskReport.children[0]; //there could be only one report by task
          reportData.type = innerTaskReport.type;
          reportData.children = taskReport.children;
        }
        return report({
          replace: true,
          noBorder: true,
          showDetailsButton: config.showDetailsButton,
          actions: config.actions
        }, reportData).on('action', function (actionId) {
          taskQueueStatus.trigger('action-' + actionId);
          taskQueueStatus.trigger('action', actionId);
        }).on('showDetails', function () {
          taskQueueStatus.trigger('showDetails');
        }).on('hideDetails', function () {
          taskQueueStatus.trigger('hideDetails');
        }).render(taskQueueStatus.getElement()).showDetails();
      }

      /**
       * The task queue status component
       * @typedef taskQueueStatus
       * @see ui/component
       * @fires taskQueueStatus#running after every loop
       * @fires taskQueueStatus#finished when the task is complete
       * @fires taskQueueStatus#statechange on each task state change
       */
      taskQueueStatus = component(statusComponent).setTemplate(statusTpl).on('destroy', function () {
        if (this.taskQueueApi) {
          this.taskQueueApi.pollStop();
        }
      }).on('render', function () {
        var self = this;
        if (config.data && config.data.status === 'finished') {
          //since the data is already available, there is no need to poll the status, so we directly display the report
          self.report = createReport(config.data.report.type || 'info', messageTpl({
            name: config.data.label,
            status: _status.finished
          }), config.data.report || {});
        } else {
          //create a temporary report  to display a loading message
          self.report = createReport('info', __('Loading task status ...'));

          //poll the status
          this.taskQueueApi = taskQueue({
            url: {
              status: config.serviceUrl
            }
          }).on('running', function (taskData) {
            if (self.status !== 'running') {
              self.report = createReport('info', messageTpl({
                name: taskData.label,
                status: _status.running
              }));
              self.status = 'running';
              self.trigger('statechange', self.status);
            }
            self.trigger('running', taskData);
          }).on('finished', function (taskData) {
            if (self.status !== 'finished') {
              self.report = createReport(taskData.report.type || 'info', messageTpl({
                name: taskData.label,
                status: _status.finished
              }), taskData.report || {});
              self.status = 'finished';
              self.trigger('finished', taskData);
              self.trigger('statechange', self.status);
            }
          }).on('error', function (err) {
            self.trigger('error', err);
          });
        }
      }).init(config);
      return taskQueueStatus;
    }

    return taskQueueStatusComponent;

});
