<template>
    <div class="wook-gantt">
        <div class="gantt-left" :style="{width:menuWidth+'px'}">
            <div class="gantt-title">
                <div class="gantt-title-text">{{$L('任务名称')}}</div>
            </div>
            <ul ref="ganttItem"
                class="gantt-item"
                @scroll="itemScrollListener"
                @mouseenter="mouseType='item'">
                <li v-for="(item, key) in lists" :key="key">
                    <div v-if="item.overdue" class="item-overdue" @click="clickItem(item)">{{$L('已超期')}}</div>
                    <div class="item-title" :class="{complete:item.complete, overdue:item.overdue}" @click="clickItem(item)">{{item.label}}</div>
                    <Icon class="item-icon" type="ios-locate-outline" @click="scrollPosition(key)"/>
                </li>
            </ul>
        </div>
        <div ref="ganttRight" class="gantt-right">
            <div class="gantt-chart">
                <ul class="gantt-month">
                    <li v-for="(item, key) in monthNum" :key="key" :style="monthStyle(key)">
                        <div class="month-format">{{monthFormat(key)}}</div>
                    </li>
                </ul>
                <ul class="gantt-date" @mousedown="dateMouseDown">
                    <li v-for="(item, key) in dateNum" :key="key" :style="dateStyle(key)">
                        <div class="date-format">
                            <div class="format-day">{{dateFormat(key, 'day')}}</div>
                            <div v-if="dateWidth > 46" class="format-wook">{{dateFormat(key, 'wook')}}</div>
                        </div>
                    </li>
                </ul>
                <ul ref="ganttTimeline"
                    class="gantt-timeline"
                    @scroll="timelineScrollListener"
                    @mouseenter="mouseType='timeline'">
                    <li v-for="(item, key) in lists" :key="key">
                        <div
                            class="timeline-item"
                            :style="itemStyle(item)"
                            @mousedown="itemMouseDown($event, item)">
                            <div class="timeline-title">{{item.label}}</div>
                            <div class="timeline-resizer"></div>
                        </div>
                    </li>
                </ul>
            </div>
        </div>
    </div>
</template>

