function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }

function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }

function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }

function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }

function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }

function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }

function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }

function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }

function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }

function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

/*
Copyright (c) 2018-2019 Uber Technologies, Inc.

This source code is licensed under the MIT license found in the
LICENSE file in the root directory of this source tree.
*/
import * as React from 'react';
import { FormControl } from '../form-control/index.js';
import { LocaleContext } from '../locale/index.js';
import { Select } from '../select/index.js';
import CalendarHeader from './calendar-header.js';
import Month from './month.js';
import TimePicker from './timepicker.js';
import { StyledRoot, StyledCalendarContainer, StyledSelectorContainer } from './styled-components.js';
import { addDays, addMonths, getMonth, addWeeks, getEffectiveMinDate, getEffectiveMaxDate, isAfter, isBefore, isSameDay, isSameMonth, isSameYear, subDays, subWeeks, subMonths, subYears, setHours, setMinutes, setSeconds, getHours, getMinutes } from './utils/index.js';
import { getOverrides } from '../helpers/overrides.js';

function applyTime(prev, next) {
  if (!prev) return next;
  var hours = setHours(next, getHours(prev));
  var minutes = setMinutes(hours, getMinutes(prev));
  var seconds = setSeconds(minutes, 0);
  return seconds;
}

var Calendar =
/*#__PURE__*/
function (_React$Component) {
  _inherits(Calendar, _React$Component);

  function Calendar(props) {
    var _this;

    _classCallCheck(this, Calendar);

    _this = _possibleConstructorReturn(this, _getPrototypeOf(Calendar).call(this, props));

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "root", void 0);

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "calendar", void 0);

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "getDateInView", function () {
      var _this$props = _this.props,
          highlightedDate = _this$props.highlightedDate,
          value = _this$props.value;
      var minDate = getEffectiveMinDate(_this.props);
      var maxDate = getEffectiveMaxDate(_this.props);
      var current = new Date();
      var initialDate = _this.getSingleDate(value) || highlightedDate;

      if (initialDate) {
        return initialDate;
      } else {
        if (minDate && isBefore(current, minDate)) {
          return minDate;
        } else if (maxDate && isAfter(current, maxDate)) {
          return maxDate;
        }
      }

      return current;
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleMonthChange", function (date) {
      if (_this.props.onMonthChange) {
        _this.props.onMonthChange({
          date: date
        });
      }
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleYearChange", function (date) {
      _this.setHighlightedDate(date);

      if (_this.props.onYearChange) {
        _this.props.onYearChange({
          date: date
        });
      }
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "changeMonth", function (_ref) {
      var date = _ref.date;

      _this.setState({
        date: date
      }, function () {
        return _this.handleMonthChange(_this.state.date);
      });
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "changeYear", function (_ref2) {
      var date = _ref2.date;

      _this.setState({
        date: date
      }, function () {
        return _this.handleYearChange(_this.state.date);
      });
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "renderCalendarHeader", function () {
      var date = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _this.state.date;
      var order = arguments.length > 1 ? arguments[1] : undefined;
      return React.createElement(CalendarHeader, _extends({}, _this.props, {
        key: "month-header-".concat(order),
        date: date,
        order: order,
        onMonthChange: _this.changeMonth,
        onYearChange: _this.changeYear
      }));
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "onKeyDown", function (event) {
      switch (event.key) {
        case 'ArrowUp':
        case 'ArrowDown':
        case 'ArrowLeft':
        case 'ArrowRight':
          _this.handleArrowKey(event.key);

          event.preventDefault();
          event.stopPropagation();
          break;
      }
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleArrowKey", function (key) {
      var oldDate = _this.state.highlightedDate;
      var highlightedDate = oldDate;

      switch (key) {
        case 'ArrowLeft':
          // adding `new Date()` as the last option to satisfy Flow
          highlightedDate = subDays(highlightedDate ? highlightedDate : new Date(), 1);
          break;

        case 'ArrowRight':
          highlightedDate = addDays( // adding `new Date()` as the last option to satisfy Flow
          highlightedDate ? highlightedDate : new Date(), 1);
          break;

        case 'ArrowUp':
          highlightedDate = subWeeks( // adding `new Date()` as the last option to satisfy Flow
          highlightedDate ? highlightedDate : new Date(), 1);
          break;

        case 'ArrowDown':
          highlightedDate = addWeeks( // adding `new Date()` as the last option to satisfy Flow
          highlightedDate ? highlightedDate : new Date(), 1);
          break;
      }

      _this.setState({
        highlightedDate: highlightedDate,
        date: highlightedDate
      });
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "focusCalendar", function () {
      if (!_this.state.focused) {
        _this.setState({
          focused: true
        });
      }
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "blurCalendar", function () {
      if (typeof document !== 'undefined') {
        var activeElm = document.activeElement;

        if (_this.calendar && !_this.calendar.contains(activeElm)) {
          _this.setState({
            focused: false
          });
        }
      }
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleTabbing", function (event) {
      if (typeof document !== 'undefined') {
        if (event.keyCode === 9) {
          var activeElm = document.activeElement; // need to look for any tabindex >= 0 and ideally for not disabled
          // focusable by default elements like input, button, etc.

          var focusable = _this.root ? _this.root.querySelectorAll('[tabindex="0"]') : null;
          var length = focusable ? focusable.length : 0;

          if (event.shiftKey) {
            if (focusable && activeElm === focusable[0]) {
              event.preventDefault();
              focusable[length - 1].focus();
            }
          } else {
            if (focusable && activeElm === focusable[length - 1]) {
              event.preventDefault();
              focusable[0].focus();
            }
          }
        }
      }
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "onDayMouseOver", function (data) {
      var date = data.date;

      _this.setState({
        highlightedDate: date
      });

      _this.props.onDayMouseOver && _this.props.onDayMouseOver(data);
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "onDayMouseLeave", function (data) {
      var date = data.date;

      _this.setHighlightedDate(date);

      _this.props.onDayMouseLeave && _this.props.onDayMouseLeave(data);
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleDateChange", function (data) {
      var _this$props$onChange = _this.props.onChange,
          onChange = _this$props$onChange === void 0 ? function (params) {} : _this$props$onChange;

      if (Array.isArray(data.date)) {
        var dates = data.date.map(function (date, index) {
          var values = [].concat(_this.props.value);
          return applyTime(values[index], date);
        });
        onChange({
          date: dates
        });
      } else if (!Array.isArray(_this.props.value)) {
        if (data.date) {
          var nextDate = applyTime(_this.props.value, data.date);
          onChange({
            date: nextDate
          });
        } else {
          onChange({
            date: data.date
          });
        }
      }
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleTimeChange", function (time, index) {
      var _this$props$onChange2 = _this.props.onChange,
          onChange = _this$props$onChange2 === void 0 ? function (params) {} : _this$props$onChange2;

      if (Array.isArray(_this.props.value)) {
        var dates = _this.props.value.map(function (date, i) {
          if (index === i) {
            return applyTime(date, time);
          }

          return date;
        });

        onChange({
          date: dates
        });
      } else {
        var date = applyTime(_this.props.value, time);
        onChange({
          date: date
        });
      }
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "renderMonths", function () {
      var _this$props$overrides = _this.props.overrides,
          overrides = _this$props$overrides === void 0 ? {} : _this$props$overrides;
      var monthList = [];

      var _getOverrides = getOverrides(overrides.CalendarContainer, StyledCalendarContainer),
          _getOverrides2 = _slicedToArray(_getOverrides, 2),
          CalendarContainer = _getOverrides2[0],
          calendarContainerProps = _getOverrides2[1];

      for (var i = 0; i < (_this.props.monthsShown || 1); ++i) {
        var monthDate = addMonths(_this.state.date, i);
        var monthKey = "month-".concat(i);
        monthList.push(_this.renderCalendarHeader(monthDate, i));
        monthList.push(React.createElement(CalendarContainer, _extends({
          key: monthKey,
          ref: function ref(calendar) {
            _this.calendar = calendar;
          },
          onKeyDown: _this.onKeyDown
        }, calendarContainerProps), React.createElement(Month, {
          date: monthDate,
          excludeDates: _this.props.excludeDates,
          filterDate: _this.props.filterDate,
          highlightedDate: _this.state.highlightedDate,
          includeDates: _this.props.includeDates,
          focusedCalendar: _this.state.focused,
          range: _this.props.range,
          locale: _this.props.locale,
          maxDate: _this.props.maxDate,
          minDate: _this.props.minDate,
          month: getMonth(_this.state.date),
          onDayBlur: _this.blurCalendar,
          onDayFocus: _this.focusCalendar,
          onDayClick: _this.props.onDayClick,
          onDayMouseOver: _this.onDayMouseOver,
          onDayMouseLeave: _this.onDayMouseLeave,
          onChange: _this.handleDateChange,
          overrides: overrides,
          value: _this.props.value,
          peekNextMonth: _this.props.peekNextMonth
        })));
      }

      return monthList;
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "renderTimeSelect", function (value, onChange) {
      var _this$props$overrides2 = _this.props.overrides,
          overrides = _this$props$overrides2 === void 0 ? {} : _this$props$overrides2;

      var _getOverrides3 = getOverrides(overrides.TimeSelectContainer, StyledSelectorContainer),
          _getOverrides4 = _slicedToArray(_getOverrides3, 2),
          TimeSelectContainer = _getOverrides4[0],
          timeSelectContainerProps = _getOverrides4[1];

      var _getOverrides5 = getOverrides(overrides.TimeSelectFormControl, FormControl),
          _getOverrides6 = _slicedToArray(_getOverrides5, 2),
          TimeSelectFormControl = _getOverrides6[0],
          timeSelectFormControlProps = _getOverrides6[1];

      var _getOverrides7 = getOverrides(overrides.TimeSelect, TimePicker),
          _getOverrides8 = _slicedToArray(_getOverrides7, 2),
          TimeSelect = _getOverrides8[0],
          timeSelectProps = _getOverrides8[1];

      return React.createElement(LocaleContext.Consumer, null, function (locale) {
        return React.createElement(TimeSelectContainer, timeSelectContainerProps, React.createElement(TimeSelectFormControl, _extends({
          label: locale.datepicker.timeSelectLabel
        }, timeSelectFormControlProps), React.createElement(TimeSelect, _extends({
          value: value,
          onChange: onChange
        }, timeSelectProps))));
      });
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "renderQuickSelect", function () {
      var _this$props$overrides3 = _this.props.overrides,
          overrides = _this$props$overrides3 === void 0 ? {} : _this$props$overrides3;

      var _getOverrides9 = getOverrides(overrides.QuickSelectContainer, StyledSelectorContainer),
          _getOverrides10 = _slicedToArray(_getOverrides9, 2),
          QuickSelectContainer = _getOverrides10[0],
          quickSelectContainerProps = _getOverrides10[1];

      var _getOverrides11 = getOverrides(overrides.QuickSelectFormControl, FormControl),
          _getOverrides12 = _slicedToArray(_getOverrides11, 2),
          QuickSelectFormControl = _getOverrides12[0],
          quickSelectFormControlProps = _getOverrides12[1];

      var _getOverrides13 = getOverrides(overrides.QuickSelect, Select),
          _getOverrides14 = _slicedToArray(_getOverrides13, 2),
          QuickSelect = _getOverrides14[0],
          quickSelectProps = _getOverrides14[1];

      if (!_this.props.quickSelect) {
        return null;
      }

      var NOW = new Date();
      NOW.setHours(12, 0, 0);
      var QUICK_SELECT_ACTIONS = [{
        id: 'Past Week',
        beginDate: subWeeks(NOW, 1)
      }, {
        id: 'Past Month',
        beginDate: subMonths(NOW, 1)
      }, {
        id: 'Past 3 Months',
        beginDate: subMonths(NOW, 3)
      }, {
        id: 'Past 6 Months',
        beginDate: subMonths(NOW, 6)
      }, {
        id: 'Past Year',
        beginDate: subYears(NOW, 1)
      }, {
        id: 'Past 2 Years',
        beginDate: subYears(NOW, 2)
      }];
      return React.createElement(LocaleContext.Consumer, null, function (locale) {
        return React.createElement(QuickSelectContainer, quickSelectContainerProps, React.createElement(QuickSelectFormControl, _extends({
          label: locale.datepicker.quickSelectLabel
        }, quickSelectFormControlProps), React.createElement(QuickSelect, _extends({
          "aria-label": locale.datepicker.quickSelectAriaLabel,
          labelKey: "id",
          onChange: function onChange(params) {
            if (!params.option) {
              _this.setState({
                quickSelectId: null
              });

              _this.props.onChange && _this.props.onChange({
                date: []
              });
            } else {
              _this.setState({
                quickSelectId: params.option.id
              });

              if (_this.props.onChange) {
                if (_this.props.range) {
                  _this.props.onChange({
                    date: [params.option.beginDate, NOW]
                  });
                } else {
                  _this.props.onChange({
                    date: params.option.beginDate
                  });
                }
              }
            }
          },
          options: _this.props.quickSelectOptions || QUICK_SELECT_ACTIONS,
          placeholder: "None",
          value: _this.state.quickSelectId && [{
            id: _this.state.quickSelectId
          }]
        }, quickSelectProps))));
      });
    });

    _this.state = {
      highlightedDate: _this.props.highlightedDate || _this.getSingleDate(_this.props.value) || new Date(),
      focused: false,
      date: _this.getDateInView(),
      quickSelectId: null
    };
    return _this;
  }

  _createClass(Calendar, [{
    key: "componentDidMount",
    value: function componentDidMount() {
      if (this.props.autoFocusCalendar) {
        this.focusCalendar();
      }
    }
  }, {
    key: "componentDidUpdate",
    value: function componentDidUpdate(prevProps) {
      if (this.props.highlightedDate && !isSameDay(this.props.highlightedDate, prevProps.highlightedDate)) {
        this.setState({
          date: this.props.highlightedDate
        });
      }

      if (this.props.autoFocusCalendar && this.props.autoFocusCalendar !== prevProps.autoFocusCalendar) {
        this.focusCalendar();
      }
    }
  }, {
    key: "getSingleDate",
    value: function getSingleDate(value) {
      // need to check this.props.range but flow would complain
      // at the return value in the else clause
      if (Array.isArray(value)) {
        return value[0] || null;
      }

      return value;
    }
  }, {
    key: "setHighlightedDate",
    value: function setHighlightedDate(date) {
      var value = this.props.value;
      var selected = this.getSingleDate(value);
      var nextState;

      if (selected && isSameMonth(selected, date) && isSameYear(selected, date)) {
        nextState = {
          highlightedDate: selected
        };
      } else {
        nextState = {
          highlightedDate: date
        };
      }

      this.setState(nextState);
    }
  }, {
    key: "render",
    value: function render() {
      var _this2 = this;

      var _this$props$overrides4 = this.props.overrides,
          overrides = _this$props$overrides4 === void 0 ? {} : _this$props$overrides4;

      var _getOverrides15 = getOverrides(overrides.Root, StyledRoot),
          _getOverrides16 = _slicedToArray(_getOverrides15, 2),
          Root = _getOverrides16[0],
          rootProps = _getOverrides16[1];

      var _concat = [].concat(this.props.value),
          _concat2 = _slicedToArray(_concat, 2),
          startDate = _concat2[0],
          endDate = _concat2[1];

      return React.createElement(Root, _extends({
        "data-baseweb": "calendar",
        ref: function ref(root) {
          _this2.root = root;
        },
        role: "application",
        "aria-label": "calendar",
        onKeyDown: this.props.trapTabbing ? this.handleTabbing : null
      }, rootProps), this.renderMonths(), this.props.timeSelectStart && this.renderTimeSelect(startDate, function (time) {
        return _this2.handleTimeChange(time, 0);
      }), this.props.timeSelectEnd && this.props.range && this.renderTimeSelect(endDate, function (time) {
        return _this2.handleTimeChange(time, 1);
      }), this.renderQuickSelect());
    }
  }]);

  return Calendar;
}(React.Component);

_defineProperty(Calendar, "defaultProps", {
  autoFocusCalendar: false,
  excludeDates: null,
  filterDate: null,
  highlightedDate: null,
  includeDates: null,
  range: false,
  locale: null,
  maxDate: null,
  minDate: null,
  onDayClick: function onDayClick() {},
  onDayMouseOver: function onDayMouseOver() {},
  onDayMouseLeave: function onDayMouseLeave() {},
  onMonthChange: function onMonthChange() {},
  onYearChange: function onYearChange() {},
  onChange: function onChange() {},
  overrides: {},
  peekNextMonth: false,
  value: null,
  trapTabbing: false
});

export { Calendar as default };