/**
 * Created by zhang on 2019/5/20.
 */

let exportUtil = {
    setEngineerPriceIndex:function (tender,projectData) {
       return gljUtil.getEngineerCostData(tender.property,projectData.bills,fixedFlag,scMathUtil);
    },
    getTotalFee:function (b) {
        return gljUtil.getTotalFee(b,scMathUtil);
    },
    getFlag: function (name,totalCost,engineerCost,buildingArea) {
        return gljUtil.getEngineerFlag(name,totalCost,engineerCost,buildingArea);
    },
    getBuildArea:function (features) {
        return gljUtil.getBuildArea(features)
    },
    calcUnitB:function (total,building,scMathUtil,coe,decimal = 3) {
        return gljUtil.calcUnitB(total,building,scMathUtil,coe,decimal)
    },
    calUnitWidthCoe:function (total,noNeedCoe) {
        return gljUtil.calUnitWidthCoe(total,noNeedCoe,projectObj.project.property.engineerFeatures,_,scMathUtil);
    },
    getIndexBills:function (bills) {
        return gljUtil.getIndexBills(bills,fixedFlag,_,scMathUtil);
    },
    getProjectInfo :async function (data) {
        let result = await ajaxPost("/pm/api/exportProject",data);
        return result;
    },
    getProjectFile:async function(projectID,projectName){
        let spString = "|----|";
        let sumString = "";
        let result = await exportUtil.getProjectInfo({projectID:projectID,type:"main",user_id: userID});
        let result_arr = result.split(spString);
        sumString = result_arr[0];
        if(result_arr.length == 2){
            let tenders = JSON.parse(result_arr[1]);
            for(let t of tenders){
                let tenderString = await exportUtil.getProjectInfo({projectID:t,rootProjectID:projectID,type:"sub",user_id: userID});
                await  setTimeoutSync(null,500);//设置间隔
                sumString = sumString + spString +tenderString;
            }
        }else {
            throw new Error("数据错误 导出建设项目失败！");
        }
        let blob = new Blob([sumString], {type: 'text/plain;charset=utf-8'});
        return {
            blob: blob,
            fileName: projectName+".ybp"
        }
    },
    exprotZBFX:async function (codes) {
        let pr = new SCComponent.InitProgressBar();
        pr.start('导出数据接口', '正在导出，请稍候……');
        try {
            if(SEIObject.fileCache.length== 2){
                let tem = SEIObject.fileCache.shift();
                let fileArry =await XML_EXPORT_BASE.getExtractFile(codes,tem.extractData);
                //添加招投标数据文件
                SEIObject.fileCache = SEIObject.fileCache.concat(fileArry);

                //导出建设项目数据
                let projectFile = await exportUtil.getProjectFile(projectObj.project.property.rootProjectID,$("#rootProjectName").val());
                //导出压缩包
                SEIObject.fileCache.push(projectFile);
                await saveZBFX(SEIObject.fileCache);
            }
        }catch (e){
            console.log(e);
            alert(e.message);
        }finally {
            pr.end();
            $('#exportCode').modal('hide');
            $('#exportIndex').modal('hide');
        }

        async function saveZBFX(fileData) {
            let zip = new JSZip();
            for (let file of fileData) {
                zip.file(file.fileName, file.blob, {binary: true});
            }
            let zipFile = await zip.generateAsync({type: 'blob'});
            saveAs(zipFile, '经济指标.ZBFX');
        }
    }
};

let SEIObject = {
    exporting:false,
    fileCache:[],
    errorMap:{},
    selfChecked:false
};

async function selfChecking(projectID,exprotCall=false) {//自检和正式导出共用接口
    if(SEIObject.selfChecked == false){//自检过了就不用重复自检了
        let extraData = await XML_EXPORT_BASE.getExtractData();
        SEIObject.errorMap = extraData.failList;
        SEIObject.fileCache.push(extraData);
        //检查重庆指标接口数量
        if(_.isEmpty(SEIObject.errorMap)){
            let [errorMap,SEIFile] = await getSEIIndexFile(projectID);
            if(errorMap) {
                SEIObject.errorMap = errorMap;
            }else {
                SEIObject.fileCache.push(SEIFile);
            }
        }
    }
    if(_.isEmpty(SEIObject.errorMap)){
        if(!exprotCall) alert("自检完成，未检测到错误数据。")
    }else{
        showExportError(SEIObject.errorMap);
    }
    SEIObject.selfChecked = true;
}


