'use strict';

exports.__esModule = true;

var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');

var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);

var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');

var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);

var _inherits2 = require('babel-runtime/helpers/inherits');

var _inherits3 = _interopRequireDefault(_inherits2);

var _react = require('react');

var _react2 = _interopRequireDefault(_react);

var _propTypes = require('prop-types');

var _propTypes2 = _interopRequireDefault(_propTypes);

var _reactDom = require('react-dom');

var _reactDom2 = _interopRequireDefault(_reactDom);

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

var EventOverlay = function (_React$Component) {
  (0, _inherits3.default)(EventOverlay, _React$Component);

  function EventOverlay() {
    var _temp, _this, _ret;

    (0, _classCallCheck3.default)(this, EventOverlay);

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

    return _ret = (_temp = (_this = (0, _possibleConstructorReturn3.default)(this, _React$Component.call.apply(_React$Component, [this].concat(args))), _this), _this.state = {
      visibleDirection: _this.props.direction
    }, _this.componentDidMount = function () {
      _this.addHandlers();
    }, _this.componentDidUpdate = function (prevProps) {
      if (_this.props.isOpen && prevProps.isOpen !== _this.props.isOpen || prevProps.direction !== _this.props.direction) {
        return _this.forceUpdate(function () {
          return _this.isVisible();
        });
      }
    }, _this.componentWillUnmount = function () {
      _this.removeHandlers();
    }, _this.isVisible = function () {
      var _this$props = _this.props,
          direction = _this$props.direction,
          isOpen = _this$props.isOpen,
          anchorNode = _this$props.anchorNode,
          showArrow = _this$props.showArrow,
          isDynamic = _this$props.isDynamic,
          targetOffset = _this$props.targetOffset;

      if (!isOpen) return;
      if (!isDynamic) return _this.setPlacement();
      var element = _reactDom2.default.findDOMNode(_this.container);
      var elementAnchor = _reactDom2.default.findDOMNode(anchorNode);
      var alignment = direction.split('-')[1];
      var tempParentArr = [];
      var anchor = elementAnchor && elementAnchor.getBoundingClientRect();
      var elementBoundingRect = element.getBoundingClientRect();
      var elementParent = element.parentElement;
      var windowBottom = window.pageXOffset + window.innerHeight;
      var elementHeight = elementBoundingRect.height;
      var anchorBottom = anchor.bottom;
      var arrowHeight = showArrow ? _reactDom2.default.findDOMNode(_this.arrow).getBoundingClientRect().height : 0;
      var offsetHeight = targetOffset.height || 0;
      var totalHeight = anchorBottom + elementHeight + arrowHeight + offsetHeight;

      var findParents = function findParents(elem) {
        return !elem.parentElement ? tempParentArr : findParents(elem.parentElement, tempParentArr.push(elem));
      };

      var elementParents = findParents(elementParent);

      var findOverflow = function findOverflow(node) {
        var searchProps = ['overflow', 'overflow-y'];

        return searchProps.reduce(function (agg, prop) {
          var overflowElement = _reactDom2.default.findDOMNode(node).style[prop];

          return !overflowElement || agg.includes(overflowElement) ? agg : agg += overflowElement;
        }, '');
      };

      var findScrollParent = function findScrollParent() {
        var overflowElement = null;
        var idx = 0;

        while (!overflowElement && elementParents[idx]) {
          if (/(auto|scroll)/.test(findOverflow(elementParents[idx]))) {
            return overflowElement = elementParents[idx];
          }
          idx++;
        }

        return overflowElement ? overflowElement : window;
      };

      var scrollParent = findScrollParent(element);
      var parentBottom = !!scrollParent.getBoundingClientRect && scrollParent.getBoundingClientRect().bottom || windowBottom;

      return totalHeight < parentBottom && totalHeight < windowBottom ? _this.setState({ visibleDirection: 'bottom-' + alignment }, function () {
        return _this.setPlacement();
      }) : _this.setState({ visibleDirection: 'top-' + alignment }, function () {
        return _this.setPlacement();
      });
    }, _this.addHandlers = function () {
      var allowClickAway = _this.props.allowClickAway;

      _this.handleResize = _this.isVisible;
      _this.handleScroll = _this.isVisible;

      allowClickAway && window.addEventListener('click', _this.handleClick, true);
      window.addEventListener('resize', _this.handleResize, true);
      window.addEventListener('scroll', _this.handleScroll, false);
      window.addEventListener('keyup', _this.handleKeyUp, true);

      _this.isVisible();
    }, _this.removeHandlers = function () {
      window.removeEventListener('click', _this.handleClick, true);
      window.removeEventListener('resize', _this.handleResize, true);
      window.removeEventListener('scroll', _this.handleScroll, true);
      window.removeEventListener('keyup', _this.handleKeyUp, true);
    }, _this.handleKeyUp = function (e) {
      if (!_this.props.isOpen) return;
      if (e.keyCode === 27) return _this.handleClickAway(e);
      var anchorNode = _reactDom2.default.findDOMNode(_this.props.anchorNode);

      return _this.container && !anchorNode.contains(document.activeElement) && !_reactDom2.default.findDOMNode(_this.container).contains(document.activeElement) && _this.handleClickAway(e);
    }, _this.handleClick = function (e) {
      if (!_this.props.isOpen) return;
      var anchorNode = _reactDom2.default.findDOMNode(_this.props.anchorNode);

      return _this.container && !_reactDom2.default.findDOMNode(anchorNode).contains(e.target) && (_this.props.closeOnClick || !_reactDom2.default.findDOMNode(_this.container).contains(e.target)) && _this.handleClickAway(e);
    }, _this.getAnchorPosition = function (node) {
      var rect = node.getBoundingClientRect();

      var anchorPosition = {
        top: rect.top,
        left: rect.left,
        width: node.offsetWidth,
        height: node.offsetHeight
      };

      anchorPosition.right = rect.right || anchorPosition.left + anchorPosition.width;
      anchorPosition.bottom = rect.bottom || anchorPosition.top + anchorPosition.height;
      anchorPosition.middle = anchorPosition.left + (anchorPosition.right - anchorPosition.left) / 2;
      anchorPosition.center = anchorPosition.top + (anchorPosition.bottom - anchorPosition.top) / 2;

      return anchorPosition;
    }, _this.getTargetPosition = function (targetNode) {
      return {
        top: 0,
        center: targetNode.offsetHeight / 2,
        bottom: targetNode.offsetHeight,
        left: 0,
        middle: targetNode.offsetWidth / 2,
        right: targetNode.offsetWidth
      };
    }, _this.getOrigin = function () {
      var side = _this.state.visibleDirection.split('-')[0];
      var alignment = _this.props.direction.split('-')[1];
      var origin = {
        anchor: {},
        target: {}
      };

      if (side === 'top' || side === 'bottom') {
        origin.anchor.vertical = side;
        origin.anchor.horizontal = alignment === 'center' ? 'middle' : alignment;

        origin.target.vertical = side === 'top' ? 'bottom' : 'top';
        origin.target.horizontal = alignment === 'center' ? 'middle' : alignment;
      }

      if (side === 'left' || side === 'right') {
        origin.anchor.vertical = alignment;
        origin.anchor.horizontal = side;

        origin.target.vertical = alignment;
        origin.target.horizontal = side === 'left' ? 'right' : 'left';
      }

      return origin;
    }, _this.setArrowPlacement = function (anchor) {
      var arrow = _this.arrow;
      var targetOffset = _this.props.targetOffset;
      var visibleDirection = _this.state.visibleDirection;

      var side = visibleDirection.split('-')[0];
      var verticalOffset = targetOffset.vertical || 0;
      var horizontalOffset = targetOffset.horizontal || 0;

      switch (side) {
        case 'top':
          arrow.style.left = anchor.middle + 'px';
          arrow.style.top = anchor.top - verticalOffset + 'px';
          break;
        case 'bottom':
          arrow.style.left = anchor.middle + 'px';
          arrow.style.top = anchor.bottom + verticalOffset + 'px';
          break;

        case 'left':
          arrow.style.left = anchor.left - horizontalOffset + 'px';
          arrow.style.top = anchor.center + 'px';
          break;

        case 'right':
          arrow.style.left = anchor.right + horizontalOffset + 'px';
          arrow.style.top = anchor.center + 'px';
          break;
      }
    }, _this.setPlacement = function () {
      var _this$props2 = _this.props,
          isOpen = _this$props2.isOpen,
          anchorNode = _this$props2.anchorNode,
          maxHeight = _this$props2.maxHeight,
          targetOffset = _this$props2.targetOffset;
      var visibleDirection = _this.state.visibleDirection;

      if (!isOpen) return;

      var anchorNodeFound = _reactDom2.default.findDOMNode(anchorNode);
      var side = visibleDirection.split('-')[0];
      var targetNode = _this.container;
      var verticalOffset = targetOffset.vertical || 0;
      var horizontalOffset = targetOffset.horizontal || 0;

      if (!targetNode || !anchorNodeFound) return;

      var anchorPosition = _this.getAnchorPosition(anchorNodeFound);
      var targetPosition = _this.getTargetPosition(targetNode);

      var origin = _this.getOrigin();

      var anchorOrigin = origin.anchor;
      var targetOrigin = origin.target;

      var targetNodePosition = {
        top: anchorPosition[anchorOrigin.vertical] - targetPosition[targetOrigin.vertical] + (side === 'top' ? -verticalOffset : verticalOffset),
        left: anchorPosition[anchorOrigin.horizontal] - targetPosition[targetOrigin.horizontal] + (side === 'left' ? -horizontalOffset : horizontalOffset)
      };

      targetNode.style.top = targetNodePosition.top + 'px';
      targetNode.style.left = targetNodePosition.left + 'px';
      targetNode.style.maxHeight = maxHeight && maxHeight + 'px';

      _this.props.showArrow && _this.setArrowPlacement(anchorPosition);
    }, _this.handleClickAway = function (e) {
      _this.props.close && _this.props.close(e);
    }, _temp), (0, _possibleConstructorReturn3.default)(_this, _ret);
  }

  EventOverlay.prototype.render = function render() {
    var _this2 = this;

    var _props = this.props,
        className = _props.className,
        isOpen = _props.isOpen,
        children = _props.children,
        showArrow = _props.showArrow;

    var side = this.state.visibleDirection.split('-')[0];
    var contentNodes = _react2.default.createElement(
      'div',
      {
        className: 'cui-event-overlay' + ('' + (showArrow && ' cui-event-overlay--arrow' || '')) + ('' + (side && ' cui-event-overlay--' + side || '')) + ('' + (className && ' ' + className || ''))
      },
      showArrow && _react2.default.createElement('div', {
        ref: function ref(_ref) {
          return _this2.arrow = _ref;
        },
        className: 'cui-event-overlay__arrow'
      }),
      _react2.default.createElement(
        'div',
        {
          className: 'cui-event-overlay__children',
          ref: function ref(_ref2) {
            return _this2.container = _ref2;
          }
        },
        children
      )
    );

    return isOpen && contentNodes;
  };

  return EventOverlay;
}(_react2.default.Component);

EventOverlay.displayName = 'EventOverlay';
exports.default = EventOverlay;


EventOverlay.defaultProps = {
  allowClickAway: true,
  anchorNode: null,
  children: null,
  className: '',
  close: null,
  isDynamic: false,
  isOpen: false,
  direction: 'bottom-left',
  targetOffset: {
    horizontal: 0,
    vertical: 0
  },
  showArrow: false,
  maxHeight: null
};

module.exports = exports['default'];