/**
 * 构建pathTree
 * 可动态加载子节点，要求子节点获取接口按/xxx/get-children定义
 * @param {Object} setting - 设置
 * @returns {PathTree}
 */

'use strict';

class PosData {
    /**
     * 构造函数
     * @param {id|Number, masterId|Number} setting
     */
    constructor (setting) {
        // 无索引
        this.datas = null;
        // 以key为索引
        this.items = {};
        // 以分类id为索引的有序
        this.ledgerPos = {};
        // pos设置
        this.setting = setting;
    }

    /**
     * 加载部位明细数据
     * @param datas
     */
    loadDatas(datas) {
        this.datas = datas;
        for (const data of this.datas) {
            const key = itemsPre + data[this.setting.id];
            this.items[key] = data;

            const masterKey = itemsPre + data[this.setting.ledgerId];
            if (!this.ledgerPos[masterKey]) {
                this.ledgerPos[masterKey] = [];
            }
            this.ledgerPos[masterKey].push(data);
        }
    }

    /**
     * 更新数据
     * @param datas
     */
    updateDatas(data) {
        const datas = data instanceof Array ? data : [data];
        for (const d of datas) {
            const key = itemsPre + d[this.setting.id];
            if (!this.items[key]) {
                this.datas.push(d);
                this.items[key] = d;

                const masterKey = itemsPre + d[this.setting.ledgerId];
                if (!this.ledgerPos[masterKey]) {
                    this.ledgerPos[masterKey] = [];
                }
                this.ledgerPos[masterKey].push(d);
            } else {
                const pos = this.items[key];
                for (const prop in d) {
                    pos[prop] = d[prop];
                }
            }
        }
    }

    /**
     * 移除数据
     * @param datas
     */
    removeDatas(data) {
        if (!data) { return; }
        const datas = data instanceof Array ? data : [data];
        for (let i = datas.length - 1; i >= 0; i--) {
            const id = datas[i];
            const d = this.getPos(id);
            this.datas.splice(this.datas.indexOf(d), 1);
            const key = itemsPre + d[this.setting.id];
            delete this.items[key];
            const masterKey = itemsPre + d[this.setting.ledgerId];
            const range = this.ledgerPos[masterKey];
            range.splice(range.indexOf(d), 1);
            if (range.length === 0) {
                delete this.ledgerPos[masterKey];
            }
        }
    }

    /**
     * 移除数据 - 根据分类id
     * @param mid
     */
    removeDatasByMasterId (mid) {
        const masterKey = itemsPre + mid;
        const range = this.ledgerPos[masterKey];
        if (range) {
            delete this.ledgerPos[masterKey];
            for (const r of range) {
                this.datas.splice(this.datas.indexOf(r), 1);
                const key = itemsPre + r[this.setting.id];
                delete this.items[key];
            }
        }
    }

    getPos(id) {
        return this.items[itemsPre + id];
    }

    getLedgerPos(mid) {
        return this.ledgerPos[itemsPre + mid];
    }

    /**
     * 计算全部
     */
    calculateAll() {
        if (!this.setting.calcFun) { return; }
        for (const pos of this.datas) {
            this.setting.calcFun(pos);
        }
    }
}

class StagePosData extends PosData {
    loadStageData(datas, fieldPre, fields) {
        if (!datas) { return; }
        datas = datas instanceof Array ? datas : [datas];
        const loadedData = [];
        for (const data of datas) {
            let node = this.getPos(data.pid);
            if (node) {
                for (const prop of fields) {
                    if (data[fieldPre + prop] !== undefined) {
                        node[fieldPre + prop] = data[prop];
                    }
                }
                if (this.setting.calcFun) {
                    this.setting.calcFun(node);
                }
                loadedData.push(node);
            }
        }

    }

    loadPreStageData(datas) {
        this.loadStageData(datas, 'pre_', this.setting.updateFields);
    }

    loadCurStageData(datas) {
        this.loadStageData(datas, '', this.setting.updateFields);
    }
}