async function exportSEI(projectID){
    if(!_.isEmpty(SEIObject.errorMap)) return showExportError(SEIObject.errorMap);//如果自检的时候已经有错误，直接提示;
    let pr = new SCComponent.InitProgressBar();
    SEIObject.exporting = true;
    try {
        if(!SEIObject.selfChecked)  pr.start('导出数据接口', '正在自检，请稍候……');
        await selfChecking(projectID,true);
        pr.end();
        await setTimeoutSync(null,300);//设置间隔
        $('#exportCode').modal('show');
    }catch (e){
        console.log(e);
        pr.end();
        alert(e.message);
    }
}

function showExportError(errorMap) {//errorMap 如果是一个数组，则是招投标接口传过来的
    let infoList = [];
    if(Array.isArray(errorMap)){
        infoList = errorMap;
    }else {
        for(let name in errorMap){
            infoList.push(`<span style="font-weight: bold">单位工程“${name}”下：</span>`);
            for(let err of errorMap[name]){
                infoList.push(err);
            }
        }
    }
    if(infoList.length > 20){
        $('#hintBox_caption').addClass('export-check');
    }
    let msg = infoList.join(`<br>`);
    alert(msg);
}

async function getSEIIndexFile(projectID) {

    let tenderProjects = [];
    let errorMap = {};
    let result = await ajaxPost("/project/getSEIProjects",{projectID:projectID});
    let project = getProject(result);
    await prepareTenderDatas(tenderProjects,project);

    if(!_.isEmpty(errorMap)){
        return [errorMap,null];
    }
    let file = toXml(project);

    return [null,file];

    function getProject(orignal) {//取建设项目信息
        let basicInformation = getBaseInfo(orignal);
        let textTpye =  orignal.property.taxType == 1 ?"一般计税":"简易计税";
        let project = {
            name: "建设项目",
            attrs: [
                {name: "项目名称", value: orignal.name},
                {name:"建设单位",value:getItemValueBykey(basicInformation.items,"constructionUnit")},
                {name:"施工单位",value:getItemValueBykey(basicInformation.items,"buildingUnit")},
                {name: "标准名称", value: "重庆市建设工程造价指标采集标准(清单计价)"},
                {name: "标准版本号", value: "1.1"},
                {name: "计税模式", value: textTpye}
            ],
            basicInformation:basicInformation,
            children:[]
        };
        initAtts(project.attrs);
        for(let c of orignal.children){
            project.children.push(getEngineering(c));
        }
        return project;
    }

    function getEngineering(source){
        let engineer = {
            name:"单项工程",
            attrs:[
                {name: "名称", value: source.name}
            ],
            children:[]
        };

        for(let c of source.children){
            let tenderProject = getTender(c);
            engineer.children.push(tenderProject);
            tenderProjects.push(tenderProject);
        }
        return engineer
    };

    function getTender(source) {
        let tender = {
            ID:source.ID,
            name:"单位工程",
            attrs:[
                {name: "名称", value: source.name}
            ],
            children:[],
            valuationType:source.property.valuationType,
            taxType:source.property.taxType,
            property:source.property,
            projectName:source.name
        };
        return tender;
    }


    async function prepareTenderDatas(tenders,project) {
        for(let t of tenders){
            await setTenderData(t,project);
            await setTimeoutSync(null,500);
        }


    }

    async function setTenderData(tender,project) {
        let projectData = await ajaxPost("/project/loadSEIProjectData",{projectID:tender.ID});
        tender.children.push(setEngineerInfo(tender));//设置工程信息
        tender.children.push(setEngineerFeature(tender));//设置工程特征
        tender.children.push(setEngineerIndex(tender,projectData));
        tender.children.push(await setGLJSummy(tender,projectData));
       //
    }


    function setEngineerIndex(tender,projectData) {//设置工程指标
        let index = {
            name:"工程指标",
            attrs:[],
            children:[],
        };
        let indexName = tender.property.indexName?tender.property.indexName:"建筑工程";
        index.children.push(exportUtil.setEngineerPriceIndex(tender,projectData));
        index.children.push(setEngineerEcoIndex(tender,projectData,indexName));
        index.children.push(setMainMaterialIndex(tender,projectData,indexName));
        index.children.push(setQuantityIndex(tender,projectData,indexName));

        return index;

        function setMainMaterialIndex(tender,projectData,indexName){
            let mainIndex = {
                name:`${indexName}工料指标`,
                attrs:[],
                children:[]
            };
            if(projectData) gljUtil.calcProjectGLJQuantity(projectData.projectGLJs,projectData.ration_gljs,projectData.rations,projectData.bills,getDecimal("glj.quantity"),_,scMathUtil);
            let materials = indexObj.getMainMaterialDatas(tender.property,tender.property.materials,projectData.projectGLJs,tender.property.calcOptions,tender.property.decimal,false,_,scMathUtil);
            for(let m of materials){
                if(m.name == "其他材料") continue;//2020-01-08  其他材料 不输出字段（不管是否有值）。
                mainIndex.children.push(getMaterial(m))
            }
            let index = {
                name:"主要工料价格及消耗量指标",
                attrs:[],
                children:[mainIndex]
            };
            return index;

            function getMaterial(m) {
                let mname = m.exportName?m.exportName:m.name;
                let material = {
                    name:mname,
                    attrs:[
                        {name:"综合单价",value:scMathUtil.roundToString(m.unitPrice,2)},
                        {name:"数量",value:scMathUtil.roundToString(m.quantity,2)},
                        {name:"单方指标",value:scMathUtil.roundToString(m.unitIndex,3)},
                        {name:"单位",value:m.unit}
                    ]
                };
                return material;
            }

        }

        function setQuantityIndex(tender,projectData,indexName) {
            let quantityIndex = {
                name:`${indexName}量指标`,
                attrs:[],
                children:[]
            };
            let quantities = indexObj.getQuantityDatas(tender.property.mainQuantities,projectData.bills);
            for(let q of quantities){
                quantityIndex.children.push(getQuantity(q));
            }

            let index = {
                name:`主要工程量指标`,
                attrs:[],
                children:[quantityIndex]
            };
            return index;

            function getQuantity(q) {
                let qname = q.exportName?q.exportName:q.name;
                let quantity = {
                    name:qname,
                    attrs:[
                        {name:"工程量指标",value:scMathUtil.roundToString(q.quantity,3)},
                        {name:"单位",value:q.quantityIndexUnit}
                    ]
                };
                return quantity;
            }
        }

        function setEngineerEcoIndex(tender,projectData,indexName) {
            let ecoIndex = {
                name:`${indexName}经济指标`,
                attrs:[],
                children:[]
            };
            let economicDatas = indexObj.getEconomicDatas(tender.property.economics,projectData.bills);
            for(let e of economicDatas){
                ecoIndex.children.push(getEco(e))
            }
            let index = {
                name:`工程经济指标`,
                attrs:[],
                children:[ecoIndex]
            };
            return index;

            function getEco(e) {
                let ename = e.exportName?e.exportName:e.name;
                let eco = {
                  name:ename,
                  attrs:[
                      {name:"综合合价",value:scMathUtil.roundToString(e.cost,2)},
                      {name:"单方指标",value:scMathUtil.roundToString(e.unitCost,2)},
                      {name:"占造价比例",value:scMathUtil.roundToString(e.per,2)}
                  ]
                };
                return eco;
            }
        }
    }

    async function setGLJSummy(tender,projectData) {

        let gljs = {
            name:"人材机汇总",
            attrs:[],
            children:[]
        };
        setGLJDetail(projectData,tender.property,gljs);
        return gljs;
    }

    function setGLJDetail(projectData,property,gljs) {
        if(projectData){
            gljUtil.calcProjectGLJQuantity(projectData.projectGLJs,projectData.ration_gljs,projectData.rations,projectData.bills,getDecimal("glj.quantity"),_,scMathUtil,true);
        }
        for(let g of projectData.projectGLJs.gljList) {
            if (!g.quantity || g.quantity == "") continue;
            let tenderCoe = gljUtil.getTenderPriceCoe(g,property);
            g.marketPrice = gljUtil.getMarketPrice(g,projectData.projectGLJs,property.calcOptions,property.decimal,false,_,scMathUtil,tenderCoe);
            gljs.children.push(setEachGLJ(g));
        }
    }

    function setEachGLJ(source){
        let g = {
            name:"人材机",
            attrs:[
                {name: "代码", value: source.code},
                {name: "名称", value: source.name},
                {name: "规格型号", value: source.specs},
                {name: "单位", value: source.unit},
                {name: "市场单价", value: source.marketPrice},
                {name: "数量", value: source.quantity},
                {name: "类型", value: source.type},
                {name: "产地", value: source.originPlace},
                {name: "厂家", value: source.vender},
                {name: "备注", value: source.remark}
            ]
        };
        handleXMLEntity(g.attrs);
        return g;
    }
    // 对每个元素的所有属性值进行特殊字符处理
    function handleXMLEntity(attrs) {
        let _xmlEntity = {
            '&': '&amp;',
            '\n': '&#xA;',
            '"': '&quot;',
            '\'': '&apos;',
            '<': '&lt;',
            '>': '&gt;'
        };
        for (let attr of attrs) {
            if (!attr.value) {
                continue;
            }
            for (let [key, value] of Object.entries(_xmlEntity)) {
                attr.value = attr.value+"";
                attr.value = attr.value.replace(new RegExp(key, 'g'), value);
            }
        }
    }


    function setEngineerInfo(tender) {//设置工程信息
        let infos = tender.property.engineerInfos?tender.property.engineerInfos:[];
        let errors =  infoRequireChecking(infos);
        if(errors.length > 0) errorMap[tender.projectName] = errors;
        let info = {
            name:"工程信息",
            attrs:[
                {name:"造价编制单位",value:getItemValueByDispName(infos,"造价编制单位")},
                {name:"造价审核单位",value:getItemValueByDispName(infos,"造价审核单位")},
                {name:"项目负责人",value:getItemValueByDispName(infos,"项目负责人")},
                {name:"施工单位编制人员",value:getItemValueByDispName(infos,"施工单位编制人员")},
                {name:"编制人员",value:getItemValueByDispName(infos,"编制人员")},
                {name:"审核人员",value:getItemValueByDispName(infos,"审核人员")},
                {name:"开工日期",value:getItemValueByDispName(infos,"开工日期")},
                {name:"竣工日期",value:getItemValueByDispName(infos,"竣工日期")},
                {name:"工程地点",value:getItemValueByDispName(infos,"工程地点")},
                {name:"工程类型",value:getItemValueByDispName(infos,"工程类型")},
                {name:"合同价类型",value:getItemValueByDispName(infos,"合同价类型")},
                {name:"造价类型",value:getItemValueByDispName(infos,"造价类型")},
                {name:"计价方式及依据",value:getItemValueByDispName(infos,"计价方式及依据")},
                {name:"工程类别",value:getItemValueByDispName(infos,"工程类别")},
                {name:"编制日期",value:getItemValueByDispName(infos,"编制日期")},
                {name:"审查日期",value:getItemValueByDispName(infos,"审查日期"),required:false}
            ]
        };
        initAtts(info.attrs);
        return info;
    }

    function setEngineerFeature(tender) {
        let fea = {
            name:"工程特征",
            attrs:[],
            children:[]
        };
        fea.children.push(setIndexName(tender));
        return fea;

        function setIndexName(tender) {
            let indexName = {
                name:tender.property.indexName?tender.property.indexName:"建筑工程",
                attrs:[],
                children:[]
            };
            setFeatures(tender,indexName.children);
            return indexName
        }
        function setFeatures(tender,arr) {
            let features = tender.property.engineerFeatures?tender.property.engineerFeatures:[];
            if(features.length == 0) return;
            let parentMap = _.groupBy(features,"ParentID");
            let rootNodes = parentMap["-1"]?parentMap["-1"]:parentMap[null];
            for(let r of rootNodes){
                arr.push(getFeatrue(r,parentMap))
            }
        }

        function getFeatrue(node,parentMap){
            let name = node.exportName?node.exportName:node.name;
            if(parentMap[node.ID]){//如果有子节点，那么它就是一个节点
                let tem = {
                    name:name.replace("*",""),
                    attrs:[],
                    children:[]
                };
                for(let s of parentMap[node.ID]){
                    let f = getFeatrue(s,parentMap);
                    f.children?tem.children.push(f):tem.attrs.push(f);//如果有children这个属性，则返回的是一个节点，如果没有，则返回的是一个属性
                }
                return tem;
            }else {//如果没有子节点，那么它就是父节点的一个属性
                if(node.isDetail == true){//如果是明细节点，则造一个明细节点
                    return {name:"明细",attrs:[{name:"名称",value:getValue(node)}],children:[]};
                }
                return {name:name.replace("*",""),value:getValue(node)};
            }
        }

        function getValue(node) {
            let value = node.value;
            if(node.required == true || node.cellType == "number"){//必填项的值为空时导出0
                if(value == undefined || value == null || value == "") value = "0";
            }
            return value;
        }


    }


    function getBaseInfo(project){
        let basicInformation = {items:[]};
        let tem = null;
        if(project.property&&project.property.basicInformation) tem =_.find(project.property.basicInformation,{"key":"basicInfo"});
        if(tem) basicInformation = tem;
        return basicInformation;
    }


    function infoRequireChecking(items) {
        let error = [];
        for(let i of items){
            if(i.required == true && _.isEmpty(i.value)) error.push(`工程信息 - ${i.dispName}不能为空。`);
        }
        return error;
    }


    function getItemValueBykey(items,key) {
        let item = _.find(items,{"key":key});
        if(item) return item.value;
        return ""
    }
    function getItemValueByDispName(items,dispName) {
        let item = _.find(items,{"dispName":dispName});
        if(item){
            return item.value;
        }
        return ""
    }

    function initAtts(arrs) {
        _.remove(arrs,function (item) {
            return item.required == false && _.isEmpty(item.value)
        })
    }

    //开始标签
    function startTag(ele) {
        let rst = `<${ele.name}`;
        for (let attr of ele.attrs) {
            rst += ` ${attr.name}="${ attr.value!=undefined&&attr.value!= null?attr.value:""}"`;
        }
        rst += ele.children&&ele.children.length > 0 ? '>' : '/>';
        return rst;
    }
    //结束标签
    function endTag(ele) {
        return `</${ele.name}>`;
    }
    //拼接成xml字符串
    function toXMLStr(eles) {
        let rst = '';
        for (let ele of eles) {
            rst += startTag(ele);
            if (ele.children&& ele.children.length > 0) {
                rst += toXMLStr(ele.children);
                rst += endTag(ele);
            }
        }
        return rst;
    }
    //格式化xml字符串
    function formatXml(text) {
        //去掉多余的空格
        text = '\n' + text.replace(/>\s*?</g, ">\n<");
        //调整格式
        let rgx = /\n(<(([^\?]).+?)(?:\s|\s*?>|\s*?(\/)>)(?:.*?(?:(?:(\/)>)|(?:<(\/)\2>)))?)/mg;
        let nodeStack = [];
        let output = text.replace(rgx, function($0, all, name, isBegin, isCloseFull1, isCloseFull2, isFull1, isFull2){
            let isClosed = (isCloseFull1 === '/') || (isCloseFull2 === '/' ) || (isFull1 === '/') || (isFull2 === '/');
            let prefix = '';
            if (isBegin === '!') {
                prefix = getPrefix(nodeStack.length);
            } else {
                if (isBegin !== '/') {
                    prefix = getPrefix(nodeStack.length);
                    if (!isClosed) {
                        nodeStack.push(name);
                    }
                } else {
                    nodeStack.pop();
                    prefix = getPrefix(nodeStack.length);
                }
            }
            let ret =  '\n' + prefix + all;
            return ret;
        });
        let outputText = output.substring(1);
        return outputText;
        function getPrefix(prefixIndex) {
            let span = '    ';
            let output = [];
            for (let i = 0 ; i < prefixIndex; ++i) {
                output.push(span);
            }
            return output.join('');
        }
    }
    /*
     * 导出数据
     * @param {Number}tenderID(当前界面的单位工程ID，后台根据这个单位工程，根据导出粒度去找其建设项目下相关数据)
     * @return {void}
     * */
     function toXml(eleData) {
         //转换成xml字符串
         let xmlStr = toXMLStr([eleData]);
         //加上xml声明
         xmlStr = `<?xml version="1.0" encoding="utf-8"?>${xmlStr}`;
         //格式化
         xmlStr = formatXml(xmlStr);
         let blob = new Blob([xmlStr], {type: 'text/plain;charset=utf-8'});
         return {
             blob: blob,
             fileName: "经济指标.ZBF"
         };
         //saveAs(blob, '经济指标.ZBF');
     }

}

$(function () {

    $("#export-index-check").click(async function (){
        let pr = new SCComponent.InitProgressBar();
        pr.start('导出数据接口', '正在自检，请稍候……');
        try {
           await selfChecking(projectObj.project.property.rootProjectID);
        }catch (e){
            console.log(e);
        }finally {
            pr.end();
        }

    });
    $("#export-index-confirm").click(async function (){
        await  exportSEI(projectObj.project.property.rootProjectID);
       // $("#exportIndex").modal("hide");
    });

    $('#exportIndex').on('hide.bs.modal', function() {
        SEIObject = {
            exporting:false,
            fileCache:[],
            errorMap:{},
            selfChecked:false
        }
    })

});