import _defineProperty from 'babel-runtime/helpers/defineProperty';
import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
import _createClass from 'babel-runtime/helpers/createClass';
import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn';
import _inherits from 'babel-runtime/helpers/inherits';
var _jsxFileName = 'src/overlay/Overlay.jsx';
/**
 * Overlay.jsx
 *
 * @Author: jruif
 * @Date: 2018/1/8 上午11:22
 */

import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import Portal from '../portal';
import { CSSTransition, TransitionGroup } from 'react-transition-group';
import addDomEventListener from 'add-dom-event-listener';
import keyboardKey from '../util/keyboardKey';

var Overlay = function (_React$PureComponent) {
    _inherits(Overlay, _React$PureComponent);

    function Overlay(props, context) {
        _classCallCheck(this, Overlay);

        var _this = _possibleConstructorReturn(this, (Overlay.__proto__ || Object.getPrototypeOf(Overlay)).call(this, props, context));

        _this.overlayWillOpen = function () {
            var _this$props = _this.props,
                onOpen = _this$props.onOpen,
                isCloseOnDocumentClick = _this$props.isCloseOnDocumentClick,
                hasMask = _this$props.hasMask,
                inline = _this$props.inline,
                autoFocus = _this$props.autoFocus,
                enforceFocus = _this$props.enforceFocus;
            var openStack = Overlay.openStack;


            if (openStack.length > 0) {
                var lastOpenedOverlay = openStack[openStack.length - 1];
                lastOpenedOverlay.handleDocumentFocusListener && lastOpenedOverlay.handleDocumentFocusListener.remove();
                lastOpenedOverlay.handleDocumentFocusListener = null;
            }

            openStack.push(_this);

            if (autoFocus) {
                _this.handleFocusInsideOverlay();
            }

            if (enforceFocus) {
                _this.handleDocumentFocusListener = addDomEventListener(document.body, 'focus', _this.handleDocumentFocus);
            }

            if (isCloseOnDocumentClick && !hasMask) {
                _this.handleDocumentClickListener = addDomEventListener(_this.containerElement, 'mousedown', _this.handleDocumentClick);
            }
            if (inline) {
                onOpen();
            } else if (hasMask) {
                var clsReg = /is-overlay-open/g;
                if (!clsReg.test(document.body.className)) {
                    document.body.className += ' is-overlay-open';
                }
            }
        };

        _this.overlayWillClose = function () {
            var clsReg = /is-overlay-open/g;
            var openStack = Overlay.openStack;

            var stackIndex = openStack.indexOf(_this);

            document.body.className = document.body.className.replace(clsReg, '').trim();
            _this.handleDocumentClickListener && _this.handleDocumentClickListener.remove();
            _this.handleDocumentClickListener = null;
            _this.handleDocumentFocusListener && _this.handleDocumentFocusListener.remove();
            _this.handleDocumentFocusListener = null;

            if (stackIndex !== -1) {
                openStack.splice(stackIndex, 1);
                if (openStack.length > 0) {
                    var lastOpenedOverlay = openStack[openStack.length - 1];
                    if (lastOpenedOverlay.props.enforceFocus) {
                        _this.handleDocumentFocusListener = addDomEventListener(document.body, 'focus', lastOpenedOverlay.handleDocumentFocus);
                    }
                }

                if (openStack.filter(function (o) {
                    return !o.props.inline && o.props.hasMask;
                }).length === 0) {
                    document.body.className = document.body.className.replace(clsReg, '').trim();
                }
            }
        };

        _this.handleMaskMouseDown = function (e) {
            var _this$props2 = _this.props,
                maskProps = _this$props2.maskProps,
                isCloseOnDocumentClick = _this$props2.isCloseOnDocumentClick,
                enforceFocus = _this$props2.enforceFocus,
                onClose = _this$props2.onClose;

            if (isCloseOnDocumentClick) {
                onClose && onClose(e);
            }
            if (enforceFocus) {
                // make sure document.activeElement is updated before bringing the focus back
                _this.handleFocusInsideOverlay();
            }
            maskProps.onMouseDown && maskProps.onMouseDown(e);
        };

        _this.handleDocumentClick = function (e) {
            var _this$props3 = _this.props,
                isOpen = _this$props3.isOpen,
                onClose = _this$props3.onClose,
                isCloseOnDocumentClick = _this$props3.isCloseOnDocumentClick;

            var eventTarget = e.target;
            var isClickInOverlay = _this.containerElement != null && _this.containerElement.contains(eventTarget);
            if (isOpen && isCloseOnDocumentClick && !isClickInOverlay) {
                onClose && onClose(e);
            }
        };

        _this.handleDocumentFocus = function (e) {
            var enforceFocus = _this.props.enforceFocus;

            if (enforceFocus && _this.containerElement != null && !_this.containerElement.contains(e.target)) {
                // prevent default focus behavior (sometimes auto-scrolls the page)
                e.preventDefault();
                e.stopImmediatePropagation();
                _this.handleFocusInsideOverlay();
            }
        };

        _this.handleFocusInsideOverlay = function () {
            return requestAnimationFrame(function () {
                // container ref may be undefined between component mounting and Portal rendering
                // activeElement may be undefined in some rare cases in IE
                if (_this.containerElement == null || document.activeElement == null || !_this.props.isOpen) {
                    return;
                }

                var isFocusOutsideModal = !_this.containerElement.contains(document.activeElement);
                if (isFocusOutsideModal) {
                    var autofocusElement = _this.containerElement.query('[autofocus]');
                    var wrapperElement = _this.containerElement.query('[tabindex]');
                    if (autofocusElement != null) {
                        autofocusElement.focus();
                    } else if (wrapperElement != null) {
                        wrapperElement.focus();
                    }
                }
            });
        };

        _this.handleKeyDown = function (e) {
            var _this$props4 = _this.props,
                canEscapeKeyClose = _this$props4.canEscapeKeyClose,
                onClose = _this$props4.onClose;

            if (keyboardKey.getCode(e) !== keyboardKey.name.Escape && canEscapeKeyClose) {
                onClose && onClose(e);
                e.preventDefault();
            }
        };

        _this.handleContentMount = function () {
            var _this$props5 = _this.props,
                onOpen = _this$props5.onOpen,
                isOpen = _this$props5.isOpen;

            if (isOpen && onOpen) {
                onOpen();
            }
        };

        _this.containerRef = function (ref) {
            return _this.containerElement = ref;
        };

        _this.state = {
            isOpen: props.isOpen
        };
        return _this;
    }

    _createClass(Overlay, [{
        key: 'componentDidMount',
        value: function componentDidMount() {
            if (this.props.isOpen) {
                this.overlayWillOpen();
            }
        }
    }, {
        key: 'componentWillReceiveProps',
        value: function componentWillReceiveProps(nextProps) {
            this.setState({ isOpen: this.state.isOpen || nextProps.isOpen });
        }
    }, {
        key: 'componentDidUpdate',
        value: function componentDidUpdate(prevProps) {
            if (prevProps.isOpen && !this.props.isOpen) {
                this.overlayWillClose();
            } else if (!prevProps.isOpen && this.props.isOpen) {
                this.overlayWillOpen();
            }
        }
    }, {
        key: 'componentWillUnmount',
        value: function componentWillUnmount() {
            this.overlayWillClose();
        }
    }, {
        key: 'render',
        value: function render() {
            var _this2 = this,
                _classNames;

            var _props = this.props,
                children = _props.children,
                prefixCls = _props.prefixCls,
                className = _props.className,
                inline = _props.inline,
                isOpen = _props.isOpen,
                hasMask = _props.hasMask,
                maskProp = _props.maskProp,
                maskClassName = _props.maskClassName,
                transitionDuration = _props.transitionDuration,
                transitionName = _props.transitionName,
                isCloseOnDocumentClick = _props.isCloseOnDocumentClick;


            var childrenWithTransitions = React.Children.map(children, function (child) {
                var decoratedChild = React.cloneElement(child, {
                    className: classNames(prefixCls + '-content'),
                    tabIndex: 0
                });
                return React.createElement(
                    CSSTransition,
                    { classNames: transitionName, timeout: transitionDuration, __source: {
                            fileName: _jsxFileName,
                            lineNumber: 232
                        },
                        __self: _this2
                    },
                    decoratedChild
                );
            });

            var transitionGroup = React.createElement(
                TransitionGroup,
                { appear: true, __source: {
                        fileName: _jsxFileName,
                        lineNumber: 239
                    },
                    __self: this
                },
                hasMask && isOpen ? React.createElement(
                    CSSTransition,
                    { classNames: transitionName, timeout: transitionDuration, __source: {
                            fileName: _jsxFileName,
                            lineNumber: 241
                        },
                        __self: this
                    },
                    React.createElement('div', Object.assign({}, maskProp, {
                        className: classNames(prefixCls + '-mask', maskClassName),
                        onMouseDown: this.handleMaskMouseDown,
                        tabIndex: isCloseOnDocumentClick ? 0 : null,
                        __source: {
                            fileName: _jsxFileName,
                            lineNumber: 242
                        },
                        __self: this
                    }))
                ) : null,
                isOpen ? childrenWithTransitions : null
            );

            var mergedClassName = classNames(prefixCls, (_classNames = {}, _defineProperty(_classNames, prefixCls + '-open', isOpen), _defineProperty(_classNames, prefixCls + '-inline', inline), _classNames), className);

            var elementProps = {
                className: mergedClassName,
                onKeyDown: this.handleKeyDown
            };

            if (inline) {
                return React.createElement(
                    'span',
                    Object.assign({}, elementProps, { ref: this.containerRef, __source: {
                            fileName: _jsxFileName,
                            lineNumber: 270
                        },
                        __self: this
                    }),
                    transitionGroup
                );
            }

            return React.createElement(
                Portal,
                Object.assign({}, elementProps, { containerRef: this.containerRef, onChildrenMount: this.handleContentMount, __source: {
                        fileName: _jsxFileName,
                        lineNumber: 277
                    },
                    __self: this
                }),
                transitionGroup
            );
        }
    }]);

    return Overlay;
}(React.PureComponent);

Overlay.displayName = 'NeatUI.Overlay';
Overlay.propTypes = {
    autoFocus: PropTypes.bool,
    inline: PropTypes.bool,
    isOpen: PropTypes.bool,
    hasMask: PropTypes.bool,
    isCloseOnDocumentClick: PropTypes.bool,
    prefixCls: PropTypes.string,
    transitionName: PropTypes.string,
    transitionDuration: PropTypes.number,
    onClose: PropTypes.func,
    onOpen: PropTypes.func,
    maskProp: PropTypes.object
};
Overlay.defaultProps = {
    prefixCls: 'ne-overlay',
    autoFocus: false,
    inline: false,
    isOpen: false,
    hasMask: true,
    transitionDuration: 500,
    isCloseOnDocumentClick: false,
    maskProp: {}
};
Overlay.openStack = [];


export default Overlay;