class MasterPosData extends PosData {
    /**
     * 构造函数
     * @param {id|Number, masterId|Number} setting
     */
    constructor (setting) {
        super(setting);
        // 关联索引
        this.masterItems = {};
    }
    /**
     * 加载主数据
     * @param datas
     */
    loadDatas (datas) {
        super.loadDatas(datas);
        // 清空旧数据
        this.masterItems = {};
        // minor数据缓存
        this.minorData = {};
        // 加载全部数据
        for (const data of this.datas) {
            const keyName = itemsPre + data[this.setting.masterId];
            this.masterItems[keyName] = data;
        }
    }
    /**
     * 根据关联id，查找节点
     * @param id
     * @returns {*}
     */
    getMasterItems(id) {
        return this.masterItems[itemsPre + id];
    }
    /**
     * 加载关联数据
     *
     * @param {Array|Object}datas - 需要关联的数据
     * @param {String} fieldPre - 关联字段前缀（关联结果）
     * @param {Array} fields - 关联字段
     * @returns {Array}
     */
    loadMinorData(datas, fieldSuf, fields) {
        if (!datas) { return; }
        datas = datas instanceof Array ? datas : [datas];
        this.minorData[fieldSuf] = datas;
        const loadedData = [];
        for (const data of datas) {
            let node = this.getMasterItems(data[this.setting.minorId]);
            if (node) {
                for (const prop of fields) {
                    if (data[prop] !== undefined) {
                        node[prop + fieldSuf] = data[prop];
                    }
                }
                loadedData.push(node);
            }
        }
        return loadedData;
    }
}

const itemsPre = 'id_';