<script>
export default {
    name: 'GanttView',
    props: {
        lists: {
            type: Array
        },
        menuWidth: {
            type: Number,
            default: 300
        },
        itemWidth: {
            type: Number,
            default: 100
        }
    },
    data() {
        return {
            mouseType: '',
            mouseWidth: 0,
            mouseScaleWidth: 0,

            dateWidth: 100,
            ganttWidth: 0,

            mouseItem: null,
            mouseBak: {},

            dateMove: null
        }
    },
    mounted() {
        this.dateWidth = this.itemWidth;
        this.$refs.ganttRight.addEventListener('mousewheel', this.handleScroll, false);
        document.addEventListener('mousemove', this.itemMouseMove);
        document.addEventListener('mouseup', this.itemMouseUp);
        window.addEventListener("resize", this.handleResize, false);
        this.handleResize();
    },
    beforeDestroy() {
        this.$refs.ganttRight.removeEventListener('mousewheel', this.handleScroll, false);
        document.removeEventListener('mousemove', this.itemMouseMove);
        document.removeEventListener('mouseup', this.itemMouseUp);
        window.removeEventListener("resize", this.handleResize, false);
    },
    watch: {
        itemWidth(val) {
            this.dateWidth = val;
        }
    },
    computed: {
        monthNum() {
            const {ganttWidth, dateWidth} = this;
            return Math.floor(ganttWidth / dateWidth / 30) + 2
        },
        monthStyle() {
            const {mouseWidth, dateWidth} = this;
            return function(index) {
                let mouseDay = mouseWidth == 0 ? 0 : mouseWidth / dateWidth;
                let date = new Date();
                //今天00:00:00
                let nowDay = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
                //当前时间
                let curDay = new Date(nowDay.getTime() + mouseDay * 86400000);
                //当月最后一天
                let lastDay = new Date(curDay.getFullYear(), curDay.getMonth() + 1, 0, 23, 59, 59);
                //相差天数
                let diffDay = (lastDay - curDay)  / 1000 / 60 / 60 / 24;
                //
                let width = dateWidth * diffDay;
                if (index > 0) {
                    lastDay = new Date(curDay.getFullYear(), curDay.getMonth() + 1 + index, 0);
                    width = lastDay.getDate() * dateWidth;
                }
                return {
                    width: width + 'px',
                }
            }
        },
        monthFormat() {
            const {mouseWidth, dateWidth} = this;
            return function(index) {
                let mouseDay = mouseWidth == 0 ? 0 : mouseWidth / dateWidth;
                let date = new Date();
                //开始位置时间（今天00:00:00）
                let nowDay = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
                //当前时间
                let curDay = new Date(nowDay.getTime() + mouseDay * 86400000);
                //
                if (index > 0) {
                    curDay = new Date(curDay.getFullYear(), curDay.getMonth() + 1 + index, 0);
                }
                return $A.formatDate("Y-m", curDay)
            }
        },
        dateNum() {
            const {ganttWidth, dateWidth} = this;
            return Math.floor(ganttWidth / dateWidth) + 2
        },
        dateStyle() {
            const {mouseWidth, dateWidth} = this;
            return function(index) {
                const style = {};
                //
                let mouseDay = mouseWidth == 0 ? 0 : mouseWidth / dateWidth;
                let mouseData = Math.floor(mouseDay) + index;
                if (mouseDay == Math.floor(mouseDay)) {
                    mouseData--;
                }
                let j = mouseWidth == 0 ? index - 1 : mouseData;
                let date = new Date(new Date().getTime() + j * 86400000);
                if ([0, 6].indexOf(date.getDay()) !== -1) {
                    style.backgroundColor = '#f9fafb';
                }
                //
                let width = dateWidth;
                if (index == 0) {
                    width = Math.abs((mouseWidth % width - width) % width);
                }
                style.width = width + 'px';
                return style
            }
        },
        dateFormat() {
            const {mouseWidth, dateWidth} = this;
            return function(index, type) {
                let mouseDay = mouseWidth == 0 ? 0 : mouseWidth / dateWidth;
                let mouseData = Math.floor(mouseDay) + index;
                if (mouseDay == Math.floor(mouseDay)) {
                    mouseData--;
                }
                let j = mouseWidth == 0 ? index - 1 : mouseData;
                let date = new Date(new Date().getTime() + j * 86400000)
                if (type == 'day') {
                    return date.getDate();
                } else if (type == 'wook') {
                    return this.$L(`星期${'日一二三四五六'.charAt(date.getDay())}`);
                } else {
                    return date;
                }
            }
        },
        itemStyle() {
            const {mouseWidth, dateWidth, ganttWidth} = this;
            return function(item) {
                const {start, end} = item.time;
                const {style, moveX, moveW} = item;
                let date = new Date();
                //开始位置时间戳（今天00:00:00时间戳）
                let nowTime = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0).getTime();
                //距离开始位置多少天
                let diffStartDay = (start - nowTime) / 1000 / 60 / 60 / 24;
                let diffEndDay = (end - nowTime) / 1000 / 60 / 60 / 24;
                //
                let left = dateWidth * diffStartDay + (mouseWidth * -1);
                let width = dateWidth * (diffEndDay - diffStartDay);
                if (typeof moveX === "number") {
                    left+= moveX;
                }
                if (typeof moveW === "number") {
                    width+= moveW;
                }
                //
                const customStyle = {
                    left: Math.min(Math.max(left, width * -1.2), ganttWidth * 1.2).toFixed(2) + 'px',
                    width: width.toFixed(2) + 'px',
                };
                if (left < 0 && Math.abs(left) < width) {
                    customStyle.paddingLeft = Math.abs(left).toFixed(2) + 'px'
                }
                if (left + width > ganttWidth && left < ganttWidth) {
                    customStyle.paddingRight = Math.abs(left + width - ganttWidth).toFixed(2) + 'px'
                }
                if (typeof style === "object") {
                    return Object.assign(customStyle, style);
                }
                return customStyle
            }
        }
    },
    methods: {
        itemScrollListener(e) {
            if (this.mouseType == 'timeline') {
                return;
            }
            this.$refs.ganttTimeline.scrollTop = e.target.scrollTop;
        },
        timelineScrollListener(e) {
            if (this.mouseType == 'item') {
                return;
            }
            this.$refs.ganttItem.scrollTop = e.target.scrollTop;
        },
        handleScroll(e) {
            e.preventDefault();
            if (e.ctrlKey) {
                //缩放
                this.dateWidth = Math.min(600, Math.max(24, this.dateWidth - Math.floor(e.deltaY)));
                this.mouseWidth = this.ganttWidth / 2 * ((this.dateWidth - 100) / 100) + this.dateWidth / 100 * this.mouseScaleWidth;
                return;
            }
            if (e.deltaY != 0) {
                const ganttTimeline = this.$refs.ganttTimeline;
                let newTop = ganttTimeline.scrollTop + e.deltaY;
                if (newTop < 0) {
                    newTop = 0;
                } else if (newTop > ganttTimeline.scrollHeight - ganttTimeline.clientHeight) {
                    newTop = ganttTimeline.scrollHeight - ganttTimeline.clientHeight;
                }
                if (ganttTimeline.scrollTop != newTop) {
                    this.mouseType = 'timeline';
                    ganttTimeline.scrollTop = newTop;
                }
            }
            if (e.deltaX != 0) {
                this.mouseWidth+= e.deltaX;
                this.mouseScaleWidth+= e.deltaX * (100 / this.dateWidth);
            }
        },
        handleResize() {
            this.ganttWidth = this.$refs.ganttTimeline.clientWidth;
        },
        dateMouseDown(e) {
            e.preventDefault();
            this.mouseItem = null;
            this.dateMove = {
                clientX: e.clientX
            };
        },
        itemMouseDown(e, item) {
            e.preventDefault();
            let type = 'moveX';
            if (e.target.className == 'timeline-resizer') {
                type = 'moveW';
            }
            if (typeof item[type] !== "number") {
                this.$set(item, type, 0);
            }
            this.mouseBak = {
                type: type,
                clientX: e.clientX,
                value: item[type],
                time: item.time,
            };
            this.mouseItem = item;
            this.dateMove = null;
        },
        itemMouseMove(e) {
            if (this.mouseItem != null) {
                e.preventDefault();
                var diff = e.clientX - this.mouseBak.clientX;
                const {start, end} = this.mouseBak.time;
                let date = new Date();
                let nowTime = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0).getTime();
                let diffStartDay = (start - nowTime) / 1000 / 60 / 60 / 24;
                let diffEndDay = (end - nowTime) / 1000 / 60 / 60 / 24;
                let width = this.dateWidth * (diffEndDay - diffStartDay);
                width += this.mouseBak.value + diff;
                if (width <= 0) {
                    return false;
                }
                this.$set(this.mouseItem, this.mouseBak.type, this.mouseBak.value + diff);
            } else if (this.dateMove != null) {
                e.preventDefault();
                let moveX = (this.dateMove.clientX - e.clientX) * 5;
                this.dateMove.clientX = e.clientX;
                this.mouseWidth+= moveX;
                this.mouseScaleWidth+= moveX * (100 / this.dateWidth);
            }
        },
        itemMouseUp(e) {
            if (this.mouseItem != null) {
                const {start, end} = this.mouseItem.time;
                let isM = false;
                //一个宽度的时间
                let oneWidthTime = 86400000 / this.dateWidth;
                //修改起止时间
                if (typeof this.mouseItem.moveX === "number" && this.mouseItem.moveX != 0) {
                    let moveTime = this.mouseItem.moveX * oneWidthTime;
                    this.$set(this.mouseItem.time, 'start', start + moveTime);
                    this.$set(this.mouseItem.time, 'end', end + moveTime);
                    this.$set(this.mouseItem, 'moveX', 0);
                    isM = true;
                }
                //修改结束时间
                if (typeof this.mouseItem.moveW === "number" && this.mouseItem.moveW != 0) {
                    let moveTime = this.mouseItem.moveW * oneWidthTime;
                    this.$set(this.mouseItem.time, 'end', end + moveTime);
                    this.$set(this.mouseItem, 'moveW', 0);
                    isM = true;
                }
                if (this.mouseItem.time && this.mouseItem.time.start > this.mouseItem.time.end) {
                    return false;
                }
                //
                if (isM) {
                    this.$emit("on-change", this.mouseItem)
                } else if (e.target.className == 'timeline-title') {
                    this.clickItem(this.mouseItem);
                }
                this.mouseItem = null;
            } else if (this.dateMove != null) {
                this.dateMove = null;
            }
        },
        scrollPosition(pos) {
            let date = new Date();
            //今天00:00:00
            let nowDay = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
            //一个宽度的时间
            let oneWidthTime = 86400000 / this.dateWidth;
            //
            let moveWidth = (this.lists[pos].time.start - nowDay) / oneWidthTime - this.dateWidth - this.mouseWidth;
            this.mouseWidth+= moveWidth;
            this.mouseScaleWidth+= moveWidth * (100 / this.dateWidth);
        },
        clickItem(item) {
            this.$emit("on-click", item)
        }
    }
}
</script>
