<template>
    <div class="ts-wrap">
        <div class="tree-select" v-clickoutside="changeDown" ref="atsTree" >
            <div class="ts-one-input" v-if="!multiple" :style="style" >
                <div :class="classes" ref="reference">
                    <Input ref="input" @blur="handleAutoComplete"
                           :style="style"
                           @on-change="search"
                           v-if="filterable"
                           v-model="currentNodeId"
                           @on-focus="changeUp"
                           @on-click="changeDownOrUp"
                           :icon="icon"
                           :placeholder="defaultValue" />
                    <Input ref="input" @blur="handleAutoComplete"
                           :style="style"
                           v-else=""
                           v-model="currentNodeId"
                           @on-focus="changeUp"
                           @on-click="changeDownOrUp"
                           :icon="icon"
                           :placeholder="defaultValue" />
                    <div class="node" v-show="showNode">
                        <span>{{node.title}}</span>
                    </div>
                    <div class="ts-icon" @click="removeNode(node.id)" v-show="tsiconshow">
                        <Icon class="pl" type="ios-close"></Icon>
                    </div>
                </div>
                <transition name="slide-up">
                    <div v-show="showTree" @click="stopClickEvent" ref="treecontainer" class="ts-body" :class="{['ivu-treeSelect-transfer']: transfer}" :style="selectStryle" :data-transfer="transfer" v-transfer-dom>
                        <Tree ref="tree" :multiple="multiple"
                              @on-select-change="getSelectNodes"
                              :data="treeData" :fields="fields" @on-tree-init="initdefaultvalue"></Tree>
                    </div>
                </transition>
            </div>
            <div class="ts-input" v-else>
                <div class="ivu-treeSelect" :style="style" ref="reference">
                    <div class="ivu-select-selection" :style="multStyle">
                        <div class="ivu-tag"  v-for="item in nodes"><span class="ivu-tag-text">{{item.title}}</span> <div class="icon" @click="removeNodes(item.id)"><Icon class="pl" type="close-round"></Icon></div></div>
                        <Input ref="input" v-if="filterable"  @blur="handleAutoComplete" :style="multStyle" @on-change="search" v-model="currentNodeId" @on-focus="changeUp" @on-click="changeDownOrUp"  :placeholder="defaultValue" />
                        <Input ref="input" v-else=""  @blur="handleAutoComplete" :style="multStyle" v-model="currentNodeId" @on-focus="changeUp" @on-click="changeDownOrUp"  :placeholder="defaultValue" />
                    </div>
                    <div class="multIcon" @click="changeDownOrUp"><Icon :size="16"  :type="icon"></Icon></div>
                </div>
                <transition name="slide-up">
                    <div @click="stopClickEvent" v-show="showTree" ref="treecontainer" class="ts-body" :class="{['ivu-treeSelect-transfer']: transfer}" :style="selectStryle" :data-transfer="transfer" v-transfer-dom>
                        <Tree ref="tree" @on-tree-init="initdefaultvalue" cascade :multiple="multiple" show-checkbox @on-select-change="getSelectNodes"  :data="treeData" :fields="fields" ></Tree>
                    </div>
                </transition>
            </div>
        </div>
    </div>
