"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
Object.defineProperty(exports, "TimePickerBase", {
  enumerable: true,
  get: function get() {
    return _TimePickerBase["default"];
  }
});
exports.timeToLocaleString = exports.TimePickerDecorator = exports.TimePicker = exports["default"] = void 0;

var _Pure = _interopRequireDefault(require("@enact/ui/internal/Pure"));

var _DateFactory = _interopRequireDefault(require("ilib/lib/DateFactory"));

var _DateFmt = _interopRequireDefault(require("ilib/lib/DateFmt"));

var _LocaleInfo = _interopRequireDefault(require("ilib/lib/LocaleInfo"));

var _compose = _interopRequireDefault(require("ramda/src/compose"));

var _DateTime = require("../internal/DateTime");

var _Skinnable = _interopRequireDefault(require("../Skinnable"));

var _TimePickerBase = _interopRequireDefault(require("./TimePickerBase"));

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }

/**
 * Provides an Agate-themed time selection component.
 *
 * @example
 * <TimePicker value={new Date()} />
 *
 * @module agate/TimePicker
 * @exports TimePicker
 * @exports TimePickerBase
 * @exports TimePickerDecorator
 * @exports timeToLocaleString
 */

/*
 * Converts a string representation of time into minutes
 *
 * @param	{String}	time	Time in the format `HH:mm`
 *
 * @returns	{Number}			Time in minute
 * @private
 */
var toMinutes = function toMinutes(time) {
  var colon = time.indexOf(':');
  var hour = parseInt(time.substring(0, colon));
  var minute = parseInt(time.substring(colon + 1));
  return hour * 60 + minute;
};
/*
 * Converts the `start` and `end` string representations (e.g. '12:00') into a numerical
 * representation.
 *
 * @param	{Object}	options			Time options
 * @param	{String}	options.start	Start time of meridiem
 * @param	{String}	options.end		End time of meridiem
 *
 * @returns	{Object}					Contains start and end time in minutes
 * @private
 */


var calcMeridiemRange = function calcMeridiemRange(_ref) {
  var start = _ref.start,
      end = _ref.end;
  return {
    start: toMinutes(start),
    end: toMinutes(end)
  };
};
/*
 * Finds the index of the meridiem which contains `time`
 *
 * @param	{Number}	time		Time in minutes
 * @param	{Object[]}	meridiems	Array of meridiems with `start` and `end` members in minutes
 *
 * @returns {Number}				Index of `time` in `meridiems`
 * @private
 */


var indexOfMeridiem = function indexOfMeridiem(time, meridiems) {
  var minutes = time.getHours() * 60 + time.getMinutes();

  for (var i = 0; i < meridiems.length; i++) {
    var m = meridiems[i];

    if (minutes >= m.start && minutes <= m.end) {
      return i;
    }
  }

  return -1;
};

var getLabelFormatter = function getLabelFormatter() {
  return new _DateFmt["default"]({
    type: 'time',
    useNative: false,
    timezone: 'local',
    length: 'full',
    date: 'dmwy'
  });
};

