<script type="text/jsx">
import MenuMixin from 'element-ui/packages/menu/src/menu-mixin'
import Emitter from 'element-ui/lib/mixins/emitter'
import Popper from 'element-ui/lib/utils/vue-popper'

const PopperMixin = {
    props: {
        transformOrigin: {type: [Boolean, String], default: false},
        offset: Popper.props.offset,
        boundariesPadding: Popper.props.boundariesPadding,
        popperOptions: Popper.props.popperOptions
    },
    data: Popper.data,
    methods: Popper.methods,
    beforeDestroy: Popper.beforeDestroy,
    deactivated: Popper.deactivated
}

export default {
    name: 'ElSubmenu',

    componentName: 'ElSubmenu',

    mixins: [MenuMixin, Emitter, PopperMixin],

    props: {
        index: String,
        showTimeout: {type: Number, default: 300},
        hideTimeout: {type: Number, default: 300},
        popperClass: String,
        disabled: Boolean,
        popperAppendToBody: {type: Boolean, default: true}
    },

    data() {
        return {
            popperJS: null,
            timeout: null,
            items: {},
            submenus: {},
            mouseInChild: false
        }
    },

    computed: {
        appendToBody() {
            return this.popperAppendToBody === undefined
                ? this.isFirstLevel
                : this.popperAppendToBody
        },
        menuTransitionName() {
            return this.rootMenu.collapse ? 'el-zoom-in-left' : 'el-zoom-in-top'
        },
        opened() {
            return this.rootMenu.openedMenus.includes(this.index)
        },
        active() {
            const active = Object.values(this.items).some(v => v.active)
            return active || Object.values(this.submenus).some(v => v.active)
        },
        mode() {
            return this.rootMenu.mode
        },
        isMenuPopup() {
            return this.rootMenu.isMenuPopup
        },
        isFirstLevel() {
            const arr = ['ElSubmenu', 'ElMenuItemGroup']
            let isFirstLevel = true
            let parent = this.$parent

            while (parent && parent !== this.rootMenu) {
                if (arr.includes(parent.$options.componentName)) {
                    isFirstLevel = false
                    break
                }
                else parent = parent.$parent
            }
            return isFirstLevel
        }
    },

    watch: {
        opened() {
            this.isMenuPopup && this.$nextTick(this.updatePopper)
        }
    },

    methods: {
        handleCollapseToggle(value) {
            value ? this.initPopper() : this.doDestroy()
        },

        addItem(item) {
            this.$set(this.items, item.index, item)
        },
        removeItem(item) {
            delete this.items[item.index]
        },
        addSubmenu(item) {
            this.$set(this.submenus, item.index, item)
        },
        removeSubmenu(item) {
            delete this.submenus[item.index]
        },

        handleClick() {
            const {rootMenu, disabled} = this
            if (
                (rootMenu.menuTrigger === 'hover' && rootMenu.mode === 'horizontal') ||
                (rootMenu.collapse && rootMenu.mode === 'vertical') ||
                disabled
            ) {
                return
            }
            this.dispatch('ElMenu', 'submenu-click', this)
        },

        handleMouseenter(event, showTimeout = this.showTimeout) {
            if (!('ActiveXObject' in window) && event.type === 'focus' && !event.relatedTarget) {
                return
            }

            const {rootMenu, disabled} = this

            if (rootMenu.menuTrigger === 'click' && rootMenu.mode === 'horizontal'
                || !rootMenu.collapse && rootMenu.mode === 'vertical'
                || disabled) return

            this.dispatch('ElSubmenu', 'mouse-enter-child')

            clearTimeout(this.timeout)
            this.timeout = setTimeout(() => this.rootMenu.openMenu(this.index, this.indexPath), showTimeout)

            this.appendToBody && this.$parent.$el.dispatchEvent(new MouseEvent('mouseenter'))
        },

        handleMouseleave(deepDispatch = false) {
            const {rootMenu} = this

            if (rootMenu.menuTrigger === 'click' && rootMenu.mode === 'horizontal'
                || !rootMenu.collapse && rootMenu.mode === 'vertical') return

            this.dispatch('ElSubmenu', 'mouse-leave-child')

            clearTimeout(this.timeout)
            this.timeout = setTimeout(() => !this.mouseInChild && this.rootMenu.closeMenu(this.index), this.hideTimeout)

            if (this.appendToBody && deepDispatch) {
                if (this.$parent.$options.name === 'ElSubmenu') {
                    this.$parent.handleMouseleave(true)
                }
            }
        },

        updatePlacement() {
            this.placement = this.mode === 'horizontal' && this.isFirstLevel
                ? 'bottom-start'
                : 'right-start'
        },

        initPopper() {
            this.referenceElm = this.$el
            this.popperElm = this.$refs.menu
            this.updatePlacement()
        }
    },

    created() {
        this.$on('toggle-collapse', this.handleCollapseToggle)
        this.$on('mouse-enter-child', () => {
            this.mouseInChild = true
            clearTimeout(this.timeout)
        })
        this.$on('mouse-leave-child', () => {
            this.mouseInChild = false
            clearTimeout(this.timeout)
        })
    },

    mounted() {
        this.parentMenu.addSubmenu(this)
        this.rootMenu.addSubmenu(this)
        this.initPopper()
    },

    beforeDestroy() {
        this.parentMenu.removeSubmenu(this)
        this.rootMenu.removeSubmenu(this)
    },

    render() {
        const {rootMenu, $slots} = this

        const popupMenu = (
            <transition name={this.menuTransitionName}>
                <div
                    ref="menu"
                    v-show={this.opened}
                    class={[`el-menu--${this.mode}`, this.popperClass]}
                    on-mouseenter={e => this.handleMouseenter(e, 100)}
                    on-mouseleave={() => this.handleMouseleave(true)}
                    on-focus={e => this.handleMouseenter(e, 100)}>
                    <ul class={['el-menu el-menu--popup', `el-menu--popup-${this.currentPlacement}`]}>
                        {$slots.default}
                    </ul>
                </div>
            </transition>
        )

        const inlineMenu = (
            <el-collapse-transition>
                <ul v-show={this.opened} class="el-menu el-menu--inline">
                    {$slots.default}
                </ul>
            </el-collapse-transition>
        )

        const submenuTitleIcon = (
            rootMenu.mode === 'horizontal' && this.isFirstLevel ||
            rootMenu.mode === 'vertical' && !rootMenu.collapse
        ) ? 'el-icon-arrow-down' : 'el-icon-arrow-right'

        return (
            <li
                class={{
                    'el-submenu': true,
                    'is-active': this.active,
                    'is-opened': this.opened,
                    'is-disabled': this.disabled
                }}
                on-mouseenter={this.handleMouseenter}
                on-mouseleave={() => this.handleMouseleave(false)}
                on-focus={this.handleMouseenter}
            >
                <div
                    ref="submenu-title"
                    class="el-submenu__title"
                    style={this.paddingStyle}
                    on-click={this.handleClick}
                >
                    {$slots.title}
                    <i class={['el-submenu__icon-arrow', submenuTitleIcon]}/>
                </div>
                {this.isMenuPopup ? popupMenu : inlineMenu}
            </li>
        )
    }
}
</script>
