"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));

var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));

var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));

var _getPrototypeOf3 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));

var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));

var _react = _interopRequireWildcard(require("react"));

var _propTypes = _interopRequireDefault(require("prop-types"));

var _uiFormField = require("@instructure/ui-form-field");

var _ScreenReaderContent = _interopRequireDefault(require("@instructure/ui-a11y/lib/components/ScreenReaderContent"));

var _uiLayout = require("@instructure/ui-layout");

var _Errors = _interopRequireDefault(require("../../../../common/components/shared/errors/Errors"));

var _quizNumberInput = _interopRequireDefault(require("@instructure/quiz-number-input"));

var _immutable = require("immutable");

var _FormattedDuration = require("../FormattedDuration");

var _formatMessage = _interopRequireDefault(require("@instructure/quiz-i18n/lib/format-message"));

var _default_de_number = Intl.NumberFormat("de", { style: "decimal" }).format;

// This component renders an input for multiple time units, and handles:
// * converting smaller units to larger units when over the unit threshold (e.g. 95 minutes to 1h35m)
// * displaying feedback messages when unit values are over a unit threshold
// * displaying feedback messages when user input is out-of-range
// * displaying error messages when user input is invalid
// * calling onChange with a value which is always valid and in-range
//
// Currently only hours and minutes are supported, but support for other units
// (e.g. seconds or days) could be added in the future if needed
var TimeUnitsInput =
/*#__PURE__*/
function (_Component) {
  (0, _inherits2.default)(TimeUnitsInput, _Component);

  function TimeUnitsInput() {
    var _getPrototypeOf2;

    var _this;

    (0, _classCallCheck2.default)(this, TimeUnitsInput);

    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
      args[_key] = arguments[_key];
    }

    _this = (0, _possibleConstructorReturn2.default)(this, (_getPrototypeOf2 = (0, _getPrototypeOf3.default)(TimeUnitsInput)).call.apply(_getPrototypeOf2, [this].concat(args)));

    _this.isIncrementOrDecrement = function (e) {
      // Is the event an increment or decrement event?
      // These events can be sourced from either the arrow buttons on the input, or the user
      // using the up or down arrows on the keyboard
      var fromButtonInput = e.nativeEvent.target && e.nativeEvent.target.tagName !== 'INPUT';
      var fromArrowKeys = e.key === 'ArrowUp' || e.key === 'ArrowDown';
      return fromButtonInput || fromArrowKeys;
    };

    _this.onChangeTime = function (e, rawString, inputNumber, source) {
      var normalizeOnInput = _this.isIncrementOrDecrement(e) || _this.props.normalizeOnInput;

      var minutes = source === 'minutes' ? inputNumber : _this.state.minutes;
      minutes = normalizeOnInput ? minutes : Math.max(minutes, 0);
      var hours = source === 'hours' ? inputNumber : _this.state.hours;
      var totalSeconds = minutes * _FormattedDuration.MINUTE_IN_SECONDS + hours * _FormattedDuration.HOUR_IN_SECONDS;
      var hoursError = null;

      if (totalSeconds > _this.props.maxTimeInSeconds) {
        var units = (0, _FormattedDuration.getHoursMinutesSeconds)(totalSeconds);
        var newHours = units.hours;
        var newMinutes = units.minutes;
        var maxTime = (0, _FormattedDuration.getHoursMinutesSeconds)(_this.props.maxTimeInSeconds);
        var maxHours = maxTime.hours;
        var maxMinutes = maxTime.minutes;
        hoursError = _default_de_number(newHours) + " hours " + _default_de_number(newMinutes) + " minutes exceeds maximum time of " + _default_de_number(maxHours) + " hours " + _default_de_number(maxMinutes) + " minutes.";
        totalSeconds = _this.props.maxTimeInSeconds;
      } else if (totalSeconds < _this.props.minTimeInSeconds) {
        var _units = (0, _FormattedDuration.getHoursMinutesSeconds)(totalSeconds);

        var _newHours = _units.hours;
        var _newMinutes = _units.minutes;
        var minTime = (0, _FormattedDuration.getHoursMinutesSeconds)(_this.props.minTimeInSeconds);
        var minHours = minTime.hours;
        var minMinutes = minTime.minutes;
        hoursError = _default_de_number(_newHours) + " hours " + _default_de_number(_newMinutes) + " minutes is lower than the minimum time of " + _default_de_number(minHours) + " hours " + _default_de_number(minMinutes) + " minutes.";
        totalSeconds = _this.props.minTimeInSeconds;
      }

      if (normalizeOnInput) {
        _this.setState({
          hours: hours,
          minutes: minutes,
          hoursError: hoursError,
          minutesError: null,
          totalSeconds: totalSeconds
        }, _this.onNormalizeTime);
      } else {
        _this.setState({
          hours: hours,
          rawHoursText: hours,
          minutes: minutes,
          rawMinutesText: minutes,
          hoursError: hoursError,
          minutesError: null,
          totalSeconds: totalSeconds
        });
      }
    };

    _this.onNormalizeTime = function () {
      var units = (0, _FormattedDuration.getHoursMinutesSeconds)(_this.state.totalSeconds);
      var newHours = units.hours;
      var newMinutes = units.minutes;

      _this.setState({
        hours: newHours,
        rawHoursText: newHours,
        minutes: newMinutes,
        rawMinutesText: newMinutes
      });

      _this.props.onChange(_this.state.totalSeconds);
    };

    _this.onChangeExtraMinutes = function (e, rawString, normalizedString) {
      _this.onChangeTimeUnit(e, rawString, normalizedString, 'minutes');
    };

    _this.onChangeExtraHours = function (e, rawString, normalizedString) {
      _this.onChangeTimeUnit(e, rawString, normalizedString, 'hours');
    };

    _this.getErrorList = function () {
      var errorArray = [];
      var _this$state = _this.state,
          hoursError = _this$state.hoursError,
          minutesError = _this$state.minutesError;
      hoursError && errorArray.push(hoursError);
      minutesError && errorArray.push(minutesError);
      return (0, _immutable.List)(errorArray);
    };

    return _this;
  }

  (0, _createClass2.default)(TimeUnitsInput, [{
    key: "componentWillMount",
    value: function componentWillMount() {
      var _getHoursMinutesSecon = (0, _FormattedDuration.getHoursMinutesSeconds)(this.props.timeInSeconds),
          hours = _getHoursMinutesSecon.hours,
          minutes = _getHoursMinutesSecon.minutes;

      this.setState({
        hours: hours,
        minutes: minutes,
        rawHoursText: hours,
        rawMinutesText: minutes,
        totalSeconds: this.props.timeInSeconds,
        errors: (0, _immutable.List)()
      });
    }
  }, {
    key: "onChangeTimeUnit",
    value: function onChangeTimeUnit(e, rawString, normalizedString, unit) {
      // Check that input is a valid number.
      // If not, set an error indicator. If so, remove error indicator.
      var rawStringBlank = rawString === '';
      var inputNumber = normalizedString === null ? NaN : Number(normalizedString);
      var numberInvalid = isNaN(inputNumber);

      if (this.props.normalizeOnInput && rawStringBlank) {
        // When normalizeOnInput is true, treat blank strings as 0,
        // otherwise it's really hard to clear the input and enter a new number
        inputNumber = 0;
        numberInvalid = false;
      }

      if (numberInvalid) {
        var _params;

        if (this.props.normalizeOnInput) {
          this.onNormalizeTime();
          return;
        }

        var unitMessageText = _formatMessage.default.custom(["userInput", "string"], "de", rawString, _params) + " is not a valid number.";
        var update = {};

        if (unit === 'minutes') {
          update.rawMinutesText = rawString;
          update.minutesError = rawStringBlank ? null : unitMessageText;
        } else if (unit === 'hours') {
          update.rawHoursText = rawString;
          update.hoursError = rawStringBlank ? null : unitMessageText;
        }

        this.setState(update);
      } else {
        this.onChangeTime(e, rawString, inputNumber, unit);
      }
    }
  }, {
    key: "render",
    value: function render() {
      return _react.default.createElement(_uiLayout.View, {
        display: "block",
        margin: this.props.margin
      }, _react.default.createElement(_uiFormField.FormFieldGroup, {
        description: _react.default.createElement(_ScreenReaderContent.default, null, this.props.description),
        layout: "columns",
        vAlign: "top",
        startAt: "small"
      }, _react.default.createElement(_quizNumberInput.default, {
        label: this.props.hoursLabel,
        min: 0,
        value: this.state.rawHoursText,
        onChange: this.onChangeExtraHours,
        onBlur: this.onNormalizeTime,
        messages: this.state.hoursError ? [{
          type: 'error'
        }] : null,
        "data-automation": this.props.hoursDataAutomation,
        width: this.props.inputWidth
      }), _react.default.createElement(_quizNumberInput.default, {
        label: this.props.minutesLabel,
        value: this.state.rawMinutesText,
        onChange: this.onChangeExtraMinutes,
        onBlur: this.onNormalizeTime,
        messages: this.state.minutesError ? [{
          type: 'error'
        }] : null,
        "data-automation": this.props.minutesDataAutomation,
        width: this.props.inputWidth
      })), _react.default.createElement(_uiLayout.View, {
        display: "block"
      }, _react.default.createElement(_Errors.default, {
        errorList: this.getErrorList()
      })));
    }
  }]);
  TimeUnitsInput.displayName = "TimeUnitsInput";
  return TimeUnitsInput;
}(_react.Component);

TimeUnitsInput.propTypes = {
  onChange: _propTypes.default.func.isRequired,
  margin: _propTypes.default.string,
  inputWidth: _propTypes.default.string,
  description: _propTypes.default.string.isRequired,
  timeInSeconds: _propTypes.default.number,
  hoursLabel: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.element]).isRequired,
  minutesLabel: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.element]).isRequired,
  hoursDataAutomation: _propTypes.default.string,
  minutesDataAutomation: _propTypes.default.string,
  maxTimeInSeconds: _propTypes.default.number.isRequired,
  minTimeInSeconds: _propTypes.default.number,
  normalizeOnInput: _propTypes.default.bool // Should the number inputs normalize on every input event, instead of waiting for blur event?
  // Note: increment actions (e.g. arrow up) will always normalize immediately
  // Note: onChange will only ever be called after normalization

};
TimeUnitsInput.defaultProps = {
  timeInSeconds: 0,
  minTimeInSeconds: 0,
  normalizeOnInput: false,
  margin: void 0,
  hoursDataAutomation: '',
  minutesDataAutomation: '',
  inputWidth: null
};
var _default = TimeUnitsInput;
exports.default = _default;