var dateTimeConfig = {
  customProps: function customProps(i18n, value) {
    var values = {
      // i18n props
      meridiems: i18n.meridiemLabels,
      // date components
      hour: 12,
      minute: 0,
      meridiem: 0
    };

    if (value) {
      if (i18n.meridiemEnabled) {
        values.meridiem = indexOfMeridiem(value, i18n.meridiemRanges);
      }

      values.hour = value.getHours();
      values.minute = value.getMinutes();
    }

    return values;
  },
  defaultOrder: ['h', 'm', 'a'],
  handlers: {
    onHourChange: function onHourChange(ev, value) {
      var currentTime = (0, _DateFactory["default"])(value).getTimeExtended();
      var currentHour = value.hour;
      value.hour = ev.value; // In the case of navigating onto the skipped hour of DST, ilib will return the same
      // value so we skip that hour and update the value again.

      var newTime = (0, _DateFactory["default"])(value).getTimeExtended();

      if (newTime === currentTime) {
        value.hour = ev.value * 2 - currentHour;
      }

      return value;
    },
    onMinuteChange: function onMinuteChange(ev, value) {
      value.minute = ev.value;
      return value;
    },
    onMeridiemChange: function onMeridiemChange(ev, value, i18n) {
      var meridiemRanges = i18n.meridiemRanges;
      var meridiem = meridiemRanges[ev.value];

      if (meridiemRanges.length === 2) {
        // In the common case of 2 meridiems, we'll offset hours by 12 so that picker stays
        // the same.
        value.hour = (value.getHours() + 12) % 24;
      } else {
        // In the rarer case of > 2 meridiems (e.g. am-ET), try to set hours only first
        var hours = Math.floor(meridiem.start / 60);
        value.hour = hours; // but check if it is still out of bounds and update the minutes as well

        var minutes = hours * 60 + value.getMinutes();

        if (minutes > meridiem.end) {
          value.minute = meridiem.end % 60;
        } else if (minutes < meridiem.start) {
          value.minute = meridiem.start % 60;
        }
      }

      return value;
    }
  },
  i18n: function i18n() {
    // Filters used to extract the order of pickers from the ilib template
    var includeMeridiem = /([khma])(?!\1)/ig;
    var excludeMeridiem = /([khm])(?!\1)/ig; // Meridiem localization

    var merFormatter = new _DateFmt["default"]({
      template: 'a',
      useNative: false,
      timezone: 'local'
    });
    var meridiems = merFormatter.getMeridiemsRange();
    var meridiemRanges = meridiems.map(calcMeridiemRange);
    var meridiemLabels = meridiems.map(function (obj) {
      return obj.name;
    }); // Picker ordering

    var li = new _LocaleInfo["default"]();
    var clockPref = li.getClock();
    var meridiemEnabled = clockPref === '12';
    var filter = meridiemEnabled ? includeMeridiem : excludeMeridiem;
    var order = getLabelFormatter().getTemplate().replace(/'.*?'/g, '').match(filter).map(function (s) {
      return s[0].toLowerCase();
    });
    return {
      formatter: getLabelFormatter(),
      meridiemEnabled: meridiemEnabled,
      meridiemLabels: meridiemLabels,
      meridiemRanges: meridiemRanges,
      order: order
    };
  }
};
/**
 * Applies Agate specific behaviors to [TimePickerBase]{@link agate/TimePicker.TimePickerBase} components.
 *
 * @hoc
 * @memberof agate/TimePicker
 * @mixes agate/Skinnable.Skinnable
 * @public
 */

var TimePickerDecorator = (0, _compose["default"])(_Pure["default"], _Skinnable["default"]);
/**
 * A component that allows displaying or selecting time.
 *
 * Set the [value]{@link agate/TimePicker.TimePicker#value} property to a standard JavaScript
 * [Date] {@link /docs/developer-guide/glossary/#date} object to initialize the picker.
 *
 * By default, `TimePicker` maintains the state of its `value` property. Supply the
 * `defaultValue` property to control its initial value. If you wish to directly control updates
 * to the component, supply a value to `value` at creation time and update it in response to
 * `onChange` events.
 *
 * @class TimePicker
 * @memberof agate/TimePicker
 * @extends agate/TimePicker.TimePickerBase
 * @mixes agate/TimePicker.TimePickerDecorator
 * @ui
 * @public
 */

exports.TimePickerDecorator = TimePickerDecorator;
var TimePicker = TimePickerDecorator((0, _DateTime.DateTimeDecorator)(dateTimeConfig, _TimePickerBase["default"]));
/**
 * Default value
 *
 * @name defaultValue
 * @memberof agate/TimePicker.TimePicker.prototype
 * @type {Number}
 * @public
 */

/**
 * The selected date.
 *
 * @name value
 * @memberof agate/TimePicker.TimePicker
 * @instance
 * @type {Date}
 * @public
 */

/**
 * Converts a standard `Date` object into a locale-specific string.
 *
 * @function
 * @memberof agate/TimePicker
 * @param {Date} time `Date` to convert
 * @returns {String?} Converted date or `null` if `date` is invalid
 */

exports.TimePicker = TimePicker;

var timeToLocaleString = function timeToLocaleString(time) {
  if (!time) {
    return null;
  }

  return getLabelFormatter().format(time);
};

exports.timeToLocaleString = timeToLocaleString;
var _default = TimePicker;
exports["default"] = _default;