</template>
<script>
    import Vue from 'vue';
    const isServer = Vue.prototype.$isServer;
    import clickoutside from '../../directives/clickoutside';
    import TransferDom from '../../directives/transfer-dom';
    import { findComponentsDownward } from '../../utils/assist';
    import Emitter from '../../mixins/emitter';
    const Popper = isServer ? function() {} : require('popper.js');  // eslint-disable-line

    function debounce(callback, delay) {
        var timeout;
        return function() {
            var context = this,
                args = arguments;
            clearTimeout(timeout);
            timeout = setTimeout(function() {
                callback.apply(context, args);
            }, delay);
        }
    }
    /**
     *
     * @param {*} treeArr 树或树的数组
     * @param {*} childrenName 子节点数组的属性名称
     * @param {*} levelName level属性的名称
     * @param {*} level 开始的级数
     */
    const addLevel = function _addLevel({treeArr,  childrenName = 'children', levelName = 'menuLevel', level = 1}) {
        if(!treeArr) return;

        if (!(treeArr instanceof Array)) {
            treeArr = [treeArr];
        }

        treeArr.forEach(tree => {
            if (!tree) return;
            tree[levelName] = level;
            _addLevel({
                treeArr: tree[childrenName],
                childName: childrenName,
                levelName: levelName,
                level: level + 1});
        });
    };
    //cascade配置，强制开启checked和selected同步,单选无checkbox，多选固定checkbox
    export  default {
        directives: { clickoutside,TransferDom },
        mixins: [ Emitter ],
        props:{
            data: {
                type: Array,
                default() {
                    return []
                }
            },
            fields: {
                type: Array,
                default(){
                    return []
                }
            },
            placeholder:{
                type: String,
                default:false
            },
            filterable: {
                type: Boolean,
                default: false
            },
            width:{
                type: Number,
                default: 160
            },
            selectHeight:{//下拉选择的高度
                type:Number,
                default:200
            },
            multiple: {
                type: Boolean,
                default: false
            },
            onSelectChange:{
                type:Function
            },
            value:{
                type:[String, Number, Array],
                default: ''
            },
            transfer:{
                type:Boolean,
                default:false
            }
        },
        computed:{
            classes () {
                return [
                    {
                        [`ts-show-clear`]: this.tsiconshow,
                    }
                ];
            },
            showTree(){
                return this.visible;
            }
        },
        data(){
            return {
                tsiconshow:false,
                treeData:this.initData(),
                visible:false,
                icon:'ios-arrow-down',
                currentNodeId:'',
                model:this.currentNodeId,
                showNode:false,
                node:{title:''},
                nodes:[],
                defaultValue:'',
                style: {
                    width:''
                },
                selectStryle:{
                    width:'',
                    height:''
                },
                multStyle:{
                    width:''
                },
                popper: null
            }
        },
        created(){
            this.init();
        },
        methods:{
            handleAutoComplete:function () {
            },
            initData(){
                let treeData = this.$props.data;
                // 获取参数
                let param = {treeArr: treeData};
                let fields = this.fields;
                // 如果fields中有children, 增加childrenName
                if(fields instanceof Array && fields.length > 0) {
                    let item = fields.find(it => it.map === 'children');
                    if(item) {
                        param.childrenName = item.field;
                    }
                }
                addLevel(param);
                return treeData;
            },
            init(){
                this.style={
                    width:this.$props.width+"px"+"!important"
                };
                this.multStyle={
                    width:( this.$props.width - 32 ) + "px"
                };
                this.selectStryle={
                    width:this.$props.width+"px"+"!important",
                    height:this.$props.selectHeight+"px"+"!important"
                };
                this.defaultValue = this.$props.placeholder;
                this.searchWhenTextChange = debounce(this.search, 300);
            },
            //组织上下级关系
            setResultArr(arr,filterArr){
                let _this = this
                for(var i=0;i<arr.length;i++){
                    arr[i].Child=_this.getLevelArrByid(arr[i].Id,filterArr);
                    _this.setResultArr(arr[i].Child,filterArr);
                }
                return arr;
            },
            //根据id查找符合当前级别子集集合
            getLevelArrByid(id,filterArr){
                var res=[];
                for(var j=0;j<filterArr.length;j++){
                    if(filterArr[j].pid==id){
                        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.pid != null) {
                        _this.getNodeShip(arr, nowNode.pid, shipArr);
                    }
                }
                return shipArr;
            },
            //根据id查找对象
            getNodeById(arr, id) {
                for (var i = 0; i < arr.length; i++) {
                    if (arr[i].Id == id) {
                        arr[i].Child = [];
                        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].Child, result);
                    }
                    return result;
                }
            },
            //找到符合搜索条件的对象集合
            getSearchArrDiGui(arr, searchStr, newArr) {
                let _this = this
                if (arr != null) {
                    for (var i = 0; i < arr.length; i++) {
                        if (arr[i].Name.indexOf(searchStr) >= 0) {
                            newArr.push(arr[i]);
                        }
                        _this.getSearchArrDiGui(arr[i].Child, searchStr, newArr);
                    }
                    return newArr;
                }

            },
            //去除符合搜索条件的对象的child
            getSearchArr(arr, searchStr) {
                let _this = this
                var searchnewArr = [];
                var newarr = _this.getSearchArrDiGui(arr, searchStr, searchnewArr);
                //去除child
                /*for (var i = 0; i < newarr.length; i++) {
                 newarr[i].Child = [];
                 }*/
                return newarr;
            },
            resetAllData(data,attr, flag){
                let _this = this
                if(this.currentNodeId === '' || this.currentNodeId === null){
                    this.treeData = this.initData();
                }else{
                    var searchArr = _this.getSearchArr(data, _this.currentNodeId);
                    //符合搜索条件的对象及上级
                    var result = [];
                    var lists = [];
                    var shipnewArr = [];
                    var allArr = _this.getAllArr(data, lists);
                    for (var i = 0; i < searchArr.length; i++) {
                        var nodeShipArr = _this.getNodeShip(allArr, searchArr[i].Id,shipnewArr );
                        for (var j = 0; j < nodeShipArr.length; j++) {
                            if (!result.includes(nodeShipArr[j]))
                                result.push(nodeShipArr[j]);
                        }
                    }
                    //第一级对象集合
                    var topLevelArr=[];
                    for(var i=0;i<result.length;i++){
                        if(result[i].menuLevel==1){
                            topLevelArr.push(result[i]);
                        }
                    }
                    //输出最后结果
                    console.log("11111111")
                    console.log(_this.setResultArr(topLevelArr,result));
                    _this.treeData = this.setResultArr(topLevelArr,result)
                }
            },
            search(e){
                this.resetAllData(this.initData(),'expand', false);
                /*const smoothUpdateTree = (data) => {
                 this.$refs.tree.data.length = 0;
                 this.$refs.tree.data.push(...data)
                 }
                 const value = e.target.value.trim();
                 const originData = this.$props.data;
                 if(value === ''){
                 smoothUpdateTree(originData);
                 return;
                 }
                 const findMatchTrees = root =>{
                 const result = [];
                 let flag;

                 const topToDown = (node, level) => {
                 if(node.title.indexOf(value)>=0){
                 const copie = Object.assign({},   node, {children:[], level})
                 if(flag && flag.level < level){
                 flag.children.push(copie)
                 }else{
                 result.push(copie)
                 flag = copie
                 }
                 }
                 return node.children
                 && node.children.forEach(child => topToDown(child, level+1))
                 }
                 topToDown(root , 0);
                 return result
                 }
                 const trees = originData.map(findMatchTrees).reduce((a,b) => [...a,...b],[])
                 smoothUpdateTree(trees);*/
            },
            changeUp(){
                this.visible=true;
                this.icon='ios-arrow-up';
            },
            changeDown(){
                this.icon='ios-arrow-down';
                this.visible=false;
            },
            changeDownOrUp(){
                if(this.icon=="ios-arrow-up"){
                    this.visible=false;
                    this.icon='ios-arrow-down';
                }else {
                    this.visible=true;
                    this.icon='ios-arrow-up';
                }
            },
            /*
             getCheckNodes(val){
             this.tsiconshow=true;
             if(!this.$props.multiple){
             if(val.length>0){
             this.node=val[0];
             this.showNode=true;
             this.changeDataStatue(val[0].id);
             this.defaultValue="";
             }else {
             this.changeDataStatue("");
             this.node="";
             this.showNode=false;
             this.defaultValue=this.$props.placeholder;
             }
             }else {
             if(val.length>0){
             this.defaultValue="";
             }else {
             this.defaultValue=this.$props.placeholder;
             }
             this.nodes=val;
             this.showNode=true;
             }
             this.$emit('on-check-change', val);
             },
             */
            getSelectNodes(val){
                if(!this.$props.multiple){
                    if(val.length>0){
                        this.tsiconshow=true;
                        this.node=val[0];
                        this.showNode=true;
                        this.changeDataStatue(val[0].id);
                        this.defaultValue="";
                    }else {
                        this.changeDataStatue("");
                        this.node="";
                        this.tsiconshow=false;
                        this.showNode=false;
                        this.defaultValue=this.$props.placeholder;
                    }
                }else {
                    if(val.length>0){
                        this.defaultValue="";
                    }else {
                        this.defaultValue=this.$props.placeholder;
                    }
                    this.nodes=val;
                    this.showNode=true;
                }
                this.$emit('on-select-change', val);
            },
            removeNode(id){
                var that=this;
                var nodes=  this.$refs.tree.$children[0].data;
                var children=new Array;
                if(nodes.id==id){
                    nodes.checked=false;
                    nodes.selected=false;
                    that.node={};
                    that.showNode=false;
                    for(var a=0;a<that.nodes.length;a++){
                        if(that.nodes[a].id==id){
                            that.nodes.splice(that.nodes[a],1);
                        }
                    }
                    this.tsiconshow=false;
                }else {
                    if(nodes.children){
                        children=nodes.children;
                        getChild(children);
                    }
                    this.tsiconshow=false;
                }
                function getChild(children){
                    children.forEach(function(node){
                        if(node.id==id){
                            node.selected=false;
                            node.checked=false;
                            that.node={};
                            that.showNode=false;
                            for(var a=0;a<that.nodes.length;a++){
                                if(that.nodes[a].id==id){
                                    that.nodes.splice(that.nodes[a],1);
                                }
                            }
                        }else {
                            if(node.children){
                                children=node.children;
                                getChild(children);
                            }
                        }
                    });
                }
                this.getSelectNodes(this.node);
            },
            removeNodes(id){
                let that=this;
                let nodes = this.$refs.tree.objData;
                for(let a =0;a<nodes.length;a++){
                    let node = nodes[a];
                    let child = node.children;
                    if(node.id==id){
                        node.checked=false;
                        node.selected=false;
                        resetNodes(node);
                        if(child != undefined && child.length >0) {
                            resetChild(child);
                        }

                    }else{
                        if(child != undefined && child.length >0) {
                            foreachChild(child);
                        }
                    }
                }
                if(this.nodes.length>0){
                    this.defaultValue="";
                }else {
                    this.showNode=false;
                    this.defaultValue=this.$props.placeholder;
                }
                //遍历子节点，checked和selected都设置成false
                function resetChild(childs){
                    for(let i=0;i<childs.length;i++){
                        childs[i].checked=false;
                        childs[i].selected=false;
                        resetNodes(childs[i]);
                        if(childs[i].child != undefined && childs[i].child.length >0) {
                            resetChild(childs[i].child);
                        }
                    }
                }
                //遍历子节点，判断是否是当前要删除的节点
                function foreachChild(childs){
                    for(let i =0;i<childs.length;i++){
                        let node = childs[i];
                        let child = node.children;
                        if(node.id==id){
                            node.checked=false;
                            node.selected=false;
                            resetNodes(node);
                            if(child != undefined && child.length >0) {
                                resetChild(child);
                            }
                        }else{
                            if(child != undefined && child.length >0) {
                                foreachChild(child);
                            }
                        }
                    }
                }
                //删除this.nodes中的指定对象
                function resetNodes(node){
                    for(let i=0;i<that.nodes.length;i++){
                        if(that.nodes[i].id==node.id){
                            that.nodes.splice(i,1);
                        }
                    }
                }

                this.getSelectNodes(this.nodes);

            },
            changeDataStatue(id){
                var nodes=  this.$refs.tree.$children[0].data;
                var children=new Array;
                if(nodes.id==id){
                    nodes.checked=true;
                    nodes.selected=true;
                }else {
                    nodes.checked=false;
                    nodes.selected=false;
                }
                if(nodes.children){
                    children=nodes.children;
                    getChild(children);
                }
                function getChild(children){
                    children.forEach(function(node){
                        if(node.id==id){
                            node.selected=true;
                            node.checked=true;
                        }else {
                            node.selected=false;
                            node.checked=false;
                        }
                        if(node.children){
                            children=node.children;
                            getChild(children);
                        }
                    });
                }
            },
            initdefaultvalue(data){
                this.getSelectNodes(data);
            },
            //设置默认值
            setDefaultValue(id){
                let nodeList = this.getNode(id);
                if(!this.$props.multiple){
                    this.node = nodeList[0];
                }else{
                    this.nodes = nodeList;
                }
                this.getSelectNodes(nodeList);
            },
            getNode(ids){
                let nodes = [];
                let that = this;
                if(ids != '' && ids != null){
                    let idAttr = ids.split(",");
                    //重置所有的节点为未选中状态
                    that.$refs.tree.resetAllAttribute(that.$refs.tree.objData,"selected",false);
                    that.$refs.tree.resetAllAttribute(that.$refs.tree.objData,"checked",false);
                    for(let i=0;i<idAttr.length;i++){
                        findComponentsDownward(this,"TreeNode").forEach(node=>{
                            let id = idAttr[i];
                            if(node.data.id == id){
                                nodes.push(node.data);
                                node.data.checked=true;
                                node.data.selected=true;
                            }
                        });

                    }
                }
                return nodes;
            },
            update () {
                if (isServer) return;
                if (this.popper) {
                    this.$nextTick(() => {
                        this.popper.update();
                    });
                } else {
                    this.$nextTick(() => {
                        this.popper = new Popper(this.$refs.reference, this.$refs.treecontainer, {
                            gpuAcceleration: false,
                            placement: 'bottom-start',
                            boundariesPadding: 0,
                            forceAbsolute: true,
                            boundariesElement: 'body'
                        });
                        this.popper.onCreate(popper => {
                            this.resetTransformOrigin(popper);
                        });
                    });
                }
            },
            destroy () {
                if (this.popper) {
                    this.resetTransformOrigin(this.popper);
                    setTimeout(() => {
                        this.popper.destroy();
                        this.popper = null;
                    }, 300);
                }
            },
            resetTransformOrigin(popper) {
                let placementMap = {top: 'bottom', bottom: 'top'};
                let placement = popper._popper.getAttribute('x-placement').split('-')[0];
                let origin = placementMap[placement];
                popper._popper.style.transformOrigin = `center ${ origin }`;
            },
            stopClickEvent(e){
                e.stopPropagation();
            }
        },
        watch: {
            data:{
                handler(val, oldVal) {
                    this.treeData = this.initData();
                }
            },
            value (val) {
                this.model = val;
                if (val === '') {
                    this.currentNodeId = '';
                    this.node='';
                    this.nodes=[];
                    this.defaultValue=this.$props.placeholder;
                    this.$refs.tree.resetAllAttribute(this.$refs.tree.objData,"selected",false);
                    this.$refs.tree.resetAllAttribute(this.$refs.tree.objData,"checked",false);
                }
                //手动触发form的验证
                this.dispatch('FormItem', 'on-form-blur', val);
            },
            visible(val){
                if (val) {
                    if (this.transfer) {
                        this.update();
                    }
                } else {
                    if (this.transfer) {
                        this.destroy();
                    }
                }
            }
        },
        beforeDestroy () {
            if (this.popper) {
                this.popper.destroy();
            }
        },
        mounted(){
            this.$on("on-select-change",(value)=>{
                if(typeof event != "undefined" && this.transfer) {
                    event.stopPropagation();
                    this.update();
                }
            })
        }
    }
</script>