<template>
  <div ref="outerWrapper" :class="wrapperClasses">
    <div v-if="isHorizontal" :class="`${prefix}-horizontal`">
      <div :style="{right: `${anotherOffset}%`}" :class="[`${prefix}-pane`, 'left-pane']"><slot name="left"/></div>
      <div :class="`${prefix}-trigger-con`" :style="{left: `${offset}%`}" @mousedown="handleMousedown">
        <slot name="trigger">
          <trigger mode="vertical"/>
        </slot>
      </div>
      <div :style="{left: `${offset}%`}" :class="[`${prefix}-pane`, 'right-pane']"><slot name="right"/></div>
    </div>
    <div v-else :class="`${prefix}-vertical`">
      <div :style="{bottom: `${anotherOffset}%`}" :class="[`${prefix}-pane`, 'top-pane']"><slot name="top"/></div>
     <div :class="`${prefix}-trigger-con`" :style="{top: `${offset}%`}" @mousedown="handleMousedown">
        <slot name="trigger">
          <trigger mode="horizontal"/>
        </slot>
      </div>
      <div :style="{top: `${offset}%`}" :class="[`${prefix}-pane`, 'bottom-pane']"><slot name="bottom"/></div>
    </div>
  </div>
</template>

<script>
import { oneOf, on, off } from '@/libs/tools'
import Trigger from './trigger.vue'
export default {
    name: 'SplitPane',
    components: {
        Trigger
    },
    props: {
        value: {
            type: [Number, String],
            default: 0.5
        },
        mode: {
            validator (value) {
                return oneOf(value, ['horizontal', 'vertical'])
            },
            default: 'horizontal'
        },
        min: {
            type: [Number, String],
            default: '40px'
        },
        max: {
            type: [Number, String],
            default: '40px'
        }
    },
    /**
   * Events
   * @on-move-start
   * @on-moving 返回值：事件对象，但是在事件对象中加入了两个参数：atMin(当前是否在最小值处), atMax(当前是否在最大值处)
   * @on-move-end
   */
    data () {
        return {
            prefix: 'ivu-split',
            offset: 0,
            oldOffset: 0,
            isMoving: false
        }
    },
    computed: {
        wrapperClasses () {
            return [
                `${this.prefix}-wrapper`,
                this.isMoving ? 'no-select' : ''
            ]
        },
        isHorizontal () {
            return this.mode === 'horizontal'
        },
        anotherOffset () {
            return 100 - this.offset
        },
        valueIsPx () {
            return typeof this.value === 'string'
        },
        offsetSize () {
            return this.isHorizontal ? 'offsetWidth' : 'offsetHeight'
        },
        computedMin () {
            return this.getComputedThresholdValue('min')
        },
        computedMax () {
            return this.getComputedThresholdValue('max')
        }
    },
    methods: {
        px2percent (numerator, denominator) {
            return parseFloat(numerator) / parseFloat(denominator)
        },
        getComputedThresholdValue (type) {
            let size = this.$refs.outerWrapper[this.offsetSize]
            if (this.valueIsPx) return typeof this[type] === 'string' ? this[type] : size * this[type]
            else return typeof this[type] === 'string' ? this.px2percent(this[type], size) : this[type]
        },
        getMin (value1, value2) {
            if (this.valueIsPx) return `${Math.min(parseFloat(value1), parseFloat(value2))}px`
            else return Math.min(value1, value2)
        },
        getMax (value1, value2) {
            if (this.valueIsPx) return `${Math.max(parseFloat(value1), parseFloat(value2))}px`
            else return Math.max(value1, value2)
        },
        getAnotherOffset (value) {
            let res = 0
            if (this.valueIsPx) res = `${this.$refs.outerWrapper[this.offsetSize] - parseFloat(value)}px`
            else res = 1 - value
            return res
        },
        handleMove (e) {
            let pageOffset = this.isHorizontal ? e.pageX : e.pageY
            let offset = pageOffset - this.initOffset
            let outerWidth = this.$refs.outerWrapper[this.offsetSize]
            let value = this.valueIsPx ? `${parseFloat(this.oldOffset) + offset}px` : (this.px2percent(outerWidth * this.oldOffset + offset, outerWidth))
            let anotherValue = this.getAnotherOffset(value)
            if (parseFloat(value) <= parseFloat(this.computedMin)) value = this.getMax(value, this.computedMin)
            if (parseFloat(anotherValue) <= parseFloat(this.computedMax)) value = this.getAnotherOffset(this.getMax(anotherValue, this.computedMax))
            e.atMin = this.value === this.computedMin
            e.atMax = this.valueIsPx ? this.getAnotherOffset(this.value) === this.computedMax : this.getAnotherOffset(this.value).toFixed(5) === this.computedMax.toFixed(5)
            this.$emit('input', value)
            this.$emit('on-moving', e)
        },
        handleUp () {
            this.isMoving = false
            off(document, 'mousemove', this.handleMove)
            off(document, 'mouseup', this.handleUp)
            this.$emit('on-move-end')
        },
        handleMousedown (e) {
            this.initOffset = this.isHorizontal ? e.pageX : e.pageY
            this.oldOffset = this.value
            this.isMoving = true
            on(document, 'mousemove', this.handleMove)
            on(document, 'mouseup', this.handleUp)
            this.$emit('on-move-start')
        }
    },
    watch: {
        value () {
            this.offset = (this.valueIsPx ? this.px2percent(this.value, this.$refs.outerWrapper[this.offsetSize]) : this.value) * 10000 / 100
        }
    },
    mounted () {
        this.$nextTick(() => {
            this.offset = (this.valueIsPx ? this.px2percent(this.value, this.$refs.outerWrapper[this.offsetSize]) : this.value) * 10000 / 100
        })
    }
}
</script>

<style lang="less">
@import './index.less';
</style>
