import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
import _createClass from "@babel/runtime/helpers/createClass";
import _inherits from "@babel/runtime/helpers/inherits";
import _createSuper from "@babel/runtime/helpers/createSuper";
import _typeof from "@babel/runtime/helpers/typeof";
import { cloneElement, Component, isValidElement } from 'react';
import { findDOMNode } from 'react-dom';
import noop from 'lodash/noop';
import alignElement, { alignPoint } from './domAlign';
import EventManager from '../_util/EventManager';
import TaskRunner from '../_util/TaskRunner';
import { isSamePoint, isWindow } from './util';

function getElement(func) {
  if (typeof func !== 'function' || !func) return null;
  return func();
}

function getPoint(point) {
  if (_typeof(point) !== 'object' || !point) return null;
  return point;
}

function isChildrenFunction(fn) {
  return typeof fn === 'function';
}

var Align = /*#__PURE__*/function (_Component) {
  _inherits(Align, _Component);

  var _super = _createSuper(Align);

  function Align() {
    var _this;

    _classCallCheck(this, Align);

    _this = _super.apply(this, arguments);

    _this.saveSourceRef = function (node) {
      _this.source = node;
      var childrenRef = _this.props.childrenRef;

      if (childrenRef) {
        childrenRef(node);
      }
    };

    return _this;
  }

  _createClass(Align, [{
    key: "componentDidMount",
    value: function componentDidMount() {
      var _this$props = this.props,
          hidden = _this$props.hidden,
          monitorWindowResize = _this$props.monitorWindowResize;
      this.forceAlign();

      if (!hidden && monitorWindowResize) {
        this.startMonitorWindowResize();
      }
    }
  }, {
    key: "componentDidUpdate",
    value: function componentDidUpdate(prevProps) {
      var _this$props2 = this.props,
          hidden = _this$props2.hidden,
          align = _this$props2.align,
          target = _this$props2.target,
          monitorWindowResize = _this$props2.monitorWindowResize;
      var preHidden = prevProps.hidden,
          preAlign = prevProps.align,
          preTarget = prevProps.target;
      var reAlign = false;

      if (!hidden) {
        var _this$source = this.source,
            source = _this$source === void 0 ? findDOMNode(this) : _this$source;
        var sourceRect = source ? source.getBoundingClientRect() : null;

        if (preHidden || preAlign !== align) {
          reAlign = true;
        } else {
          var lastElement = getElement(preTarget);
          var currentElement = getElement(target);
          var lastPoint = getPoint(preTarget);
          var currentPoint = getPoint(target);

          if (isWindow(lastElement) && isWindow(currentElement)) {
            // Skip if is window
            reAlign = false;
          } else if (lastElement !== currentElement || // Element change
          lastElement && !currentElement && currentPoint || // Change from element to point
          lastPoint && currentPoint && currentElement || // Change from point to element
          currentPoint && !isSamePoint(lastPoint, currentPoint)) {
            reAlign = true;
          } // If source element size changed


          var preRect = this.sourceRect;

          if (!reAlign && sourceRect && (!preRect || Math.round(preRect.width) !== Math.round(sourceRect.width) || Math.round(preRect.height) !== Math.round(sourceRect.height))) {
            reAlign = true;
          }
        }

        this.sourceRect = sourceRect;
      }

      if (reAlign) {
        this.forceAlign();
      }

      if (monitorWindowResize && !hidden) {
        this.startMonitorWindowResize();
      } else {
        this.stopMonitorWindowResize();
      }
    }
  }, {
    key: "componentWillUnmount",
    value: function componentWillUnmount() {
      this.stopMonitorWindowResize();
    }
  }, {
    key: "startMonitorWindowResize",
    value: function startMonitorWindowResize() {
      var monitorBufferTime = this.props.monitorBufferTime;

      if (!this.resizeHandler) {
        this.resizeHandler = new EventManager(window);
        this.bufferMonitor = new TaskRunner();
        this.resizeHandler.addEventListener('resize', this.bufferMonitor.delay.bind(this.bufferMonitor, monitorBufferTime, this.forceAlign.bind(this)));
      }
    }
  }, {
    key: "stopMonitorWindowResize",
    value: function stopMonitorWindowResize() {
      if (this.resizeHandler) {
        if (this.bufferMonitor) {
          this.bufferMonitor.cancel();
        }

        this.resizeHandler.clear();
        this.resizeHandler = null;
      }
    }
  }, {
    key: "forceAlign",
    value: function forceAlign() {
      var _this$props3 = this.props,
          hidden = _this$props3.hidden,
          _this$props3$onAlign = _this$props3.onAlign,
          onAlign = _this$props3$onAlign === void 0 ? noop : _this$props3$onAlign,
          target = _this$props3.target,
          align = _this$props3.align;

      if (!hidden && target) {
        var _this$source2 = this.source,
            source = _this$source2 === void 0 ? findDOMNode(this) : _this$source2;

        if (source && source.offsetParent) {
          var result;
          var element = getElement(target);
          var point = getPoint(target);

          if (element) {
            if (!element.offsetParent && !(element instanceof SVGElement)) {
              return;
            }

            result = alignElement(source, element, align);
          } else if (point) {
            result = alignPoint(source, point, align);
          }

          var translate = {
            x: 0,
            y: 0
          };
          var _result = result,
              points = _result.points,
              _result$overflow = _result.overflow,
              adjustX = _result$overflow.adjustX,
              adjustY = _result$overflow.adjustY;

          if (element && (adjustX || adjustY) && (points.includes('bc') || points.includes('tc'))) {
            var r1 = source.getBoundingClientRect();
            var r2 = element.getBoundingClientRect();

            if (adjustX) {
              translate.x = Math.round(r1.left + r1.width / 2 - r2.left - r2.width / 2);
            }

            if (adjustY) {
              translate.y = Math.round(r1.top + r1.height / 2 - r2.top - r2.height / 2);
            }
          }

          onAlign(source, result, element, translate, point);
        }
      }
    }
  }, {
    key: "render",
    value: function render() {
      var props = this.props;
      var childrenProps = props.childrenProps,
          children = props.children;
      var node = isChildrenFunction(children) ? children(this.saveSourceRef) : children;

      if (childrenProps && /*#__PURE__*/isValidElement(node)) {
        var newProps = {};
        Object.keys(childrenProps).forEach(function (prop) {
          if ({}.hasOwnProperty.call(childrenProps, prop)) {
            newProps[prop] = props[childrenProps[prop]];
          }
        });
        return /*#__PURE__*/cloneElement(node, newProps);
      }

      return node;
    }
  }]);

  return Align;
}(Component);

export { Align as default };
Align.displayName = 'Align';
Align.defaultProps = {
  target: function target() {
    return window;
  },
  monitorBufferTime: 50,
  monitorWindowResize: false,
  hidden: true
};
//# sourceMappingURL=Align.js.map
