import _defineProperty from 'babel-runtime/helpers/defineProperty';
import _objectWithoutProperties from 'babel-runtime/helpers/objectWithoutProperties';
import _slicedToArray from 'babel-runtime/helpers/slicedToArray';
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/tooltip/Tooltip.jsx';
/**
 * Tooltip.jsx
 *
 * @Author: jruif
 * @Date: 2017/7/14 下午3:18
 */

import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import Box from '../box';
import omit from '../util/omit';
import extend from 'deep-extend';
import throttle from '../util/throttle';
import addEventListener from '../util/addEventListener';
import { isBoolean } from '../util/isType.js';

export var POSITIONS = ['top', 'topLeft', 'topRight', 'bottom', 'bottomLeft', 'bottomRight', 'left', 'leftTop', 'leftBottom', 'right', 'rightTop', 'rightBottom'];

export var defaultProps = {
    prefixCls: 'ne-tooltip',
    position: 'top',
    isOpen: false,
    // isOpenOnTriggerClick: false,
    // isCloseOnTriggerClick: false,
    // isOpenOnTriggerFocus: false,
    // isCloseOnTriggerBlur: false,
    // isOpenOnTriggerMouseEnter: false,
    // isCloseOnTriggerMouseLeave: false,
    // isCloseOnBoxMouseLeave: true,
    isCloseOnDocumentClick: true,
    // isCacheInNodeTree: true,
    isScrollClose: false,
    autoAdjustPosition: false,
    mouseEnterDelay: 50,
    mouseLeaveDelay: 100,
    trigger: 'hover',
    translate: 5,
    animationTime: 300 };

/**
 * Tooltip
 * */

