/**
 * Created by Mai on 2017/4/1.
 */

var Bills = {
    createNew: function (project) {
        var billsTreeSetting = {
            id: 'ID',
            pid: 'ParentID',
            nid: 'NextSiblingID',
            rootId: -1,
            autoUpdate: true
        };

        // 用户定义private方法
        var tools = {
            coverseTreeUpdateData: function (datas, projectID) {
                var updateDatas = [];
                datas.forEach(function (data) {
                    var updateData = {};
                    data.data.projectID = projectID;
                    if (data.type === idTree.updateType.new) {
                        updateData.updateType = 'ut_create';
                        updateData.updateData = data.data;
                    } else if (data.type === idTree.updateType.update) {
                        updateData.updateType = 'ut_update';
                        updateData.updateData = data.data;
                    } else if (data.type === idTree.updateType.delete) {
                        updateData.updateType = 'ut_delete';
                        updateData.updateData = data.data;
                    }
                    updateDatas.push(updateData);
                });
                return updateDatas;
            },
            formatBillsUpdateData: function (data) {
                let uData = JSON.parse(JSON.stringify(data));
                delete uData.feesIndex;
                delete uData.flagsIndex;
                if (uData.quantity) {
                    uData.quantity = uData.quantity.toFixed(2);
                }
                if (uData.fees) {
                    for (let fee of uData.fees) {
                        if(fee.unitFee) fee.unitFee = fee.unitFee.toFixed(2);
                        if(fee.totalFee) fee.totalFee = fee.totalFee.toFixed(2);
                        if(fee.tenderUnitFee) fee.tenderUnitFee = fee.tenderUnitFee.toFixed(2);
                        if(fee.tenderTotalFee) fee.tenderTotalFee = fee.tenderTotalFee.toFixed(2);
                    }
                }
                return uData;
            }
        };

        // 所有通过this访问的属性，都不应在此单元外部进行写入操作
        var bills = function (proj) {
            this.project = proj;
            this.datas = null;
            this.tree = idTree.createNew(billsTreeSetting);

            var sourceType = ModuleNames.bills;
            this.getSourceType = function () {
                return sourceType;
            }
            proj.registerModule(ModuleNames.bills, this);
        };

        // 从后台获取数据
        /*bills.prototype.pullData = function (){
            this.project.pullData(
                '/bills/getData',
                {projectID: this.project.ID},
                function(result){
                    if (result.error ===0){
                        this.loadDatas(result.data);
                    }
                    else {
                        // to do: ?错误处理需要细化
                        alert(result.message);
                    }
                },
                function (){}// to do: 错误处理需要细化
            )
        };*/

        // prototype用于定义public方法
        bills.prototype.loadData = function (datas) {
            parseIDs(datas);
            this.datas = datas;
            // generate Fees & Flags Index, For View & Calculate
            this.datas.forEach(function (data) {
                if (data.quantity) {
                    data.quantity = parseFloat(data.quantity);
                }
                data.feesIndex = getFeeIndex(data.fees);
                data.flagsIndex = {};
                if (data.flags) {
                    data.flags.forEach(function (flag) {
                        data.flagsIndex[flag.fieldName] = flag;
                    });
                }
            });
            // datas load to Tree
            this.tree.loadDatas(this.datas);
        };
        bills.prototype.addDatasToList = function (new_datas) {
            let me = this;
            if(me.datas && Array.isArray(me.datas)){
                for(let d of new_datas){
                    me.datas.push(d);
                }
            }
        };
        bills.prototype.setMaxID = function (ID) {
            this.tree.maxNodeID(ID);
        };

        // 提交数据后的错误处理方法
        bills.prototype.doAfterUpdate = function(err, data){
             // console.log(data)
            if(data.quantityRefresh){
                this.refreshDatas(data,'quantity');
            }
        };
        bills.prototype.getBillByCode = function(code){
            let sortData = _.sortBy(projectObj.project.Bills.datas,'code');
            return _.find(sortData, function(b) {
                if(b.code&&b.code.indexOf(code)!=-1){
                    return true;
                }else {
                    return false;
                }
            });
        };
        bills.prototype.refreshDatas = function(data,fieldName){
            var dataIndex = _.findIndex(this.datas,function(item) {
                return item.ID ==data.billID;
            });
            this.datas[dataIndex][fieldName] = data[fieldName];
            if(fieldName=='quantity'){
                this.datas[dataIndex]['isFromDetail']=1
            }
            var controller = projectObj.mainController;
            var selected = controller.sheet.getSelections();
            var col =   _.findIndex(project.projSetting.main_tree_col.cols,function (col) {
                return col.data.field ==fieldName;
            });
            controller.sheet.getCell(selected[0].row,col).value(data[fieldName]);
        };

        bills.prototype.getCounterData = function (count) {
            var updateData = {'projectID': this.project.ID()};
            if (count) {
                updateData[this.getSourceType()] = this.tree.maxNodeID() + count;
            } else {
                updateData[this.getSourceType()] = this.tree.maxNodeID() + 1;
            }
            return updateData;
        };
        bills.prototype.insertSpecialBill=function(parentId, nextSiblingId,isUserAdd,type){
            var insertData = this.tree.getInsertData(parentId, nextSiblingId, true);
            var that = this, newData = null;
            insertData.forEach(function (data) {
                if (data.type === idTree.updateType.new) {
                    if(isUserAdd==true){//如果是用户新增的
                        data.data.isAdd = 1;
                    }
                    data.data.type = type;
                    newData = data.data;
                }
            });
            this.project.pushNow('insertBills', [this.getSourceType(), this.project.projCounter()],
                [ tools.coverseTreeUpdateData(insertData, this.project.ID()), this.getCounterData()]);
            //project.pushNow('insertBills', ModuleNames.bills, tools.coverseTreeUpdateData(insertData));

            this.datas.push(newData);
            return this.tree.insertByData(newData,parentId, nextSiblingId, true);
        };
        bills.prototype.insertBills = function (parentId, nextSiblingId) {
            var insertData = this.tree.getInsertData(parentId, nextSiblingId, true);
            var that = this, newData = null;
            insertData.forEach(function (data) {
                if (data.type === idTree.updateType.new) {
                    data.data.type = billType.BILL;
                    if (projectObj.project.property.valuationType === commonConstants.ValuationType.BOQ) {
                        data.data.unitPriceAnalysis = 1;
                    }
                    newData = data.data;
                }
            });
            this.project.pushNow('insertBills', [this.getSourceType(), this.project.projCounter()],
                [ tools.coverseTreeUpdateData(insertData, this.project.ID()), this.getCounterData()]);
            //project.pushNow('insertBills', ModuleNames.bills, tools.coverseTreeUpdateData(insertData));

            this.datas.push(newData);
            return this.tree.insertByData(newData,parentId, nextSiblingId, true);
        };
        bills.prototype.insertStdBills = function (parentId, nextSiblingId, stdBillsData) {
            var insertData = this.tree.getInsertData(parentId, nextSiblingId, true);
            var newData = null, that = this;
            insertData.forEach(function (data) {
                if (data.type === idTree.updateType.new) {
                    if (projectObj.project.property.valuationType === commonConstants.ValuationType.BOQ) {
                        data.data.unitPriceAnalysis = 1;
                    }
                    data.data.code = that.newFormatCode(stdBillsData.code);
                    data.data.name = stdBillsData.name;
                    data.data.unit = stdBillsData.unit;
                    // 工程量计算规则
                    data.data.ruleText = stdBillsData.ruleText;
                    // 说明（清单备注）
                    data.data.comments = stdBillsData.comments;
                    //zhong 特征及内容
                    data.data.jobContent = stdBillsData.jobContent;
                    data.data.itemCharacter = stdBillsData.itemCharacter;
                    data.data.jobContentText = stdBillsData.jobContentText;
                    data.data.itemCharacterText = stdBillsData.itemCharacterText;
                    data.data.programID = stdBillsData.engineering;
                    data.data.type = stdBillsData.type;//插入清单类型
                    //Vincent
                    data.data.billsLibId = stdBillsData.billsLibId;//添加清单库ID
                    //zhong
                    newData = data.data;
                }
            });
            this.project.pushNow('insertStdBills', [this.getSourceType(), this.project.projCounter()],
                [ tools.coverseTreeUpdateData(insertData, this.project.ID()), this.getCounterData()]);

            this.datas.push(newData);
            return this.tree.insertByData(newData, parentId, nextSiblingId, true);
        };
        bills.prototype.deleteBills = function (node) {
            let deleteNode = function (node) {
                this.project.Ration.deleteByBills([node]);
                // this.project.VolumePrice.deleteByBills([node]);
                return this.tree.delete(node);
            }
            var deleteData = this.tree.getDeleteData(node);
            var ration_glj =projectObj.project.ration_glj;
            // let modules =[ModuleNames.bills, ModuleNames.ration, ModuleNames.ration_glj, ModuleNames.volume_price];
            let modules =[ModuleNames.bills, ModuleNames.ration, ModuleNames.ration_glj];
            let deleteDatas=[tools.coverseTreeUpdateData(deleteData, this.project.ID()),
                this.project.Ration.getDeleteDataByBill([node]), ration_glj.getDeleteDataByBills(deleteData),
                // this.project.VolumePrice.getDeleteDataByBills([node])
            ];
            project.ration_glj.deleteByBills(deleteData);
            project.quantity_detail.deleteByBills(deleteData);
            project.pushNow('deleteBills', modules, deleteDatas);

            this.datas.splice(this.datas.indexOf(node.data), 1);
            return this.tree.delete(node);
        };

        bills.prototype.removeByID = function(ID){
            _.remove(this.datas,{'ID':ID});
        };

        bills.prototype.singleDeleteBills=function(node,controller){//只删除选中的分部，不删除其子项
            let updateData = {};
            let updateNode={};
            let newParent=null;
            let me = this;
            if(node){
                if(node.children.length>0){//有子项
                    if(node.preSibling){//有前兄弟，则子项变成前兄弟的子项
                        if(node.preSibling.children.length>0){//前兄弟有子项,
                            let preNode = node.preSibling.children[node.preSibling.children.length-1];
                            updateData[preNode.data.ID]={
                                NextSiblingID:node.children[0].data.ID
                            };
                            updateNode[preNode.data.ID] = preNode;
                        }
                        for(let i=0;i<node.children.length;i++){
                            updateData[node.children[i].data.ID]={
                                ParentID:node.preSibling.data.ID
                            };
                            updateNode[node.children[i].data.ID]=node.children[i];
                        }
                        newParent=node.preSibling;
                    }else {//没有前兄弟,则子项升一级
                        let parent = node.parent;
                        for(let i=0;i<node.children.length;i++){
                            updateData[node.children[i].data.ID]={
                                ParentID:parent.data.ID
                            };
                            updateNode[node.children[i].data.ID]=node.children[i];
                            if(node.nextSibling&&i == node.children.length-1){//最后一个子项，在有后兄弟的情况下，作为后兄弟的前兄弟
                                updateData[node.children[i].data.ID].NextSiblingID = node.nextSibling.data.ID;
                            }
                        }


               /*         let parent = node.nextSibling.parent;
                        for(let i=0;i<node.children.length;i++){
                            if(i == node.children.length-1&&node.nextSibling){//最后一个子项，在有后兄弟的情况下，作为后兄弟的前兄弟
                                updateData[node.children[i].data.ID]={
                                    ParentID:parent.data.ID,
                                    NextSiblingID:node.nextSibling.data.ID
                                };
                            }else {
                                updateData[node.children[i].data.ID]={
                                    ParentID:parent.data.ID
                                };
                            }
                            updateNode[node.children[i].data.ID]=node.children[i];
                        }*/
                        newParent=parent;
                    }
                }
                $.bootstrapLoading.start();
                CommonAjax.post("/bills/singleDelete", {updateData:updateData,projectID:node.data.projectID,user_id:userID,ID:node.data.ID}, function () {
                    //更新缓存
                    console.log(updateNode);
                    _.remove(me.datas,{'ID':node.data.ID});
                    for(let n_key in updateNode){
                        let updateDoc =  updateData[n_key];
                        for(let u_key in updateDoc){
                            updateNode[n_key].data[u_key] =updateDoc[u_key];
                        }
                    }
                    controller.singleDelete();//删除树节点
                    me.tree.singleDelete(node.source);
                    project.calcProgram.calcAndSave(newParent);
                    $.bootstrapLoading.end();
                }, function () {
                    $.bootstrapLoading.end();
                });
            }

        };
        bills.prototype.upMoveBills = function (node) {
            var upMoveData = node.getUpMoveData();
            project.pushNow('upMoveBills', this.getSourceType(), tools.coverseTreeUpdateData(upMoveData, this.project.ID()));

            return node.upMove();
        };
        bills.prototype.multiUpMoveBills = function (tree, nodes) {
            const upMoveData = tree.getMultiUpMoveData(nodes);;
            project.pushNow('upMoveBills', this.getSourceType(), tools.coverseTreeUpdateData(upMoveData, this.project.ID()));
            nodes.forEach(node => node.upMove());
        };
        bills.prototype.downMoveBills = function (node) {
            var downMoveData = node.getDownMoveData();
            project.pushNow('downMoveBills', this.getSourceType(), tools.coverseTreeUpdateData(downMoveData, this.project.ID()));

            return node.downMove();
        };
        bills.prototype.multiDownMoveBills = function (tree, nodes) {
            const downMoveData = tree.getMultiDownMoveData(nodes);
            project.pushNow('downMoveBills', this.getSourceType(), tools.coverseTreeUpdateData(downMoveData, this.project.ID()));
            for (let i = nodes.length - 1; i >= 0; i--) {
                nodes[i].downMove();
            }
        };
        bills.prototype.upLevelBills = function (node) {
            var upLevelData = node.getUpLevelData();
            project.pushNow('upLevelBills', this.getSourceType(), tools.coverseTreeUpdateData(upLevelData, this.project.ID()));

            return node.upLevel();
        };
        bills.prototype.multiUpLevelBills = function (tree, nodes) {
            const upLevelData = tree.getMultiUpLevelData(nodes);
            project.pushNow('upLevelBills', this.getSourceType(), tools.coverseTreeUpdateData(upLevelData, this.project.ID()));
            nodes.forEach(node => node.upLevel());
        };
        bills.prototype.downLevelBills = function (node) {
            var downLevelData = node.getDownLevelData();
            this.setQuantityAfterDownLevel(node,downLevelData);
            project.pushNow('downLevelBills', [this.getSourceType()], [tools.coverseTreeUpdateData(downLevelData, this.project.ID())]);

            return node.downLevel();
        };
        bills.prototype.multiDownLevelBills = function (tree, nodes) {
            const downLevelData = tree.getMultiDownLevelData(nodes);
            const firstNode = nodes[0];
            this.setQuantityAfterDownLevel(firstNode, downLevelData);
            project.pushNow('downLevelBills', [this.getSourceType()], [tools.coverseTreeUpdateData(downLevelData, this.project.ID())]);
            nodes.forEach(node => node.downLevel());
        };
        bills.prototype.setQuantityAfterDownLevel = function (node,downLevelData) {
            if(projectObj.project.projectInfo.property && projectObj.project.projectInfo.property.valuationType == "ration"){//工程量清单项目中，将B降级为A的子项后应清空A的工程量
                let preNode = node.preSibling;
                for(let d of downLevelData){
                    if(preNode && preNode.getID()==d.data.ID){
                        d.data.quantity = "0";
                        d.data.quantityEXP = "";
                        preNode.data.quantity = "0";
                        preNode.data.quantityEXP = "";
                    }
                }
            }

        };
        bills.prototype.updateField = function (node, field, newValue,toBX) {//当toBX为true时类型改为补项
            calcFees.setFee(node.data, field, newValue);
            let updateData = [];
            let data = {'ID': node.getID(), 'projectID': this.project.ID()};
            data[field] = newValue;
            if(toBX == true){
                data.type = billType.BX
            }
            updateData.push({'updateType': 'ut_update', 'updateData': tools.formatBillsUpdateData(data)});
            this.project.pushNow('updateBills', this.getSourceType(), updateData);
        };

        bills.prototype.getUpdateAllData = function () {
            let updateData = [];
            for (let data of this.datas) {
                updateData.push({'updateType': 'ut_update', 'updateData': tools.formatBillsUpdateData(data)});
            }
            return updateData;
        };

        bills.prototype.updateAll = function () {
            this.project.pushNow('updateAllBills', this.getSourceType(), this.getUpdateAllData());
        };

        bills.prototype.getUpdateNodesData = function (nodes) {
            let updateData = [];
            for (let node of nodes) {
                updateData.push({'updateType': 'ut_update', 'updateData': tools.formatBillsUpdateData(node.data)});
            }
            return updateData;
        }

        bills.prototype.updateNodes = function (nodes, updateNow) {
            if (updateNow) {
                this.project.pushNow('updateBills', this.getSourceType(), this.getUpdateNodesData(nodes));
            } else {
                this.project.push(this.getSourceType(), this.getUpdateNodesData(nodes));
            }
        };

        bills.prototype.sameStdCode = function (stdCode, filterCode) {
            let reg = new RegExp('^' + stdCode), matchs= [];
            for (let data of this.datas) {
                if (data.code && data.code.length === 12 && reg.test(data.code) && data.code !== filterCode) {
                    matchs.push(data.code);
                }
            }
            return matchs;
        }

        bills.prototype.newFormatCode = function (stdCode, filterCode) {
            let matchs = this.sameStdCode(stdCode, filterCode);
            let format = function (Number) {
                let s = Number + '';
                while (s.length < 3) {
                    s = '0' + s;
                }
                return s;
            }
            for (let i = 0; i <= matchs.length; i++) {
                let formatCode = stdCode + format(i+1);
                if (matchs.indexOf(formatCode) === -1) {
                    return formatCode;
                }
            }
        };

        bills.prototype.replaceBills = function (node, stdBillsData, code) {
            let updateData = [];
            node.data.code = code;
            if (stdBillsData) {
                node.data.name = stdBillsData.name;
                node.data.unit = stdBillsData.unit;
                // 工程量计算规则
                node.data.ruleText = stdBillsData.ruleText;
                // 说明（补注）
                node.data.comments = stdBillsData.recharge;
                // 工作内容
               /* node.data.jobContent = stdBillsData.jobContent;
                node.data.jobContentText = stdBillsData.jobContentText;*/
                // 特征
               /* node.data.itemCharacter = stdBillsData.itemCharacter;
                node.data.itemCharacterText = stdBillsData.itemCharacterText;*/
                node.data.programID = stdBillsData.engineering;
                node.data.billsLibId = stdBillsData.billsLibId;
            }
            updateData.push({'updateType': 'ut_update', 'updateData': tools.formatBillsUpdateData(node.data)});

            this.project.pushNow('replaceBills', this.getSourceType(), updateData);
            return node;            
        };
        bills.prototype.sameStdCodeBillsData = function (stdCode) {
            let reg = new RegExp('^' + stdCode);
            for (let data of this.datas) {
                if (data.code && data.code.length === 12 && reg.test(data.code) && /^[\d]+$/.test(data.code)) {
                    return data;
                }
            }
            return null;            
        };

        bills.prototype.getSubdivisionProjectLeavesID=function () {//取所有分部分项工程清单叶子节点ID
            let roots = projectObj.project.mainTree.roots;//所有根节点
            let subdivisionNode = null;
            for(let r of roots){
               if(isFlag(r.data)&&r.data.flagsIndex.fixed.flag==fixedFlag.SUB_ENGINERRING) {
                   subdivisionNode = r;
                   break;
               }
            }
            let nodes = this.getLeavesBillNodes(subdivisionNode);
            return  _.map(nodes,"data.ID");
        };


        bills.prototype.getTechLeavesID=function () {//取所有分计算技术措施项目清单叶子节点ID
            let items = projectObj.project.mainTree.items;//所有节点;
            let techNode = null;
            for(let item of items){
                if(this.flagEquals(item,fixedFlag.CONSTRUCTION_TECH)){
                    techNode = item;
                    break;
                }
            }
            let nodes = this.getLeavesBillNodes(techNode);
            return  _.map(nodes,"data.ID");
        };
        bills.prototype.getLeavesBillNodes = function (rnode) {//取该节点下的所有清单叶子节点
            let leaves = [];
            getLeaves(rnode,leaves);
            return leaves;

            function  getLeaves(node,children) {
                if(node){
                    if(node.source.children.length>0){
                        for(let c of node.children){
                            getLeaves(c,children)
                        }
                    }else {
                        children.push(node);
                    }
                }
            }
        };
        bills.prototype.getRootNode = function (node) {
            if(node.parent){
                return this.getRootNode(node.parent);
            }else {
                return node;
            }
        };
        bills.prototype.isFBFX = function (node) {//判读是否属于分部分项部分
           let rootNode = this.getRootNode(node);
            if(this.flagEquals(rootNode,fixedFlag.SUB_ENGINERRING)){
                return true;
            }else {
                return false;
            }
        };
        bills.prototype.isFXorBX=function (node) {//是分项或者补项
            if(node.sourceType == projectObj.project.Bills.getSourceType()){
                return   node.data.type == billType.FX || node.data.type == billType.BX;
            }
            return false;
        };
        bills.prototype.nodeFlagCheck = function (node,fixedFlag) {//按flag判断节点是否属于该类型（包括子节点）
            let me = this;
            let flagCheck = function (checkNode) {
                if(me.flagEquals(checkNode,fixedFlag)){
                    return true;
                }else {
                    if(checkNode.parent){
                        return flagCheck(checkNode.parent);
                    }else {
                        return false;
                    }
                }
            };
            return flagCheck(node);
        };

        bills.prototype.flagEquals = function (node,fixedFlag) {
            if(isFlag(node.data)&&node.data.flagsIndex.fixed.flag==fixedFlag){
                return true;
            }
            return false
        };
        bills.prototype.getNodeByFlag = function(node,flag){//取节点类型，返回本身或父项节点
            if(node){
                if(isFlag(node.data)&&node.data.flagsIndex.fixed.flag==flag){
                    return node;
                }else {
                    return this.getNodeByFlag(node.parent,flag);
                }
            }else {
                return null;
            }
        };
        bills.prototype.isTopThreeNode = function (node) {//是否为前三项，即大项1、2、3项
            return this.flagEquals(node,fixedFlag.SUB_ENGINERRING)||this.flagEquals(node,fixedFlag.MEASURE)||this.flagEquals(node,fixedFlag.OTHER)//是大项1、2、3项的编号设置为只读
        };
        bills.prototype.isEngineerEst = function (node) {//判断是否是“专业工程暂估价”节点或者子项
           return this.nodeFlagCheck(node,fixedFlag.ENGINEERING_ESITIMATE);
            //return node && isFlag(node.data)&&node.data.flagsIndex.fixed.flag==fixedFlag.ENGINEERING_ESITIMATE;
        };
        bills.prototype.isTotalService = function (node) {//判断是否是“总承包服务费”节点
            return this.nodeFlagCheck(node,fixedFlag.TURN_KEY_CONTRACT);
        };
        bills.prototype.isClaimVisa = function (node) {//判断是否是“签证及索赔计价”节点
            return this.nodeFlagCheck(node,fixedFlag.CLAIM_VISA);
        };
        bills.prototype.isMeasure = function (node) {//判读是否属于措施项目部分
            let rootNode = this.getRootNode(node);
            if(isFlag(rootNode.data)&&rootNode.data.flagsIndex.fixed.flag==fixedFlag.MEASURE){
                return true;
            }else {
                return false;
            }
        };
        bills.prototype.hasFlags = function (node) {
            return isFlag(node.data);
        };
        bills.prototype.isBX = function (node) {//判读是否属于补项
            if(node && node.sourceType == ModuleNames.bills&&node.data.type==billType.BX){
                return  true;
            }
            return false;
        };
        bills.prototype.isTechMeasure = function (node) {//判读是否属于技术措施项目部分
            let techMeasureCheck = function (checkNode) {
                if(isFlag(checkNode.data)&&checkNode.data.flagsIndex.fixed.flag==fixedFlag.CONSTRUCTION_TECH){
                    return true;
                }else {
                    if(checkNode.parent){
                        return techMeasureCheck(checkNode.parent);
                    }else {
                        return false;
                    }
                }
            }
            return techMeasureCheck(node);
        };

        bills.prototype.isEngineeringCost = function (node) {//判断这个节点是否是工程造价节点
            if(isFlag(node.data)&&node.data.flagsIndex.fixed.flag==fixedFlag.ENGINEERINGCOST){
                return true;
            }else {
                return false;
            }
        };
        bills.prototype.isTotalCost = function (node) {//判断这个节点是否是总造价
            if(isFlag(node.data)&&node.data.flagsIndex.fixed.flag==fixedFlag.TOTAL_COST){
                return true;
            }else {
                return false;
            }
        };
        bills.prototype.calcEngineeringCostNode=function(controller){
            let roots =  controller.tree.roots;
            for(let root of roots){
                if(project.Bills.isEngineeringCost(root)==true){
                    project.calcProgram.calcAndSave(root);
                    break;
                }
            }
        };
        bills.prototype.getEngineeringCostNode=function(controller){//取工程造价节点
            let roots =  controller.tree.roots;
            for(let root of roots){
                if(project.Bills.isEngineeringCost(root)==true){
                    return root;
                }
            }
        };
        bills.prototype.getTotalCostNode=function(controller){//取工程造价总金额节点
            let roots =  controller.tree.roots;
            for(let root of roots){
                if(project.Bills.isTotalCost(root)==true){
                    return root;
                }
            }
        };

        bills.prototype.getFBFXNode = function (controller) {//取分部分项工程节点
            let roots =  controller.tree.roots;
            for(let root of roots){
                if(isFlag(root.data)&&root.data.flagsIndex.fixed.flag==fixedFlag.SUB_ENGINERRING){
                    return root;
                }
            }
        };
        bills.prototype.getMeasureNode = function (controller) {//取措施项目工程节点
            let roots =  controller.tree.roots;
            for(let root of roots){
                if(isFlag(root.data)&&root.data.flagsIndex.fixed.flag==fixedFlag.MEASURE){
                    return root;
                }
            }
        };
        bills.prototype.getTechNode=function () {//取技术措施项目节点
            let items = projectObj.project.mainTree.items;//所有节点;
            let techNode = null;
            for(let item of items){
                if(isFlag(item.data)&&item.data.flagsIndex.fixed.flag==fixedFlag.CONSTRUCTION_TECH){
                    techNode = item;
                    break;
                }
            }
           return techNode;
        };

        bills.prototype.deleteSelectedNode=function(){//删除选中单行时的节点
            let controller = projectObj.mainController, project = projectObj.project;
            let selected = controller.tree.selected, parent = selected.parent;
            if (selected) {
                if (selected.sourceType === project.Bills.getSourceType()) {
                    if (cbTools.isUsedByFormula(selected)){
                        alert('该清单行被其它公式结点引用，不允许删除！');
                        return;
                    }
                    project.Bills.deleteBills(selected.source);
                    controller.delete();
                } else if (selected.sourceType === project.Ration.getSourceType()) {
                    project.Ration.delete(selected.source);
                    controller.delete();
                }else if(selected.sourceType==ModuleNames.ration_glj){
                    project.ration_glj.updataOrdelete(selected.source);
                }
                if(project.Bills.isFBFX(selected)) { //判断是否属于分部分项工程 ，是的话才需要做计取安装费计算
                    project.installation_fee.calcInstallationFee(function (isChange) {
                        if(isChange){
                            project.calcProgram.calcAllNodesAndSave();
                        }else {
                            if(parent){
                                projectObj.converseCalculateBills(parent);
                            }else { //删除的是大项费用要重新计算工程造价节点
                                project.Bills.calcEngineeringCostNode(controller);
                            }
                            project.projectGLJ.loadData();
                        }
                    });
                }else {
                    if(parent){
                        projectObj.converseCalculateBills(parent);
                    }else { //删除的是大项费用要重新计算工程造价节点
                        project.Bills.calcEngineeringCostNode(controller);
                    }
                    project.projectGLJ.loadData();
                }
            }
        };
        bills.prototype.deleteSelectedNodes=function(isDeleteChild = false, parentNode = null) {//删除选中多行时的节点
            let controller = projectObj.mainController, project = projectObj.project;
            let selected = controller.tree.selected, parent = selected.parent;
            let me = this;
            let idTreeMap = {};
            let mainTreeMap = {};
            let mainNodes = [];
            let idTreeNodes=[];
            let updateData={};
            let includeRootNode=false;
            let parentNodes = [];
            let selection = projectObj.mainSpread.getActiveSheet().getSelections()[0];
            console.log(`selection`);
            console.log(selection);
            for(let i =0;i<selection.rowCount;i++){
                let tem_node = controller.tree.items[selection.row+i];
                //被行引用的清单（大项费用）不可删除
                if (cbTools.isUsedByFormula(tem_node)){
                    alert('该清单行被其它公式结点引用，不允许删除！');
                    return;
                }
                if(i==0){//第一个直接添加;
                    mainTreeMap[tem_node.getID()] = tem_node;
                    mainNodes.push(tem_node);
                    if(tem_node.sourceType == project.Bills.getSourceType()){
                        idTreeMap[tem_node.source.getID()] = tem_node.source;
                        idTreeNodes.push(tem_node.source);
                    }
                }else {
                    this.setNodeToMapAndArray(tem_node,mainTreeMap,mainNodes);
                    if(tem_node.sourceType == project.Bills.getSourceType()){
                        this.setNodeToMapAndArray(tem_node.source,idTreeMap,idTreeNodes);
                    }
                }
            }
            let updateNodes = [];//需要删除的所有节点;
            let billsUpdate={};
            let rationUpdate = {};
            let updateBill = false;
            let updateRation = false;
            for(let m_node of mainNodes){
                if(m_node.sourceType == project.Bills.getSourceType()){
                    if(m_node.preSibling && !gljUtil.isDef(mainTreeMap[m_node.preSibling.data.ID])){ //有前一节点，并且前一节点不在删除的列表中
                        billsUpdate[m_node.preSibling.data.ID] = {
                            NextSiblingID:getNotDeleteNextID(m_node.nextSibling,mainTreeMap)
                        };
                        updateBill=true;
                    }
                }
                if(m_node.parent==null&&includeRootNode==false){//删除的节点中包含了根节点，要重新计算工程造价,并且工程造价节点只要加入一次就行了
                    parentNodes.push(me.getTotalCostNode(controller));
                    includeRootNode=true
                }else {
                    m_node.parent?parentNodes.push(m_node.parent):"";
                }
                updateNodes.push(m_node);
                controller.tree.getAllSubNode(m_node,updateNodes);
            }
            let refNodes = mbzm_obj.deleteReferenceRation(mainNodes,updateNodes);//删除子目关联定额节点
            for(let u_node of updateNodes){
                if(u_node.sourceType == project.Bills.getSourceType()){
                    billsUpdate[u_node.data.ID] = true;
                    updateBill=true;
                }
                if(u_node.sourceType == project.Ration.getSourceType()){
                    rationUpdate[u_node.data.ID] = true;
                    updateRation = true;
                }
            }
            updateBill==true?updateData['bills']=billsUpdate:'';
            updateRation==true?updateData['ration']=rationUpdate:'';
            updateData.projectID = selected.data.projectID;
            updateData.user_id = userID;
            $.bootstrapLoading.start();
            CommonAjax.post("/bills/multiDelete", updateData, function () {
                // 回收删除节点
                BlockController.recycleBlock(selection);
                let quantity_detail_datas = project.quantity_detail.datas;
                let ration_datas = project.Ration.datas;
                let nodes = controller.tree.nodes;
                let prefix = controller.tree.prefix;
                //更新缓存
                if(updateData['bills']){//更新bills
                    for(let b_key in updateData['bills']){
                        if(updateData['bills'][b_key]===true){//删除清单和工程量明细
                            _.remove(me.datas,{'ID':b_key});
                            _.remove(quantity_detail_datas,{'billID':b_key});
                        }else {//更新清单属性
                            for(let p_key in updateData['bills'][b_key]){
                                nodes[prefix+b_key].data[p_key] = updateData['bills'][b_key][p_key]
                            }
                        }
                    }
                }
                if(updateData['ration']){
                    for(let r_key in updateData['ration']){//定额只有删除，没有更新
                        _.remove(ration_datas,{'ID':r_key});
                        project.Ration.deleteSubListOfRation({ID:r_key});
                    }
                }
                for(let r of refNodes){
                    controller.m_delete([r],r.serialNo())//这里删除关联子目生成的定额因为是离散的树节点，所以要这样分开处理
                }
                controller.m_delete(mainNodes,mainNodes[0].serialNo());//删除树节点
                me.tree.m_delete(idTreeNodes);
                $.bootstrapLoading.end();
                //重新计算
            /*    project.installation_fee.calcInstallationFee(function (isChange) { 养护没有安装增加费，同时计算安装增加费的clone 那里性能很低
                    project.calcProgram.calcAllNodesAndSave();
                    if(!isChange) {
                        project.projectGLJ.loadData();
                    }
                    gljOprObj.refreshView();
                });*/
                project.calcProgram.calcNodesAndSave(parentNodes);
                project.projectGLJ.calcQuantity();
                gljOprObj.refreshView();
                if (isDeleteChild){
                    calcTools.forceSelect(parentNode);
                }
            }, function () {
                $.bootstrapLoading.end();
            });

            function getNotDeleteNextID(nextNode,map) {
                if(nextNode){
                    if(gljUtil.isDef(map[nextNode.data.ID])){
                        return getNotDeleteNextID(nextNode.nextSibling,map)
                    } else {
                        return nextNode.data.ID
                    }
                }else {
                    return -1
                }
            }

        };
        bills.prototype.deleteChildren = function(node) {
            if (!(node.children.length && node.children.length > 0)) return;
            let me = this;
            let firstChild = node.firstChild();
            calcTools.forceSelect(firstChild, node.children.length);
            me.deleteSelectedNodes(true, node);
        };
        bills.prototype.setNodeToMapAndArray=function (node,map,array) {
            let nodeID = node.getID();
            if(map[nodeID]==undefined||map[nodeID]==null){
                newMap(node,node.parent,map,array)
            }
            function newMap(node,parent,map,array) {
                let nodeID =node.getID();
                if(parent==null){//说明已经是最顶层了
                    map[nodeID]=node;
                    array.push(node);
                }else {
                    let parentID = parent.getID();
                    if(map[parentID]==undefined||map[parentID]==null){
                        newMap(node,parent.parent,map,array);
                    }
                }
            }
        };
        bills.prototype.deleteAllSubNodes = function(){
            let controller = projectObj.mainController, project = projectObj.project;
            let Bill = project.Bills;
            let FBFX = Bill.getFBFXNode(controller);//取分部分项工程节点;
            let deleteRootNodes = _.clone(FBFX.children);
            let deleteRootNodes_id = _.clone(FBFX.source.children);
            let sels = controller.sheet.getSelections();
            controller.tree.m_delete(deleteRootNodes);
            this.tree.m_delete(deleteRootNodes_id);
            TREE_SHEET_HELPER.massOperationSheet(controller.sheet, function () {
                let rowCount = 0;
                for(let node of deleteRootNodes){
                    rowCount = rowCount+node.posterityCount() + 1;
                }
                controller.sheet.deleteRows(1, rowCount);
                let index = sels[0]?sels[0].row:1;
                //controller.setTreeSelected(controller.tree.items[1]);
            });
            cbTools.refreshFormulaNodes();
        };
        bills.prototype.getAllBXs = function () {
          return _.filter(this.datas,{"type":billType.BX});
        };

        bills.prototype.getAutoParentNode = function (type) {//取需自动生成清单的父节点
            let controller = projectObj.mainController;
            let parentNode;
            if(type == '措施费用'){
                parentNode = this.getTechNode();
            }else {
                let rootNode = this.getFBFXNode(controller);
                parentNode =getLeaveBill(rootNode.source);
                if(parentNode.data.type == billType.FX||parentNode.data.type == billType.BX){//如果是分项或补项的话，取父节点
                    parentNode = parentNode.parent;
                }
            }
            return parentNode;

            function getLeaveBill(node) {
                if(node.children.length>0){
                    return getLeaveBill(node.children[node.children.length-1]);
                }else {
                    return node;
                }
            }
        };


        bills.prototype.getNewInstallBillData = function (code,billID,feeType) {
            let parentNode = this.getAutoParentNode(feeType);
            if(!billID){
                billID = uuid.v1();
            }
            let data = {
                ID:billID,
                projectID: parseInt(projectObj.project.ID()),
                ParentID:parentNode.data.ID,
                NextSiblingID:-1,
                code : this.newFormatCode(code),
                name:'安装增加费',
                unit:'元',
                quantity:'1'
            };
            return data;
        };

        return new bills(project);
    }
};
function isDef(v) {
    return v !== undefined && v !== null;
}

function isFlag(v) {
    return this.isDef(v.flagsIndex) && this.isDef(v.flagsIndex.fixed) && this.isDef(v.flagsIndex.fixed.flag);
}

function getRootFixedNode(node) {
    let parent = node.parent;
    if(isFlag(node.data) && (node.data.flagsIndex.fixed.flag === fixedFlag.SUB_ENGINERRING
        || node.data.flagsIndex.fixed.flag === fixedFlag.MEASURE
        || node.data.flagsIndex.fixed.flag === fixedFlag.OTHER
        || node.data.flagsIndex.fixed.flag === fixedFlag.CHARGE
        || node.data.flagsIndex.fixed.flag === fixedFlag.TAX)){
        return node;
    }
    else {
        if(!parent){
            return node;
        }
        else {
            return getRootFixedNode(parent);
        }
    }
}

//转换ID '-1' to -1
function parseIDs(datas){
    for(let data of datas){
        if(isDef(data.ID) && data.ID === '-1'){
            data.ID = -1;
        }
        if(isDef(data.ParentID) && data.ParentID === '-1'){
            data.ParentID = -1;
        }
        if(isDef(data.NextSiblingID) && data.NextSiblingID === '-1'){
            data.NextSiblingID = -1;
        }
    }
}