const createNewPathTree = function (type, setting) {
    class BaseTree {
        /**
         * 构造函数
         */
        constructor (setting) {
            // 无索引
            this.datas = [];
            // 以key为索引
            this.items = {};
            // 以排序为索引
            this.nodes = [];
            // 根节点
            this.children = [];
            // 树设置
            this.setting = setting;
        }
        /**
         * 树结构根据显示排序
         */
        sortTreeNode (isResort) {
            const self = this;
            const addSortNodes = function (nodes) {
                if (!nodes) { return }
                for (let i = 0; i < nodes.length; i++) {
                    self.nodes.push(nodes[i]);
                    nodes[i].index = self.nodes.length - 1;
                    if (!isResort) {
                        nodes[i].children = self.getChildren(nodes[i]);
                    } else {
                        nodes[i].children.sort(function (a, b) {
                            return a.order - b.order;
                        })
                    }
                    addSortNodes(nodes[i].children);
                }
            };
            self.nodes = [];
            this.children = this.getChildren(null);
            addSortNodes(this.getChildren(null));
        }
        /**
         * 加载数据(初始化), 并给数据添加部分树结构必须数据
         * @param datas
         */
        loadDatas (datas) {
            // 清空旧数据
            this.items = {};
            this.nodes = [];
            this.datas = [];
            this.children = [];
            // 加载全部数据
            for (const data of datas) {
                const keyName = itemsPre + data[this.setting.id];
                if (!this.items[keyName]) {
                    this.items[keyName] = JSON.parse(JSON.stringify(data));
                    this.datas.push(this.items[keyName]);
                }
            }
            this.sortTreeNode();
            for (const node of this.nodes) {
                node.expanded = node.children.length > 0;
                node.visible = true;
            }
        }

        getItemsByIndex(index) {
            return this.nodes[index];
        }
        /**
         * 根据id获取树结构节点数据
         * @param {Number} id
         * @returns {Object}
         */
        getItems (id) {
            return this.items[itemsPre + id];
        };
        /**
         * 查找node的parent
         * @param {Object} node
         * @returns {Object}
         */
        getParent (node) {
            return this.getItems(node[this.setting.pid]);
        };

        /**
         * 根据path查找完整节点
         * @param {Number} path
         */
        getFullPathNodes (path) {
            const self = this, ids = path.split('.');
            if (ids.length > 0) {
                return this.nodes.filter((x) => {
                    return ids.indexOf('' + x[self.setting.id]) >= 0;
                });
            } else {
                return [];
            }
        };
        /**
         * 查询node的已下载子节点
         * @param {Object} node
         * @returns {Array}
         */
        getChildren (node) {
            const setting = this.setting;
            const pid = node ? node[setting.id] : setting.rootId;
            const children = this.datas.filter(function (x) {
                return x[setting.pid] === pid;
            });
            children.sort(function (a, b) {
                return a.order - b.order;
            });
            return children;
        };
        /**
         * 查询node的已下载的全部后代
         * @param {Object} node
         * @returns {Array}
         */
        getPosterity (node) {
            const reg = new RegExp('^' + node.full_path + '.');
            return this.datas.filter(function (x) {
                return reg.test(x.full_path);
            })
        };
        /**
         * 查询node是否是父节点的最后一个子节点
         * @param {Object} node
         * @returns {boolean}
         */
        isLastSibling (node) {
            const siblings = this.getChildren(this.getParent(node));
            return node.order === siblings[siblings.length - 1].order;
        };
        /**
         * 刷新子节点是否可见
         * @param {Object} node
         * @private
         */
        _refreshChildrenVisible (node) {
            if (!node.children) {
                node.children = this.getChildren(node);
            }
            if (node.children && node.children.length > 0) {
                for (const child of node.children) {
                    child.visible = node.expanded && node.visible;
                    this._refreshChildrenVisible(child);
                }
            }
        };
        /**
         * 设置节点是否展开, 并控制子节点可见
         * @param {Object} node
         * @param {Boolean} expanded
         */
        setExpanded (node, expanded) {
            node.expanded = expanded;
            this._refreshChildrenVisible(node);
        };

        /**
         * 提取节点key和索引数据
         * @param {Object} node - 节点
         * @returns {key}
         */
        getNodeKeyData (node) {
            const data = {};
            for (const key of this.setting.keys) {
                data[key] = node[key];
            }
            return data;
        };
        /**
         * 得到树结构构成id
         * @param node
         * @returns {*}
         */
        getNodeKey (node) {
            return node[this.setting.id];
        };

        /**
         * 递归 设置节点展开状态
         * @param {Array} nodes - 需要设置状态的节点
         * @param {Object} parent - nodes的父节点
         * @param {Function} checkFun - 判断节点展开状态的方法
         * @private
         */
        _recursiveExpand(nodes, parent, checkFun) {
            for (const node of nodes) {
                node.expanded = checkFun(node);
                node.visible = parent ? (parent.expanded && parent.visible) : true;
                this._recursiveExpand(node.children, node, checkFun);
            }
        }
        /**
         * 自定义展开规则
         * @param checkFun
         */
        expandByCustom(checkFun) {
            this._recursiveExpand(this.children, null, checkFun);
        }
        /**
         * 展开到第几层
         * @param {Number} level - 展开层数
         */
        expandByLevel(level) {
            // function recursiveExpand(nodes, parent) {
            //     for (const node of nodes) {
            //         node.expanded = node.level < level;
            //         node.visible = parent ? (parent.expanded && parent.visible) : true;
            //         recursiveExpand(node.children, node);
            //     }
            // }
            // recursiveExpand(this.children);
            this.expandByCustom(function (n) {
                return n.level < level;
            });
        }
    }

    class MeasureTree extends BaseTree {
        addData (datas) {
            const loadedData = [];
            for (const data of datas) {
                let node = this.getItems(data[this.setting.id]);
                if (node) {
                    for (const prop in node) {
                        if (data[prop] !== undefined) {
                            node[prop] = data[prop];
                        }
                    }
                    loadedData.push(node);
                } else {
                    const keyName = itemsPre + data[this.setting.id];
                    const node = JSON.parse(JSON.stringify(data));
                    this.items[keyName] = node;
                    this.datas.push(node);
                    node.expanded = false;
                    node.visible = true;
                    loadedData.push(node);
                }
            }
            this.sortTreeNode();
            for (const node of loadedData) {
                const children = node.children;
                if (!node.expanded && children.length > 0) {
                    node.expanded = true;
                    this._refreshChildrenVisible(node);
                }
            }
            return loadedData;
        }
        removeData (datas) {
            datas.sort(function (a, b) {
                return b.level - a.level;
            });
            const removeArrayData = function (array, data) {
                const index = array.indexOf(data);
                array.splice(index, 1);
            };
            for (const data of datas) {
                const node = this.getItems(data[this.setting.id]);
                if (node && this.getChildren(node).length === 0) {
                    delete this.items[itemsPre + node[this.setting.id]];
                    if (node[this.setting.pid] !== this.setting.rootId) {
                        const parent = this.items[itemsPre + node[this.setting.pid]];
                        removeArrayData(parent.children, node);
                    }
                    removeArrayData(this.datas, node);
                    removeArrayData(this.nodes, node);
                }
            }
        };
        loadLeafData (data) {
            const datas = data instanceof Array ? data : [data];
            for (const d of datas) {
                let node = this.getItems(d[this.setting.id]);
                if (node && node.is_leaf) {
                    for (const prop in node) {
                        if (data[prop] !== undefined) {
                            node[prop] = d[prop];
                        }
                    }
                }
            }
        };
    }

    class FxTree extends BaseTree {

        /**
         * 检查节点是否是最底层项目节
         * @param node
         * @returns {boolean}
         */
        isLeafXmj(node) {
            for (const child of node.children) {
                if (!child.b_code || child.b_code === '') {
                    return false;
                }
            }
            return true;
        }

        /**
         * 展开至最底层项目节
         */
        expandToLeafXmj() {
            const self = this;
            this.expandByCustom(function (node) {
                if (node.b_code && node.b_code !== '') {
                    return false;
                } else {
                    return !self.isLeafXmj(node);
                }
            })
        }
    }

    class LedgerTree extends FxTree {

        /**
         * 加载数据(动态)，只加载不同部分
         * @param {Array} datas
         * @return {Array} 加载到树的数据
         * @privateA
         */
        _updateData (datas) {
            datas = datas instanceof Array ? datas : [datas];
            let loadedData = [];
            for (const data of datas) {
                let node = this.getItems(data[this.setting.id]);
                if (node) {
                    for (const prop in node) {
                        if (prop === this.setting.pid && data[prop] !== node[prop]) {

                        }
                        if (data[prop] !== undefined && data[prop] !== node[prop]) {
                            if (prop === this.setting.pid) {
                                loadedData.push(this.getItems(node[this.setting.pid]));
                                loadedData.push(this.getItems(data[this.setting.pid]));
                            }
                            node[prop] = data[prop];
                        }
                    }
                    loadedData.push(node);
                }
            }
            loadedData = _.uniq(loadedData);
            for (const node of loadedData) {
                node.children = this.getChildren(node);
                node.expanded = node.children.length > 0 && node.children[0].visible;
            }
            this.sortTreeNode(true);
            return loadedData;
        };
        /**
         * 加载数据(动态)，只加载不同部分
         * @param {Array} datas
         * @return {Array} 加载到树的数据
         * @privateA
         */
        _loadData (datas) {
            datas = datas instanceof Array ? datas : [datas];
            const loadedData = [], resortData = [];
            for (const data of datas) {
                let node = this.getItems(data[this.setting.id]);
                if (node) {
                    const parent = this.getItems(node[this.setting.pid]);
                    for (const prop in node) {
                        if (data[prop] !== undefined && data[prop] !== node[prop]) {
                            node[prop] = data[prop];
                            if (parent && resortData.indexOf(parent) === -1) {
                                resortData.push(parent);
                            }
                        }
                    }
                    loadedData.push(node);
                } else {
                    const keyName = itemsPre + data[this.setting.id];
                    const node = JSON.parse(JSON.stringify(data));
                    this.items[keyName] = node;
                    this.datas.push(node);
                    node.expanded = false;
                    node.visible = true;
                    loadedData.push(node);
                    if (resortData.indexOf(node) === -1) {
                        resortData.push(node);
                    }
                    const parent = this.getItems(node[this.setting.pid]);
                    if (parent && resortData.indexOf(parent) === -1) {
                        resortData.push(parent);
                    }
                }
            }
            for (const node of resortData) {
                node.children = this.getChildren(node);
            }
            this.sortTreeNode(true);
            for (const node of loadedData) {
                if (!node.expanded) {
                    this.setExpanded(node, true);
                }
            }
            return loadedData;
        };
        /**
         * 清理数据(动态)
         * @param datas
         * @private
         */
        _freeData (datas) {
            datas = datas instanceof Array ? datas : [datas];
            const freeDatas = [];
            const removeArrayData = function (array, data) {
                const index = array.indexOf(data);
                array.splice(index, 1);
            };
            for (const data of datas) {
                const node = this.getItems(data[this.setting.id]);
                if (node) {
                    freeDatas.push(node);
                    delete this.items[itemsPre + node[this.setting.id]];
                    if (node[this.setting.pid] !== this.setting.rootId) {
                        const parent = this.getItems(node[this.setting.pid]);
                        if (parent) {
                            removeArrayData(parent.children, node);
                        }
                    }
                    removeArrayData(this.datas, node);
                    removeArrayData(this.nodes, node);
                }
            }
            return freeDatas;
        };
        /**
         * 加载需展开的数据
         * @param {Array} datas
         * @returns {Array}
         * @private
         */
        _loadExpandData (datas) {
            datas = datas instanceof Array ? datas : [datas];
            const loadedData = [], existData = [], expandData = [], resortData = [];
            for (const data of datas) {
                let node = this.getItems(data[this.setting.id]);
                if (node) {
                    existData.push(node);
                } else {
                    const keyName = itemsPre + data[this.setting.id];
                    const node = JSON.parse(JSON.stringify(data));
                    this.items[keyName] = node;
                    this.datas.push(node);
                    node.expanded = false;
                    node.visible = true;
                    loadedData.push(node);

                    if (resortData.indexOf(node) === -1) {
                        resortData.push(node);
                    }
                    const parent = this.getItems(node[this.setting.pid]);
                    if (parent && resortData.indexOf(parent) === -1) {
                        resortData.push(parent);
                    }
                }
            }
            for (const node of resortData) {
                node.children = this.getChildren(node);
            }
            this.sortTreeNode(true);
            for (const node of loadedData) {
                if (!node.expanded) {
                    this.setExpanded(node, true);
                }
            }
            for (const node of existData) {
                const parent = this.getItems(node[this.setting.pid]);
                if (expandData.indexOf(parent) === -1) {
                    expandData.push(parent);
                    if (!parent.expanded) {
                        this.setExpanded(parent, true);
                    }
                }
                if (!node.expanded) {
                    this.setExpanded(node, true);
                }
            }
            return [loadedData, expandData];
        };

        /**
         *
         * @param parent
         * @param node
         * @private
         */
        _getNodesParents(parents, nodes) {
            for (const node of nodes) {
                const parent = this.getParent(node);
                if (parent) {
                    const paths = this.getFullPathNodes(parent.full_path);
                    for (const p of paths) {
                        if (parents.indexOf(p) === -1) {
                            parents.push(p);
                        }
                    }
                }
                if (this.getItems(node.ledger_id) && node.children.length > 0) {
                    parents.push(node);
                }
            }
        }

        /**
         * 因为提交其他数据，引起的树结构数据更新，调用该方法
         *
         * @param data - 更新的数据 {update, create, delete}
         * @param {function} callback - 界面刷新
         */
        loadPostData(data, callback) {
            const result = {}, parents = [];
            if (data.update) {
                result.update = this._updateData(data.update);
                this._getNodesParents(parents, result.update);
            }
            if (data.create) {
                result.create = this._loadData(data.create);
                this._getNodesParents(parents, result.create);
            }
            if (data.delete) {
                result.delete = this._freeData(data.delete);
                this._getNodesParents(parents, result.delete);
            }
            parents.sort((a, b) => {
                return b.level - a.level;
            });
            for (const parent of parents) {
                treeCalc.calculateNode(this, parent, this.setting.calcFields, this.setting.calcFun);
            }
            result.update = result.update ? result.update.concat(parents) : parents;
            callback(result);
        }

        /**
         * 以下方法需等待响应, 通过callback刷新界面
         */
        /**
         * 加载子节点
         * @param {Object} node
         * @param {function} callback
         */
        loadChildren (node, callback) {
            const self = this;
            const url = this.setting.preUrl ? this.setting.preUrl + '/get-children' : 'get-children';
            postData(url, this.getNodeKeyData(node), function (data) {
                self._loadData(data);
                callback();
            });
        };
        /**
         * 树结构基本操作
         * @param {String} url - 请求地址
         * @param {Object} node - 操作节点
         * @param {String} type - 操作类型
         * @param {function} callback - 界面刷新
         */
        baseOperation (url, node, type, callback) {
            const self = this;
            const data = {
                id: node[this.setting.id],
                postType: type
            };
            postData(url, data, function (datas) {
                self.loadPostData(datas, callback);
            });
        };
        /**
         * 节点数据编辑
         * @param {String} url - 请求地址
         * @param {Array|Object} updateData - 需更新的数据
         * @param {function} callback - 界面刷新
         */
        update (url, updateData, callback) {
            const self = this;
            postData(url, updateData, function (datas) {
                self.loadPostData(datas, callback);
            }, function () {
                if (updateData instanceof Array) {
                    const result = [];
                    for (const data of updateData) {
                        result.push(self.getItems(data[self.setting.id]));
                    }
                    callback(result)
                } else {
                    callback([self.getItems(updateData[self.setting.id])]);
                }
            });
        };
        /**
         * 复制粘贴整块（目前仅可粘贴为后项）
         * @param {String} url - 请求地址
         * @param {Object} node - 操作节点
         * @param {Array} block - 被复制整块的节点列表
         * @param {function} callback - 界面刷新
         */
        pasteBlock (url, node, block, callback) {
            const self = this;
            const data = {
                id: node[self.setting.id],
                block: block
            };
            postData(url, data, function (datas) {
                self.loadPostData(datas, callback);
            });
        };
        /**
         * 提交数据
         * @param {String} url - 请求地址
         * @param {Object} node - 当前选中节点
         * @param {Object} data - 提交的数据
         * @param {function} callback - 界面刷新
         */
        postData (url, node, data, callback) {
            const self = this;
            if (node) {
                data.id = node[self.setting.id];
            }
            postData(url, data, function (datas) {
                const result = {};
                if (datas.update) {
                    result.update = self._updateData(datas.update);
                }
                if (datas.create) {
                    result.create = self._loadData(datas.create);
                }
                if (datas.delete) {
                    result.delete = self._freeData(datas.delete);
                }
                if (datas.expand) {
                    const [create, update] = self._loadExpandData(datas.expand);
                    result.create = result.create ? result.create.concat(create) : create;
                    result.expand = update;
                }
                callback(result);
            });
        };
    }

    class StageTree extends FxTree {
        /**
         * 构造函数
         */
        constructor (setting) {
            super(setting);
            // stage关联索引
            this.stageItems = {};
        }
        /**
         * 加载数据(初始化), 并给数据添加部分树结构必须数据
         * @param datas
         */
        loadDatas (datas) {
            super.loadDatas(datas);
            // 清空旧数据
            this.stageItems = {};
            // 加载全部数据
            for (const data of this.datas) {
                const keyName = itemsPre + data[this.setting.stageId];
                this.stageItems[keyName] = data;
            }
        }
        getStageItems(id) {
            return this.stageItems[itemsPre + id];
        }

        loadStageData(datas, fieldPre, fields) {
            datas = datas instanceof Array ? datas : [datas];
            const loadedData = [];
            for (const data of datas) {
                let node = this.getStageItems(data.lid);
                if (node) {
                    for (const prop of fields) {
                        if (data[fieldPre + prop] !== undefined) {
                            node[fieldPre + prop] = data[prop];
                        }
                    }
                    loadedData.push(node);
                }
            }
        }

        loadPreStageData(preStageData) {
            this.loadStageData(curStageData, 'pre_', this.setting.updateFields);
        }

        loadCurStageData(curStageData) {
            this.loadStageData(curStageData, '', this.setting.updateFields);
        }

        /**
         * 加载数据(动态)，只加载不同部分
         * @param {Array} datas
         * @return {Array} 加载到树的数据
         * @privateA
         */
        _updateStageData (datas) {
            datas = datas instanceof Array ? datas : [datas];
            const loadedData = [];
            for (const data of datas) {
                let node = this.getStageItems(data.lid);
                if (node) {
                    for (const prop of this.setting.updateFields) {
                        if (data[prop] !== undefined) {
                            node[prop] = data[prop];
                        }
                    }
                    loadedData.push(node);
                }
            }
            return loadedData;
        };
        /**
         *
         * @param parent
         * @param node
         * @private
         */
        _getNodesParents(parents, nodes) {
            for (const node of nodes) {
                const parent = this.getParent(node);
                if (parent) {
                    const paths = this.getFullPathNodes(parent.full_path);
                    for (const p of paths) {
                        if (parents.indexOf(p) === -1) {
                            parents.push(p);
                        }
                    }
                }
                if (node.children && node.children.length > 0) {
                    parents.push(node);
                }
            }
        }

        /**
         * 提交数据至后端，返回的前端树结构应刷新的部分
         * StageTree仅有更新CurStage部分，不需要增删
         *
         * @param data - 需要更新的数据
         * @returns {Array} - 界面需要刷新的数据
         */
        loadPostStageData(data) {
            let result, parents = [];
            if (data) {
                result = this._updateStageData(data);
                this._getNodesParents(parents, result);
            }
            result = result ? result.concat(parents) : parents;
            result.sort((a, b) => {
                return b.level - a.level;
            });
            for (const node of result) {
                treeCalc.calculateNode(this, node);
            }
            return result;
        }
    }

    class MasterTree extends FxTree {
        /**
         * 构造函数
         */
        constructor (setting) {
            super(setting);
            // 关联索引
            this.masterItems = {};
        }
        /**
         * 加载数据(初始化), 并给数据添加部分树结构必须数据
         * @param datas
         */
        loadDatas (datas) {
            super.loadDatas(datas);
            // 清空旧数据
            this.masterItems = {};
            // minor数据缓存
            this.minorData = {};
            // 加载全部数据
            for (const data of this.datas) {
                const keyName = itemsPre + data[this.setting.masterId];
                this.masterItems[keyName] = data;
            }
        }

        /**
         * 根据关联id，查找节点
         * @param id
         * @returns {*}
         */
        getMasterItems(id) {
            return this.masterItems[itemsPre + id];
        }
        /**
         * 加载关联数据
         *
         * @param {Array|Object}datas - 需要关联的数据
         * @param {String} fieldPre - 关联字段前缀（关联结果）
         * @param {Array} fields - 关联字段
         * @returns {Array}
         */
        loadMinorData(datas, fieldSuf, fields) {
            if (!datas) { return; }
            datas = datas instanceof Array ? datas : [datas];
            this.minorData[fieldSuf] = datas;
            const loadedData = [];
            for (const data of datas) {
                let node = this.getMasterItems(data[this.setting.minorId]);
                if (node) {
                    for (const prop of fields) {
                        if (data[prop] !== undefined) {
                            node[prop + fieldSuf] = data[prop];
                        }
                    }
                    loadedData.push(node);
                }
            }
            return loadedData;
        }

        /**
         * 展开至最底层项目节
         */
        expandByCalcFields() {
            const self = this;
            this.expandByCustom(function (node) {
                for (const field of self.setting.calcFields) {
                    if (node[field]) {
                        return true;
                    }
                }
                return false;
            })
        }
    }

    if (type === 'base') {
        return new BaseTree(setting);
    } else if (type === 'stage') {
        return new StageTree(setting);
    } else if (type === 'ledger') {
        return new LedgerTree(setting);
    } else if (type === 'measure') {
        return new MeasureTree(setting);
    } else if (type === 'master') {
        return new MasterTree(setting);
    }
};