var Tooltip = function (_React$Component) {
    _inherits(Tooltip, _React$Component);

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

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

        _this.updateTriggerEvent = function () {
            var trigger = _this.props.trigger;

            _this.triggerEvent = {
                /** 当trigger被点击时，是否打开 */
                isOpenOnTriggerClick: trigger === 'click',

                /** 在trigger上点击是否关闭 */
                isCloseOnTriggerClick: trigger === 'click',

                /** 当trigger被focus时，是否打开 */
                isOpenOnTriggerFocus: trigger === 'focus',

                /** 在trigger上失焦是否关闭 */
                isCloseOnTriggerBlur: trigger === 'focus',

                /** 当trigger被Mouse Enter时，是否打开 */
                isOpenOnTriggerMouseEnter: trigger === 'hover',

                /** 在trigger上Mouse Leave是否关闭 */
                isCloseOnTriggerMouseLeave: trigger === 'hover',

                /** 在box上Mouse Leave是否关闭 */
                isCloseOnBoxMouseLeave: trigger === 'hover'
            };
        };

        _this.setPosition = function () {
            if (!_this.state.isOpen || _this.hasPosition || !(_this.triggerNode && _this.tooltipClientRect)) {
                return;
            }
            _this.detectBoundary();
            var tooltipClientRect = _this.tooltipClientRect;
            var arrowClientRect = _this.arrowClientRect;
            var clientRect = _this.triggerNode.getBoundingClientRect();
            var _window = window,
                pageYOffset = _window.pageYOffset,
                pageXOffset = _window.pageXOffset;
            var clientWidth = document.documentElement.clientWidth;
            var translate = _this.props.translate;
            var position = _this.state.position;

            // 计算坐标

            var index = POSITIONS.indexOf(position);
            var nowStyle = { left: null, top: null, right: null, bottom: null, opacity: 1 };
            var arrow = { top: null, left: null },
                transformX = 0,
                transformY = 0;

            switch (index) {
                case -1:
                case 0:
                    // top
                    transformX = -(tooltipClientRect.width - clientRect.width) / 2;
                    //transformY = -tooltipClientRect.height + translate;
                    transformY = -clientRect.height + translate;
                    nowStyle.transform = 'translate(0, -' + translate + 'px)';
                    nowStyle.bottom = -Math.round(pageYOffset + clientRect.bottom + transformY);
                    nowStyle.left = Math.round(pageXOffset + clientRect.left + transformX);
                    break;
                case 1:
                    // topLeft
                    transformY = -clientRect.height + translate;
                    nowStyle.transform = 'translate(0, -' + translate + 'px)';
                    nowStyle.bottom = -Math.round(pageYOffset + clientRect.bottom + transformY);
                    nowStyle.left = Math.round(clientRect.left + pageXOffset);
                    arrow.left = Math.round((clientRect.width - arrowClientRect.width) / 2);
                    break;
                case 2:
                    // topRight
                    //transformX = -tooltipClientRect.width + clientRect.width;
                    transformY = -clientRect.height + translate;
                    nowStyle.transform = 'translate(0, -' + translate + 'px)';
                    nowStyle.bottom = -Math.round(pageYOffset + clientRect.bottom + transformY);
                    nowStyle.right = Math.round(clientWidth - pageXOffset - clientRect.right);
                    arrow.left = Math.round(tooltipClientRect.width - (clientRect.width + arrowClientRect.width) / 2);
                    break;
                case 3:
                    // bottom
                    transformX = (-tooltipClientRect.width + clientRect.width) / 2;
                    transformY = clientRect.height - translate;
                    nowStyle.top = Math.round(pageYOffset + clientRect.top + transformY);
                    nowStyle.left = Math.round(pageXOffset + clientRect.left + transformX);
                    nowStyle.transform = 'translate(0, ' + translate + 'px)';
                    break;
                case 4:
                    // bottomLeft
                    transformY = clientRect.height - translate;
                    nowStyle.transform = 'translate(0, ' + translate + 'px)';
                    nowStyle.top = Math.round(pageYOffset + clientRect.top + transformY);
                    nowStyle.left = Math.round(clientRect.left + pageXOffset + transformX);
                    arrow.left = Math.round((clientRect.width - arrowClientRect.width) / 2);
                    break;
                case 5:
                    // bottomRight
                    transformY = clientRect.height - translate;
                    nowStyle.transform = 'translate(0, ' + translate + 'px)';
                    nowStyle.top = Math.round(pageYOffset + clientRect.top + transformY);
                    nowStyle.right = Math.round(clientWidth - pageXOffset - clientRect.right);
                    arrow.left = Math.round(tooltipClientRect.width - (clientRect.width + arrowClientRect.width) / 2);
                    break;
                case 6:
                    // left
                    transformY = -(tooltipClientRect.height - clientRect.height) / 2;
                    nowStyle.top = Math.round(pageYOffset + clientRect.top + transformY);
                    nowStyle.right = Math.round(clientWidth - pageXOffset - clientRect.left - translate);
                    nowStyle.transform = 'translate(-' + translate + 'px, 0)';
                    break;
                case 7:
                    // leftTop
                    nowStyle.top = Math.round(pageYOffset + clientRect.top);
                    nowStyle.right = Math.round(clientWidth - pageXOffset - clientRect.left - translate);
                    nowStyle.transform = 'translate(-' + translate + 'px, 0)';
                    arrow.top = Math.round((clientRect.height - arrowClientRect.height) / 2);
                    break;
                case 8:
                    // leftBottom
                    //transformY = -clientRect.height + translate;
                    //transformX = -translate;
                    nowStyle.bottom = -Math.round(pageYOffset + clientRect.bottom);
                    nowStyle.right = Math.round(clientWidth - pageXOffset - clientRect.left - translate);
                    nowStyle.transform = 'translate(-' + translate + 'px, 0)';
                    arrow.bottom = Math.round((clientRect.height - arrowClientRect.height) / 2);
                    break;
                case 9:
                    // right
                    transformY = -(tooltipClientRect.height - clientRect.height) / 2;
                    nowStyle.top = Math.round(pageYOffset + clientRect.top + transformY);
                    nowStyle.left = Math.round(pageXOffset + clientRect.right);
                    nowStyle.transform = 'translate(' + translate + 'px, 0)';
                    transformX = clientRect.width - translate;
                    break;
                case 10:
                    // rightTop
                    transformX = clientRect.width - translate;
                    nowStyle.top = Math.round(pageYOffset + clientRect.top);
                    nowStyle.left = Math.round(pageXOffset + clientRect.left + transformX);
                    nowStyle.transform = 'translate(' + translate + 'px, 0)';
                    arrow.top = Math.round((clientRect.height - arrowClientRect.height) / 2);
                    break;
                case 11:
                    // rightBottom
                    transformX = clientRect.width - translate;
                    nowStyle.bottom = -Math.round(pageYOffset + clientRect.bottom);
                    nowStyle.left = Math.round(pageXOffset + clientRect.left + transformX);
                    nowStyle.transform = 'translate(' + translate + 'px, 0)';
                    arrow.bottom = Math.round((clientRect.height - arrowClientRect.height) / 2);
                    break;
                default:
                    return;
            }

            // bug fixed: 在ReactDOM.unstable_renderSubtreeIntoContainer挂载的时候
            // tooltip窗口内文字会莫名其妙的换行，导致首次定位出现错误
            // nowStyle.width = tooltipClientRect.width;

            _this.setState({
                style: omit(nowStyle, function (value) {
                    return value === null;
                }),
                arrow: arrow
            });
            //this.hasPosition = true;
        };

        _this.detectBoundary = function () {
            var _this$props = _this.props,
                position = _this$props.position,
                autoAdjustPosition = _this$props.autoAdjustPosition;

            if (!autoAdjustPosition && _this.triggerNode !== null) {
                return;
            }
            var _document$documentEle = document.documentElement,
                clientWidth = _document$documentEle.clientWidth,
                clientHeight = _document$documentEle.clientHeight;

            var clientRect = _this.triggerNode.getBoundingClientRect();
            var tooltipClientRect = _this.tooltipNode && _this.tooltipNode.getBoundingClientRect();
            var boundary = position.split(/(?=[A-Z])/g);

            var _boundary = _slicedToArray(boundary, 2),
                first = _boundary[0],
                _boundary$ = _boundary[1],
                second = _boundary$ === undefined ? 'center' : _boundary$;

            if (!tooltipClientRect) {
                return;
            }

            var horizontal = function horizontal(second) {
                var isInit = 0;
                second = second.toLowerCase();
                var func = {
                    left: function left() {
                        isInit++;
                        return clientRect.left + tooltipClientRect.width < clientWidth || isInit > 2 ? 'Left' : func.center();
                    },
                    center: function center() {
                        isInit++;
                        var ban = (tooltipClientRect.width - clientRect.width) / 2;
                        if (tooltipClientRect.width < clientWidth) {
                            if (clientRect.right + ban < clientWidth && clientRect.left > ban || isInit > 2) {
                                return 'center';
                            } else if (clientRect.left + clientRect.width / 2 > clientWidth / 2) {
                                return func.right();
                            } else {
                                return func.left();
                            }
                        }
                        return 'center';
                    },
                    right: function right() {
                        isInit++;
                        return clientRect.right > tooltipClientRect.width || isInit > 2 ? 'Right' : func.center();
                    }
                };
                return func[second]();
            };

            var vertical = function vertical(second) {
                var isInit = 0;
                second = second.toLowerCase();
                var func = {
                    top: function top() {
                        isInit++;
                        return clientRect.top + tooltipClientRect.height < clientHeight || isInit > 3 ? 'Top' : func.center();
                    },
                    center: function center() {
                        isInit++;
                        var ban = (tooltipClientRect.height - clientRect.height) / 2;
                        if (tooltipClientRect.height < clientHeight) {
                            if (clientRect.bottom + ban < clientHeight && clientRect.top > ban || isInit > 3) {
                                return 'center';
                            } else if (clientRect.top + clientRect.width / 2 > clientHeight / 2) {
                                return func.bottom();
                            } else {
                                return func.top();
                            }
                        }
                        return 'center';
                    },
                    bottom: function bottom() {
                        isInit++;
                        return clientRect.bottom > tooltipClientRect.height || isInit > 3 ? 'Bottom' : func.top();
                    }
                };
                return func[second]();
            };

            switch (first) {
                case 'top':
                    if (clientRect.top - tooltipClientRect.height < 0) {
                        first = 'bottom';
                    }
                    second = horizontal(second);
                    break;
                case 'left':
                    if (clientRect.left - tooltipClientRect.width < 0) {
                        first = 'right';
                    }
                    // top or bottom
                    second = vertical(second);
                    break;
                case 'bottom':
                    if (tooltipClientRect.height + clientRect.bottom > clientHeight) {
                        first = 'top';
                    }
                    second = horizontal(second);
                    break;
                case 'right':
                    if (tooltipClientRect.width + clientRect.left > clientWidth) {
                        first = 'left';
                    }
                    second = vertical(second);
                    break;
                default:
                    break;
            }

            if (first) {
                _this.setState({
                    position: [first, second.replace('center', '')].join('')
                });
            }
        };

        _this.handleOpen = function (e) {
            var _this$props2 = _this.props,
                onOpen = _this$props2.onOpen,
                trigger = _this$props2.trigger;

            if (trigger === 'none') {
                return;
            }

            var target = void 0;
            if (_this.contentNode) {
                target = _this.contentNode;
            } else {
                target = e.currentTarget;
            }
            _this.triggerNode = _this.contentNode || target;

            return Promise.resolve(e).then(function (e) {
                if (onOpen && !_this.hasOpened) {
                    _this.hasOpened = true;
                    return onOpen(e, _this.props);
                }
            }).then(function () {
                if (!_this.state.isOpen) {
                    _this.setState({ isOpen: true, style: { display: '' } });
                }
            }).then(function () {
                _this.setPosition();
            });
        };

        _this.handleClose = function (e) {
            var _this$props3 = _this.props,
                onClose = _this$props3.onClose,
                animationTime = _this$props3.animationTime;


            var prom = new Promise(function (reslove) {
                if (_this.state.isOpen) {
                    _this.setState({
                        style: extend(_this.state.style, {
                            transform: 'translate(0, 0)',
                            opacity: 0
                        })
                    });
                    setTimeout(reslove, animationTime || 0);
                }
            });
            // bug fixed: 必须返回，才有动画
            return Promise.resolve(e).then(function () {
                if (onClose) {
                    return onClose(e, _this.props);
                }
            }).then(function () {
                return prom;
            }).then(function () {
                //this.hasPosition = false;
                _this.hasOpened = false;
                if (_this.state && _this.state.isOpen) {
                    _this.setState({
                        isOpen: false,
                        style: { display: 'none' }
                    });
                }
            });
        };

        _this.handleMount = function (e) {
            var _this$props4 = _this.props,
                onMount = _this$props4.onMount,
                isScrollClose = _this$props4.isScrollClose;

            if (onMount) onMount(e, _this.props);
            _this.onResize = addEventListener(window, 'resize', throttle(_this.setPosition, 60));
            _this.onScroll = addEventListener(window, 'scroll', isScrollClose ? function (e) {
                _this.handleClose(e);
                if (_this.onScroll) {
                    _this.onScroll.remove();
                    _this.onScroll = null;
                }
            } : throttle(_this.setPosition, 60));
        };

        _this.handleUnmount = function (e) {
            var onUnmount = _this.props.onUnmount;
            //this.hasPosition = false;

            _this.triggerNode = null;
            _this.tooltipClientRect = null;
            _this.arrowClientRect = null;
            if (_this.onScroll) {
                _this.onScroll.remove();
                _this.onScroll = null;
            }
            if (_this.onResize) {
                _this.onResize.remove();
                _this.onResize = null;
            }

            _this.setState({
                style: {}
            });
            if (onUnmount) onUnmount(e, _this.props);
        };

        _this.handleRef = function (tooltip) {
            var prefixCls = _this.props.prefixCls;

            _this.tooltipNode = tooltip;
            _this.tooltipClientRect = tooltip ? tooltip.getBoundingClientRect() : null;
            _this.arrowClientRect = tooltip ? tooltip.querySelector('.' + prefixCls + '-arrow').getBoundingClientRect() : null;
        };

        _this.handleContentRef = function (content) {
            _this.contentNode = content;
        };

        _this.hasOpened = false;
        _this.hasPosition = false;
        _this.state = {
            isOpen: props.isOpen,
            style: {
                top: null,
                left: null,
                width: null,
                transform: null,
                opacity: 0,
                display: 'none'
            },
            arrow: {
                left: null,
                top: null
            },
            position: props.position
        };
        _this.updateTriggerEvent();
        return _this;
    }

    _createClass(Tooltip, [{
        key: 'componentWillReceiveProps',
        value: function componentWillReceiveProps(newProps) {
            if (newProps.isOpen !== this.state.isOpen && this.props.isOpen !== newProps.isOpen) {
                this.updateTriggerEvent();
                if (newProps.isOpen) {
                    this.handleOpen();
                } else {
                    this.handleClose();
                }
            }
        }

        // shouldComponentUpdate(nextProps, nextState) {
        //     // 打开／将要状态下 或 content 发生改变
        //     return this.state.isOpen || nextState.isOpen || this.props.content !== nextProps.content;
        // }

        // 检测边界

    }, {
        key: 'render',
        value: function render() {
            var _this2 = this;

            var _props = this.props,
                content = _props.content,
                trigger = _props.trigger,
                prefixCls = _props.prefixCls,
                children = _props.children,
                className = _props.className,
                title = _props.title,
                style = _props.style,
                animationTime = _props.animationTime,
                other = _objectWithoutProperties(_props, ['content', 'trigger', 'prefixCls', 'children', 'className', 'title', 'style', 'animationTime']);

            var position = this.state.position;


            var omitProps = [];

            Object.keys(this.triggerEvent).forEach(function (key) {
                omitProps.push(key);
                if (isBoolean(other[key])) {
                    _this2.triggerEvent[key] = other[key];
                }
            });

            var classes = classNames('tooltip-base', prefixCls, _defineProperty({}, prefixCls + '-position-' + position, position), className);

            var tooltip = React.createElement(
                'div',
                {
                    className: classes,
                    style: extend({
                        transition: 'all ' + animationTime / 1000 + 's'
                    }, this.state.style, style),
                    ref: this.handleRef, __source: {
                        fileName: _jsxFileName,
                        lineNumber: 559
                    },
                    __self: this
                },
                React.createElement('div', { className: prefixCls + '-arrow', style: this.state.arrow, __source: {
                        fileName: _jsxFileName,
                        lineNumber: 569
                    },
                    __self: this
                }),
                React.createElement(
                    'div',
                    { className: prefixCls + '-inner', __source: {
                            fileName: _jsxFileName,
                            lineNumber: 570
                        },
                        __self: this
                    },
                    title && React.createElement(
                        'div',
                        { className: prefixCls + '-header', __source: {
                                fileName: _jsxFileName,
                                lineNumber: 571
                            },
                            __self: this
                        },
                        title
                    ),
                    children && React.createElement(
                        'div',
                        { className: prefixCls + '-content', __source: {
                                fileName: _jsxFileName,
                                lineNumber: 572
                            },
                            __self: this
                        },
                        children
                    )
                )
            );

            return React.createElement(
                Box,
                Object.assign({}, omit(other, ['children', 'className', 'prefixCls', 'trigger', 'isOpen', 'style', 'position'].concat(omitProps)), omit(this.triggerEvent, []), {
                    trigger: content,
                    triggerRef: this.handleContentRef,
                    className: 'tooltip-base-box ' + prefixCls + '-box',
                    isOpen: this.state.isOpen,
                    onOpen: this.handleOpen,
                    onClose: this.handleClose,
                    onMount: this.handleMount,
                    onUnmount: this.handleUnmount, __source: {
                        fileName: _jsxFileName,
                        lineNumber: 578
                    },
                    __self: this
                }),
                tooltip
            );
        }
    }]);

    return Tooltip;
}(React.Component);

