define(['lodash', 'i18n', 'moment', 'ui/component', 'ui/datetime/picker', 'handlebars', 'lib/handlebars/helpers', 'css!ui/dateRange/css/dateRange.css'], function (_, __, moment, component, dateTimePicker, Handlebars, Helpers0, dateRange_css) { 'use strict';

    _ = _ && Object.prototype.hasOwnProperty.call(_, 'default') ? _['default'] : _;
    __ = __ && Object.prototype.hasOwnProperty.call(__, 'default') ? __['default'] : __;
    moment = moment && Object.prototype.hasOwnProperty.call(moment, 'default') ? moment['default'] : moment;
    component = component && Object.prototype.hasOwnProperty.call(component, 'default') ? component['default'] : component;
    dateTimePicker = dateTimePicker && Object.prototype.hasOwnProperty.call(dateTimePicker, 'default') ? dateTimePicker['default'] : dateTimePicker;
    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); data = data || {};
      var buffer = "", stack1, helper, options, functionType="function", escapeExpression=this.escapeExpression, helperMissing=helpers.helperMissing, self=this;

    function program1(depth0,data) {
      
      var buffer = "", stack1;
      buffer += "\n    <button class=\"small btn-info\" data-control=\"filter\" title=\""
        + escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.applyButton)),stack1 == null || stack1 === false ? stack1 : stack1.title)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1))
        + "\">\n        <span class=\"icon icon-"
        + escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.applyButton)),stack1 == null || stack1 === false ? stack1 : stack1.icon)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1))
        + "\"></span> "
        + escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.applyButton)),stack1 == null || stack1 === false ? stack1 : stack1.label)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1))
        + "\n    </button>\n    ";
      return buffer;
      }

    function program3(depth0,data) {
      
      var buffer = "", stack1;
      buffer += "\n    <button class=\"small btn-info btn-secondary\" data-control=\"reset\" title=\""
        + escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.resetButton)),stack1 == null || stack1 === false ? stack1 : stack1.title)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1))
        + "\">\n        <span class=\"icon icon-"
        + escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.resetButton)),stack1 == null || stack1 === false ? stack1 : stack1.icon)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1))
        + "\"></span> "
        + escapeExpression(((stack1 = ((stack1 = (depth0 && depth0.resetButton)),stack1 == null || stack1 === false ? stack1 : stack1.label)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1))
        + "\n    </button>\n    ";
      return buffer;
      }

      buffer += "<div class=\"daterange\">\n    <span class=\"start\">\n        <label for=\"periodStart\">"
        + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "From", options) : helperMissing.call(depth0, "__", "From", options)))
        + "</label>\n    </span>\n    <span class=\"end\">\n        <label for=\"periodEnd\">"
        + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "to", options) : helperMissing.call(depth0, "__", "to", options)))
        + "</label>\n    </span>\n    ";
      stack1 = helpers['if'].call(depth0, ((stack1 = (depth0 && depth0.applyButton)),stack1 == null || stack1 === false ? stack1 : stack1.enable), {hash:{},inverse:self.noop,fn:self.program(1, program1, data),data:data});
      if(stack1 || stack1 === 0) { buffer += stack1; }
      buffer += "\n    ";
      stack1 = helpers['if'].call(depth0, ((stack1 = (depth0 && depth0.resetButton)),stack1 == null || stack1 === false ? stack1 : stack1.enable), {hash:{},inverse:self.noop,fn:self.program(3, program3, data),data:data});
      if(stack1 || stack1 === 0) { buffer += stack1; }
      buffer += "\n</div>\n";
      return buffer;
      });
    function formTpl(data, options, asString) {
      var html = Template(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) 2016-2019 (original work) Open Assessment Technologies SA ;
     *
     */

    /**
     * Default configuration
     * @type {Object}
     */
    var defaults = {
      maxRangeDays: false,
      resetButton: {
        enable: true,
        label: __('Reset'),
        title: __('Reset the range values'),
        icon: 'reset'
      },
      applyButton: {
        enable: true,
        label: __('Apply'),
        title: __('Apply date range'),
        icon: 'filter'
      },
      startPicker: {
        setup: 'datetime',
        format: 'YYYY-MM-DD HH:mm:SS',
        field: {
          name: 'periodStart'
        }
      },
      endPicker: {
        setup: 'datetime',
        format: 'YYYY-MM-DD HH:mm:SS',
        field: {
          name: 'periodEnd'
        }
      }
    };

    /**
     * Setup a datetime picker on an element
     * @param {HTMLElement|jQuery} element - the element to append to the picker to
     * @param {Object} [config] - the picker configuration
     * @returns {Promise<dateTimePicker>} resolves when the picker is "ready"
     */
    var setupDateTimePicker = function setupDateTimePicker(element, config) {
      return new Promise(function (resolve) {
        dateTimePicker(element, config).on('ready', function () {
          resolve(this);
        });
      });
    };

    /**
     * Creates a dates range with date pickers
     *
     * @param {HTMLElement|jQuery} container - where to append the component
     * @param {Object} [config]
     * @param {Object} [config.resetButton]
     * @param {Boolean} [config.resetButton.enable] - enable or not the reset button
     * @param {String} [config.resetButton.label] - the reset button label
     * @param {String} [config.resetButton.title] - the reset button title (HTML title)
     * @param {Boolean} [config.applyButton.enable] - enable or not the apply button
     * @param {String} [config.applyButton.label] - the apply button label
     * @param {String} [config.applyButton.title] - the apply button title (HTML title)
     * @param {Object} [config.startPicker] - the configuration sent to the start picker, see ui/datetime/picker
     * @param {Object} [config.startPicker] - the configuration sent to the end picker ,s see ui/datetime/picker
     * @param {Number} [config.maxRangeDays] - if > 0 limits the max number of days in the range
     * @fires dateRange#ready the picker is ready
     * @fires dateRange#change when any date is changed
     * @fires dateRange#close when a picker is closed
     * @fires dateRange#submit when the submit button is clicked
     */
    function dateRangeFactory(container, config) {
      // if the picker replace fields we don't use the component template
      // NOTE this is used for backward compatibility only...
      var preConfig = _.defaults(config || {}, defaults);
      var useTemplate = preConfig.startPicker && !preConfig.startPicker.replaceField && preConfig.endPicker && !preConfig.endPicker.replaceField;
      /**
       * The date range component
       * @typedef {Object} dateRange
       */
      var dateRange = component({
        /**
         * Gets the start date of the range
         * @returns {String} the start date value
         */
        getStart: function getStart() {
          if (this.is('ready')) {
            return this.startPicker.getValue();
          }
        },
        /**
         * Gets the end date of the range
         * @returns {String} the end date value
         */
        getEnd: function getEnd() {
          if (this.is('ready')) {
            return this.endPicker.getValue();
          }
        },
        /**
         * Reset the values
         * @returns {dateRange} chains
         * @fires dateRange#reset
         */
        reset: function reset() {
          if (this.is('ready')) {
            this.startPicker.updateConstraints('maxDate', null).clear();
            this.endPicker.updateConstraints('minDate', null).clear();

            /**
             * The values get cleared out
             * @event dateRange#reset
             */
            this.trigger('reset');
          }
          return this;
        },
        /**
         * Apply and submit the values
         * @returns {dateRange} chains
         * @fires dateRange#submit
         */
        submit: function submit() {
          if (this.is('ready')) {
            /**
             * The values get submitted
             * @event dateRange#submit
             * @param {String} start - the start/from date
             * @param {String} end - the end/to date
             */
            this.trigger('submit', this.getStart(), this.getEnd());
          }
        }
      }, defaults);
      if (useTemplate) {
        dateRange.setTemplate(formTpl);
      }
      dateRange.on('init', function () {
        if (container) {
          this.render(container);
        }
      }).on('render', function () {
        var self = this;
        var startElement;
        var endElement;
        var element = this.getElement()[0];
        if (useTemplate) {
          this.controls = {
            filter: element.querySelector('[data-control="filter"]'),
            reset: element.querySelector('[data-control="reset"]'),
            start: element.querySelector('.start'),
            end: element.querySelector('.end')
          };
          startElement = this.controls.start;
          endElement = this.controls.end;
        } else {
          startElement = element;
          endElement = element;
        }
        Promise.all([setupDateTimePicker(startElement, this.config.startPicker), setupDateTimePicker(endElement, this.config.endPicker)]).then(function (pickers) {
          self.startPicker = pickers[0];
          self.endPicker = pickers[1];
          self.startPicker.on('change', function (value) {
            if (value && self.endPicker && self.endPicker.is('ready')) {
              self.endPicker.updateConstraints('minDate', value);
              if (self.config.maxRangeDays > 0) {
                self.endPicker.updateConstraints('maxDate', moment(value).add(self.config.maxRangeDays, 'd').toDate());
              }
            }

            /**
             * The values get changed
             * @event dateRange#change
             * @param {String} target - start or end
             * @param {String} value - the changed value
             */
            self.trigger('change', 'start', value);
          }).on('clear', function () {
            if (self.endPicker && self.endPicker.is('ready')) {
              self.endPicker.updateConstraints('minDate', '');
              self.endPicker.updateConstraints('maxDate', '');
            }
          }).on('close', function () {
            /**
             * The picker get closed
             * @event dateRange#close
             * @param {String} target - start or end
             * @param {String} value - the changed value
             */
            self.trigger('close', 'start', this.getValue());
          }).spread('error', self);
          self.endPicker.on('change', function (value) {
            if (value && self.startPicker && self.startPicker.is('ready')) {
              self.startPicker.updateConstraints('maxDate', value);
            }

            /**
             * @see dateRange#change
             */
            self.trigger('change', 'end', value);
          }).on('clear', function () {
            if (self.startPicker && self.startPicker.is('ready')) {
              self.startPicker.updateConstraints('minDate', '');
              self.startPicker.updateConstraints('maxDate', '');
            }
          }).on('close', function () {
            /**
             * @see dateRange#close
             */
            self.trigger('close', 'end', this.getValue());
          }).spread('error', self);
        }).then(function () {
          self.setState('ready', true);

          /**
           * The component is fully ready to get used
           * @event dateRange#ready
           */
          self.trigger('ready');
        }).catch(function (err) {
          self.trigger('error', err);
        });
        if (useTemplate && this.controls.filter) {
          this.controls.filter.addEventListener('click', function (e) {
            e.preventDefault();
            self.submit();
          });
        }
        if (useTemplate && this.controls.reset) {
          this.controls.reset.addEventListener('click', function (e) {
            e.preventDefault();
            self.reset();
          });
        }
      }).on('destroy', function () {
        if (this.startPicker) {
          this.startPicker.destroy();
        }
        if (this.endPicker) {
          this.endPicker.destroy();
        }
      });
      _.defer(function () {
        dateRange.init(config);
      });
      return dateRange;
    }

    return dateRangeFactory;

});