const treeCalc = {
    getMaxLevel: function (tree) {
        return Math.max.apply(Math, tree.datas.map(function(o) {return o.level}));
    },
    calculateNode: function (tree, node) {
        if (node.children && node.children.length > 0) {
            const gather = node.children.reduce(function (rst, x) {
                const result = {};
                const fieldCalc = function (field) {
                    if (rst[field]) {
                        result[field] = x[field] ? _.round(rst[field] + x[field], 6) : rst[field];
                    } else {
                        result[field] = x[field] ? x[field] : undefined;
                    }
                };
                for (const cf of tree.setting.calcFields) {
                    result[cf] = _.round(_.add(rst[cf], x[cf]), 8);
                    //fieldCalc(cf);
                }
                return result;
            });
            // 汇总子项
            for (const cf of tree.setting.calcFields) {
                //node[cf] = _.sumBy(node.children, cf);
                if (gather[cf]) {
                    node[cf] = gather[cf];
                } else {
                    node[cf] = null;
                }
            }
        }
        // 自身运算
        if (tree.setting.calcFun) {
            tree.setting.calcFun(node);
        }
    },
    calculateLevelNode: function (tree, level) {
        const nodes = tree.datas.filter((n) => { return n.level === level });
        for (const node of nodes) {
            this.calculateNode(tree, node);
        }
    },
    calculateAll: function (tree) {
        for (let i = this.getMaxLevel(tree); i >= 0; i--) {
            this.calculateLevelNode(tree, i);
        }
    },
    calculateParent: function (tree, node) {
        const nodes = tree.getFullPathNodes(node.full_path);
        nodes.sort((a, b) => {
            return b.level - a.level;
        });
        for (const n of nodes) {
            this.calculateNode(tree, n);
        }
        return nodes;
    }
};