Tooltip.propTypes = {
    /** @ignore*/
    children: PropTypes.node,
    /**
     * 触发方式
     * */
    trigger: PropTypes.oneOf(['click', 'hover', 'focus', 'none']),
    /**
     * 提示框标题
     * */
    title: PropTypes.node,
    /**
     * 触发提示框的Node，接受的数据类型是PropTypes.node
     * */
    content: PropTypes.node,
    /**
     * 用于手动控制提示框显隐
     * */
    isOpen: PropTypes.bool,
    /**
     * 提示框是否在页面滚动的时候关闭
     * */
    isScrollClose: PropTypes.bool,
    // isCacheInNodeTree: PropTypes.bool,
    /**
     * 点击提示框外层是否关闭
     * */
    isCloseOnDocumentClick: PropTypes.bool,
    /**
     * 气泡被遮挡时是否自动调整定位
     * */
    autoAdjustPosition: PropTypes.bool,
    /**
     * 显示样式
     * */
    style: PropTypes.object,
    /**
     * 显示类名
     * */
    className: PropTypes.string,
    /**
     * 提示框位置
     * */
    position: PropTypes.oneOf(POSITIONS),
    /** 提示框距离trigger元素的偏移距离，单位是像素（px）*/
    translate: PropTypes.number,
    /** 鼠标移入时延迟时间*/
    mouseEnterDelay: PropTypes.number,
    /** 鼠标移出时延迟时间*/
    mouseLeaveDelay: PropTypes.number,
    /** 动画执行时间*/
    animationTime: PropTypes.number,
    /** 关闭回调*/
    onClose: PropTypes.func
};
Tooltip.defaultProps = defaultProps;


export default Tooltip;