<template>
    <div :class="prefixCls">
        <Input ref="input" placeholder="请输入..." style="width: 300px" v-if="searchable"  @on-change="search" v-model="value" />
        <!--<div :class="[prefixCls + '-arrow-box']">
            <Icon type="ios-close" :class="[prefixCls + '-close']" v-show="showCloseIcon" @click.native="clearSingleSelect"></Icon>
        </div>-->
        <template v-for="(item, index) in objData">
            <Tree-node :contentEditable="contentEditable" :editedEnd="editedEnd" :onTitleChange="onItemTitleChange" :key="index" :data="item" visible :multiple="multiple" :show-checkbox="showCheckbox" :draggable="draggable" :cascade="cascade" :withCheckAll="withCheckAll" @customDragstart="customDragstart" @customDrop="customDrop" :lazy="lazy" :load="load" :handleNewNodeLoaded="foreachMakeDataInfo" :setParentLazyLoading="setParentLazyLoading">
            </Tree-node>
        </template>
        <div :class="[prefixCls + '-empty']" v-if="!objData.length">{{ localeEmptyText }}</div>
    </div>
</template>
<script>
    import TreeNode from './node.vue';
    import { findComponentsDownward } from '../../utils/assist';
    import Emitter from '../../mixins/emitter';
    import Locale from '../../mixins/locale';

    const prefixCls = 'ivu-tree';

    export default {
        name: 'Tree',
        mixins: [Emitter, Locale],
        components: { TreeNode },
        props: {
            data: {
                type: Array,
                default() {
                    return [];
                }
            },
            fields: {
                type: Array,
                default() {
                    return []
                }
            },
            multiple: {
                type: Boolean,
                default: false
            },
            showCheckbox: {
                type: [Boolean, Object],
                default: false
            },
            cascade: {
                type: Boolean,
                default: false
            },
            searchable: {
                type: Boolean,
                default: false
            },
            draggable: {
                type: Boolean,
                default: false
            },
            emptyText: {
                type: String
            },
            withCheckAll: {
                type: Boolean,
                default: true
            },
            contentEditable: {
                type: Boolean,
                default: false
            },
            onItemTitleChange: {
                type: Function,
                default: () => { }
            },
            withParentChecked: {
                type: Boolean,
                default: false
            },
            // 是否懒加载
            lazy: {
                type: Boolean,
                default: false
            },
            // 懒加载节点获取函数
            load: {
                type: Function,
                default: (node, resolve) => {
                    // return (node, resolve) => {
                    return resolve([]);
                    // };
                }
            },
        },
        data() {
            return {
                showCloseIcon: false,
                objData: this.makeDataInfo(),
                prefixCls: prefixCls,
                value: "",
                dragstartItem: {},
                dropItem: {}
            };
        },
        computed: {
            localeEmptyText() {
                if (this.emptyText === undefined) {
                    return this.t('i.tree.emptyText');
                } else {
                    return this.emptyText;
                }
            },

        },
        methods: {
            // 点击清除文本框内容
            clearSingleSelect () {
                this.value  = ''
                this.resetAllAttribute(this.objData, "target", false);
                this.travalTree(this.objData, this.value)
                this.showCloseIcon = false
            },
            makeDataInfo() {
                let oData = JSON.parse(JSON.stringify(this.data));
                for (let row = 0; row < oData.length; row++) {
                    if (this.fields.length > 0) {
                        for (let i = 0; i < this.fields.length; i++) {
                            if (oData[row][this.fields[i].field] != undefined) {
                                oData[row][this.fields[i].map] = oData[row][this.fields[i].field];
                            }
                        }
                    }
                    if (oData[row].children != undefined && oData[row].children.length > 0) {
                        oData[row].hasChild = true;
                        this.foreachMakeDataInfo(oData[row].children)
                    } else {
                        oData[row].hasChild = false
                    }
                }
                this.setParent(null, oData)
                return oData
            },
            foreachMakeDataInfo: function(oData) {
                if (oData !== undefined && oData != null) {
                    for (let row = 0; row < oData.length; row++) {
                        if (this.fields.length > 0) {
                            for (let i = 0; i < this.fields.length; i++) {
                                if (oData[row][this.fields[i].field] != undefined) {
                                    oData[row][this.fields[i].map] = oData[row][this.fields[i].field];
                                }
                            }
                        }
                        if (oData[row].children != undefined && oData[row].children.length > 0) {
                            oData[row].hasChild = true;
                            this.foreachMakeDataInfo(oData[row].children)
                        } else {
                            oData[row].hasChild = false
                        }
                    }
                }
            },
            getSelectedNodes() {
                const nodes = findComponentsDownward(this, 'TreeNode');
                return nodes.filter(node => node.data.selected).map(node => node.data);
            },
            getCheckedNodes() {
                const nodes = findComponentsDownward(this, 'TreeNode');
                return nodes.filter(node => node.data.checked).map(node => node.data);
            },
            updateData(isInit = true, active = 'checked') {
                // init checked status
                let _this = this
                function reverseChecked(data) {
                    if (data.children && data.children.length > 0) {
                        let checkedLength = 0;
                        data.children.forEach(node => {
                            if (node.children) node = reverseChecked(node);
                            if (node[active]) checkedLength++;
                        });

                        if (isInit) {
                            if (checkedLength >= data.children.length) {
                                if (_this.cascade) {
                                    data.checked = true;
                                    _this.setAttribute(data, 'selected', true)
                                } else {
                                    _this.setAttribute(data, active, true)
                                }
                            }
                        } else {
                            if (_this.cascade) {
                                data.checked = checkedLength >= data.children.length;
                                data.selected = checkedLength >= data.children.length;
                            } else {
                                _this.setAttribute(data, active, checkedLength >= data.children.length)
                            }
                        }
                        return data;
                    } else {
                        return data;
                    }
                }
                // 如果父节点被选中，则子节点全选
                function forwardChecked(data) {
                    if (data.children) {
                        data.children.forEach(node => {
                            if (data[active]) _this.setAttribute(node, active, true);
                            if (node.children) node = forwardChecked(node);
                        });
                        return data;
                    } else {
                        return data;
                    }
                }
                if (this.withParentChecked && this.multiple) {
                    this.objData.map(node => reverseChecked(node)).map(node => forwardChecked(node));
                }
                this.broadcast('TreeNode', 'indeterminate');
            },
            /**
             * [setAttribute description]
             * 设置检测属性，如果原对象有该属性则重新赋值，如果没有则使用set创建一个挂载属性并赋值
             * @param {[Object]} item [被设置的对象]
             * @param {[String]} attr [需要设置的属性]
             * @param {[String || Boolean]} val  [需要设置的属性值]
             */
            setAttribute(item, attr, val) {
                if (typeof item[attr] === 'undefined') {
                    this.$set(item, attr, val);
                } else {
                    item[attr] = val;
                }
            },
            /**
             * [travalTree]  遍历树中的所有节点，满足需求的标红，并为节点设置指针指向父节点
             * @param  {[Object]} root        [当前根节点，此次遍历的所有元素的父节点]
             * @param  {[Array]} data        [节点对象数组]
             * @param  {[String]} queryString [要查找的字符串]
             * @return {[type]}             [description]
             */
            travalTree(data, queryString) {
                let _this = this
                if (data.length == 1 && typeof data[0].children === 'undefined') {
                    let temp = data[0];
                    if (queryString !== "" && data[0].title.indexOf(queryString) !== -1) {
                        _this.setAttribute(data[0], "target", true);
                        // while循环处理节点的展开状态，节点被标红，则父节点全部展开
                        while (temp.parentNode !== null) {
                            _this.setAttribute(temp.parentNode, "expand", true);
                            temp = temp.parentNode;
                        }
                    } else {
                        _this.setAttribute(data[0], "target", false);
                    }
                }
                else {
                    data.forEach(function(item, index) {
                        let temp = item;
                        if (queryString !== "" && item.title.indexOf(queryString) !== -1) {
                            _this.setAttribute(item, "target", true);
                            // while循环处理节点的展开状态，节点被标红，则父节点全部展开
                            while (temp.parentNode !== null) {
                                _this.setAttribute(temp.parentNode, "expand", true);
                                temp = temp.parentNode;
                            }
                        } else {
                            _this.setAttribute(item, "target", false);
                        }
                        if (typeof item.children !== 'undefined') {
                            _this.travalTree(item.children, queryString)
                        }
                    })
                }
            },
            //组织上下级关系
            setResultArr(arr,filterArr){
                let _this = this
                for(var i=0;i<arr.length;i++){
                    arr[i].children=_this.getLevelArrByid(arr[i].menuId,filterArr);
                    _this.setResultArr(arr[i].children,filterArr);
                }
                return arr;
            },
            //根据id查找符合当前级别子集集合
            getLevelArrByid(menuid,filterArr){
                var res=[];
                for(var j=0;j<filterArr.length;j++){
                    if(filterArr[j].parentId==menuid){
                        res.push(filterArr[j]);
                    }
                }
                return res;
            },
            //查找所有和搜索关键字匹配的上下级对象
            getNodeShip(arr, nodePid, shipArr) {
                let _this = this
                var nowNode = _this.getNodeById(arr, nodePid);
                if (nowNode) {
                    shipArr.push(nowNode);
                    if (nowNode.parentId != null) {
                        _this.getNodeShip(arr, nowNode.parentId, shipArr);
                    }
                }
                return shipArr;
            },
            //根据id查找对象
            getNodeById(arr, id) {
                for (var i = 0; i < arr.length; i++) {
                    if (arr[i].menuId == id) {
                        arr[i].children = [];
                        return arr[i];
                    }
                }
            },
            //把n级数据组合成1级数据，为了查找符合条件的某一个对象，提高效率
            getAllArr(arr, result) {
                let _this = this
                if (arr != null) {
                    for (var i = 0; i < arr.length; i++) {
                        result.push(arr[i]);
                        _this.getAllArr(arr[i].children, result);
                    }
                }
                return result;
            },
            //找到符合搜索条件的对象集合
            getSearchArrDiGui(arr, searchStr, newArr) {
                let _this = this
                if (arr != null) {
                    for (var i = 0; i < arr.length; i++) {
                        if (arr[i].title.indexOf(searchStr) !== -1) {
                            newArr.push(arr[i]);
                        }
                        _this.getSearchArrDiGui(arr[i].children, searchStr, newArr);
                    }
                }
                return newArr;
            },
            //去除符合搜索条件的对象的child
            getSearchArr(arr, searchStr) {
                let _this = this
                var searchnewArr = [];
                var newarr = _this.getSearchArrDiGui(arr, searchStr, searchnewArr);
                //去除children
                for (var i = 0; i < newarr.length; i++) {
                    newarr[i].children = [];
                }
                return newarr;
            },
            /**
             * [resetAllAttribute description]重置树中所有节点的属性
             * @param  {[Array]} data [要设置的对象数组]
             * @param  {[String]} attr [要修改的属性]
             * @param  {[String || Boolean]} flag [要设置的值]
             * @return {[type]}      [description]
             */
            resetAllAttribute(data, attr, flag) {
                let _this = this
                this.objData = []
                let oData = JSON.parse(JSON.stringify(this.data));
                if(_this.value === "" ){
                    this.objData = this.makeDataInfo();
                } else{
                    var lists = [];
                    var allArr = _this.getAllArr(data, lists);
                    var searchArr = _this.getSearchArr(data, _this.value);
                    //符合搜索条件的对象及上级
                    var result = [];
                    var shipnewArr = [];

                    for (var i = 0; i < searchArr.length; i++) {
                        var nodeShipArr = _this.getNodeShip(allArr, searchArr[i].menuId,shipnewArr );
                        for (var j = 0; j < nodeShipArr.length; j++) {
                            if (!result.includes(nodeShipArr[j]))
                                result.push(nodeShipArr[j]);
                        }
                    }
                    //第一级对象集合
                    let topLevelArr=[];
                    for(var i=0;i<result.length;i++){
                        if(result[i].menuLevel === 1){
                            topLevelArr.push(result[i]);
                        }
                    }
                    //输出最后结果
                    var data  = _this.setResultArr(topLevelArr,result)
                    if ( data.length == 0){
                        console.log('kong')
                        _this.objData = this.makeDataInfo();
                    } else{
                        console.log('不是空呀')
                        console.log(data)
                        _this.objData = data
                    }
                }
                /*if (data.length == 1 && typeof data[0].children === 'undefined') {
                    _this.setAttribute(data[0], attr, flag);
                }
                else {
                    data.forEach(function(item, index) {
                        _this.setAttribute(item, attr, flag);
                        if (typeof item.children !== 'undefined') {
                            _this.resetAllAttribute(item.children, attr, flag)
                        }
                    })
                }*/
            },
            /**
             * [setParent 为树中的节点设置父节点]
             * @param {[Object]} root [当前根节点]
             * @param {[Array]} data [要设置的对象数组]
             */
            setParent(root, data) {
                let _this = this
                if (data.length < 1) return
                if (data.length == 1 && typeof data[0].children === 'undefined') {
                    _this.setAttribute(data[0], "parentNode", root);
                }
                else {
                    data.forEach(function(item, index) {
                        _this.setAttribute(item, 'parentNode', root)
                        if (typeof item.children !== 'undefined') {
                            _this.setParent(item, item.children)
                        }
                    })
                }
            },
            // 懒加载 设置父节点
            setParentLazyLoading() {
                this.setParent(null, this.objData)
            },
            setIndex(data) {
                let _this = this

                if (data.length == 1 && typeof data[0].children === 'undefined') {
                    let currentIndex = !data[0].parentNode ? "0"
                        : data[0].parentNode.index + "-0"
                    _this.setAttribute(data[0], 'index', currentIndex);
                }
                else {
                    data.forEach(function(item, index) {
                        let currentIndex = !item.parentNode ? index
                            : item.parentNode.index + "-" + index
                        _this.setAttribute(item, 'index', currentIndex);
                        if (typeof item.children !== 'undefined') {
                            _this.setIndex(item.children)
                        }
                    })
                }
            },
            // 搜索框内容变化执行搜索操作
            search() {
                console.log(this.value)
                // this.setParent(null, this.objData)
                if (this.value !== '' || this.value !== null || this.value !== undefined) {
                    this.showCloseIcon = true
                    this.resetAllAttribute(this.objData, "expand", false);
                }
                if (this.value === '' || this.value === null || this.value === undefined) {
                    this.showCloseIcon = false
                    this.resetAllAttribute(this.objData, "target", false);
                }
                this.travalTree(this.objData, this.value)
                // this.resetParent(0, this.objData)
            },
            customDragstart(item) {
                if(this.draggable){
                    this.dragstartItem = item
                }

            },
            customDrop(item, position) {
                if(this.draggable) {
                    this.dropItem = item
                    this.changeItem(position)
                }
            },
            /**
             * [changeItem description] 执行交换操作
             *
             */
            changeItem(position) {
                this.setIndex(this.objData)

                // 将父节点向子节点中拖动也不会执行任何操作
                // 如果拖拽的对象和目标对象相同，则不执行任何操作
                if ((this.dropItem.index + "").indexOf((this.dragstartItem.index + "")) === 0 || this.dragstartItem.index === this.dropItem.index) {
                    return false
                }
                // 获取拖动对象和目标对象的层次列表
                let dragStartIndexList = []
                let dropIndexList = []
                if ((this.dragstartItem.index + "").indexOf("-") !== -1) {
                    dragStartIndexList = this.dragstartItem.index.split('-')
                }
                else {
                    dragStartIndexList.push(this.dragstartItem.index)
                }
                if ((this.dropItem.index + "").indexOf("-") !== -1) {
                    dropIndexList = this.dropItem.index.split('-')
                }
                else {
                    dropIndexList.push(this.dropItem.index)
                }
                let dragIndex = parseInt(dragStartIndexList[dragStartIndexList.length - 1])
                let dropIndex = parseInt(dropIndexList[dropIndexList.length - 1])
                let droptemp = this.objData
                let dragtemp = this.objData
                // 找到拖拽元素所在的数组
                for (let i = 0; i < dragStartIndexList.length - 1; i++) {
                    let tempIndex = dragStartIndexList[i] - 0
                    dragtemp = dragtemp[tempIndex]
                    dragtemp = dragtemp.children
                }

                if (position === 'inside') {
                    // 将拖动的元素插入到drop位置的最后一个子节点
                    for (let i = 0; i < dropIndexList.length; i++) {
                        let tempIndex = dropIndexList[i] - 0
                        droptemp = droptemp[tempIndex]
                        if (typeof droptemp.children === 'undefined') {
                            this.$set(droptemp, "children", [])
                        }
                        if (i === dropIndexList.length - 1) {
                            this.dragstartItem.parentNode = droptemp
                            this.setAttribute(droptemp, 'expand', true);
                        }
                        droptemp = droptemp.children
                    }
                    droptemp.push(this.dragstartItem)
                    //将移动的item从原来的位置删除
                    dragtemp.splice(dragIndex, 1)
                }
                else if (position === 'pre' || position === 'next') {
                    // 获取到drop位置所在的数组
                    for (let i = 0; i < dropIndexList.length - 1; i++) {
                        let tempIndex = dropIndexList[i] - 0
                        droptemp = droptemp[tempIndex]
                        droptemp = droptemp.children
                    }
                    // 拖拽对象和目标位置处于同一层级
                    if (this.dragstartItem.parentNode === this.dropItem.parentNode) {
                        // 先从原来的位置删除掉被拖拽的项，父元素没有变化，所以不用设置父节点
                        dragtemp.splice(dragIndex, 1)
                        if (position === 'pre') {
                            if (dragIndex > dropIndex) {
                                droptemp.splice(dropIndex, 0, this.dragstartItem)
                            } else {
                                droptemp.splice(dropIndex - 1, 0, this.dragstartItem)
                            }
                        }
                        else {
                            if (dragIndex > dropIndex) {
                                droptemp.splice(dropIndex + 1, 0, this.dragstartItem)
                            } else {
                                droptemp.splice(dropIndex, 0, this.dragstartItem)
                            }
                        }
                    }
                    else {
                        // 目标和drag对象处于不同层级
                        this.dragstartItem.parentNode = droptemp[0].parentNode
                        if (position === 'pre') {
                            droptemp.splice(dropIndex, 0, this.dragstartItem)
                        } else {
                            droptemp.splice(dropIndex + 1, 0, this.dragstartItem)
                        }
                        //将移动的item从原来的位置删除
                        dragtemp.splice(dragIndex, 1)
                    }
                }
                this.setIndex(droptemp)
                this.setIndex(dragtemp)
                this.$emit('on-changed', this.objData)
            },
            //设置selected和checked同步
            consistentSelectAndChecked(data) {
                let _this = this
                data.forEach(function(item, index){
                    if (item.selected || item.checked) {
                        _this.setAttribute(item, "checked", true);
                        _this.setAttribute(item, "selected", true);
                        if (item.children && item.children.length > 0 && _this.withCheckAll) {
                            _this.resetAllAttribute(item.children, 'checked', true)
                            _this.resetAllAttribute(item.children, 'selected', true)
                        }
                    } else if (item.children && item.children.length > 0) {
                        _this.consistentSelectAndChecked(item.children)
                    }
                })
            },
            editedEnd(param){
                this.$emit('onEditedAfter',param);
//            alert(param)
            }
        },
        mounted() {
            this.updateData();
            if (this.cascade) {
                this.consistentSelectAndChecked(this.objData)
            }
            this.$on('oneSelected', ori => {
                const nodes = findComponentsDownward(this, 'TreeNode');
                nodes.forEach(node => {
                    this.$set(node.data, 'selected', false);
                    if (this.cascade) {
                        this.$set(node.data, 'checked', false);
                    }
                })
                this.$set(ori, 'selected', true);
                if (this.cascade) {
                    this.$set(ori, 'checked', true);
                }
            })

            this.$on('on-selected', () => {
                this.updateData(false, 'selected');
                this.$emit('on-select-change', this.getSelectedNodes());
            });

            this.$on('oneChecked', ori => {
                const nodes = findComponentsDownward(this, 'TreeNode');
                nodes.forEach(node => {
                    this.$set(node.data, 'checked', false);
                    if (this.cascade) {
                        this.$set(node.data, 'selected', false);
                    }
                })
                this.$set(ori, 'checked', true);
                if (this.cascade) {
                    this.$set(ori, 'selected', true);
                }
            })
            this.$on('checked', () => {
                this.updateData(false);
            });
            this.$on('on-checked', () => {
                this.$emit('on-check-change', this.getCheckedNodes());
            });
            this.$on('toggle-expand', (payload) => {
                this.$emit('on-toggle-expand', payload);
            });
        },
        watch: {
            data: {
                handler(val, oldVal) {
                    this.objData = this.makeDataInfo();
                    if (this.cascade) {
                        this.consistentSelectAndChecked(this.objData)
                    }
                    this.$nextTick(() => {
                        this.updateData();
                        this.broadcast('TreeNode', 'indeterminate');
                        if(!this.showCheckbox && !this.multiple){//单选无checkbox
                            this.$emit("on-tree-init",this.getSelectedNodes());
                        }else if (this.cascade && this.showCheckbox && this.multiple) {//多选且cascade，主要针对treeselect的情况
                            this.$emit("on-tree-init",this.getSelectedNodes());
                        }else{
                            this.$emit("on-tree-init",this.getSelectedNodes()||this.getCheckedNodes());
                        }

                    });
                },
                deep: true
            }
        }
    };
</script>