var MD5 = require('md5.js')

let NodeFunc = function({key,buildFunc,postFunc}){
    this.buildFunc = buildFunc;
    this.key = key;
    this.postFunc = postFunc;
    this.children = [];
    this.skip = false;
}
/**
 * 跟据信息数组,组建链表,并返回头指针
 */
function buldNodeChain(arr){
    let head = null;
    let cur = null;
    for(let item of arr){
        let node = new NodeFunc(item)
        if(head == null){
            head = node
            cur = head;
        }else{
            cur.children.push(node);
            cur = node;
        }
    }
    return head;
}

const COMMON_NODE_ARR = [
    {key:"trtcre",buildFunc:"buildTrtcre",postFunc:"processTrtcre"},
    {key:"dftcre",buildFunc:"buildDftcre",postFunc:"processDftcre"},
    {key:"liaall",buildFunc:"buildEngp",postFunc:"processLiaall"},
    {key:"liaccv",buildFunc:"buildCcvpan",postFunc:"processLiaccv"},
    {key:"limitbody",buildFunc:"buildLimitbody",postFunc:"processLimitbody"},
    {key:"setcode",buildFunc:"buildSetmodCodeTable",postFunc:"getSetmodCodeTable"},
    {key:"setfeg",buildFunc:"buildSetfeg",postFunc:"calcFeeDetail"},
    {key:"setglg",buildFunc:"buildSetglg",postFunc:"calcSettleDetail"},
    //面函需要出申报单,因此申报组件试算需提前
    {key:"bopgat",buildFunc:"buildBopgat",postFunc:"initBopgat"},
    {key:"boprem",buildFunc:"buildBoprem",postFunc:"initBoprem"},
    {key:"boppay",buildFunc:"buildBoppay",postFunc:"initBoppay"},
    {key:"docpan",buildFunc:"buildDocpan",postFunc:"processTrndoc"},
    {key:"glepan",buildFunc:"buildGlepan",postFunc:"processGlentry"},
    // {key:"rmbbopPf",buildFunc:"buildRmbbop",postFunc:"query2111xcd"},
		// {key:"rmbbopSh",buildFunc:"buildRmbbop",postFunc:"query2101xid"},
		{key:"usrmd",buildFunc:"buildUsrmd",postFunc:"processUsrmd"},
		{key:"entmod",buildFunc:"buildEntmod",postFunc:"processEntmod"},
		// {key:"forexmod",buildFunc:"buildForexmod",postFunc:"processForexmod"},
    {key:"rmbbop",buildFunc:"buildRmbbop",postFunc:"initRmbbop"},
    {key:"cfabop",buildFunc:"buildCfabop",postFunc:"initCfabop"},
    {key:"jshmod",buildFunc:"buildJshmod",postFunc:"initJshmod"},
]


function exchangeTabWithKey(tabName){
  if(tabName == 'engp'){
    return "liaall"
  }else if(tabName == "ccvpan" || tabName == "liauni"){
    return "liaccv"
  }else if(tabName == "setpan"){
    return "setglg"
  }
  return tabName
}

const ALL_AVA_KEY = [
    ...COMMON_NODE_ARR.map(item=>item.key),
]

function buildNodeChain(){
    const CHAIN_HEAD = buldNodeChain(COMMON_NODE_ARR);
    return CHAIN_HEAD;
}

function walkNode(node,cb){
    cb && cb(node)

    for(let subNode of node.children){
        walkNode(subNode,cb)
    }
}

//定义为平衡器
//参数构建回调,发送请求回调
export default function MacBalance(root){
    this.macSet = {};
    this.root = root;
    //构造链条完毕
    this.CHAIN_HEAD = buildNodeChain()
    //默认before模式
    this.mode = 1;
}

MacBalance.prototype.executeKey = async function(key,tabs){
    key = exchangeTabWithKey(key)
    if(tabs){
        this.updateChain(tabs)
    }
    if(key == "setglg"){
      //如果算结算信息,直接一直算到面函
      key = "docpan"
    }
    //不支持的标签
    if(!ALL_AVA_KEY.includes(key)){
        return;
    }
    //2次经验值优化
    for(let i=0;i<2;i++){
      let head = this.CHAIN_HEAD;
      let que = [];
      que.push(head);
      while(que.length){
          let node = que.shift()
          if(node.skip){
              //没有该公共组件,跳过
              for(let subNode of node.children){
                que.push(subNode)
              }
              continue;
          }
          if(this.isBeforeMode() && node.key == key){
            //已经执行到了key,可以退出了
            break;
          }
          let rtnmsg = await this.executeNode(node)
          if (rtnmsg.respCode != SUCCESS){
            //终止计算
            // return
          }

          if(this.isAfterMode() && node.key == key){
            //已经执行了key,可以退出了
            break;
					}
					node.children.forEach(item =>{
						que.push(item)
					})
          
          // for(let subNodes of node.children){
          //     que.push(subNode)
          // }

      }
  }
}

MacBalance.prototype.executeNode=async function(node){
    let oldMac = this.macSet;
    let params  = this.root.buildCommonData(this.root.model,this.root.trnName)
    let request = this.getRequestByNode(node,params);
    let mac = this.macGen(request);
    //判断mac是否一致,不一致则发送请求给后端计算
    if(mac != oldMac[node.key]){
        console.log("------执行{}",node.key)
        let rtnmsg = await this.sendRequestByNode(node,params);
        if (rtnmsg.respCode === SUCCESS){
          params  = this.root.buildCommonData(this.root.model,this.root.trnName)
          request = this.getRequestByNode(node,params);
          mac = this.macGen(request);
          oldMac[node.key] = mac;
        }else{
          oldMac[node.key] = "";
        }
        
        return rtnmsg
    }
    return {respCode:SUCCESS}
}

MacBalance.prototype.getRequestByNode= function(node,params){
    let request = this.root[node.buildFunc].call(this.root,params);
    request =  {...request,...params,};
    return request;
}
MacBalance.prototype.sendRequestByNode = function(node,params){
    return this.root[node.postFunc].call(this.root,params);
}

MacBalance.prototype.macGen= function(obj){
    let str = JSON.stringify(obj);
    let mac = new MD5().update(str).digest('hex');
    return mac;
}

MacBalance.prototype.updateChain = function(tabs){
		let tabNames = tabs.$children.map(tab=>exchangeTabWithKey(tab.name))
		if(this.root.$refs.liacombo){
			let comboTabs = this.root.$refs.liacombo.$children[0].$children.map(collapse=>exchangeTabWithKey(collapse.name))
			tabNames = [...tabNames,...comboTabs]
		} 
		if(this.root.$refs.regulat){
			let gulatTabs = this.root.$refs.regulat.$children[0].$children.map(collapse=>exchangeTabWithKey(collapse.name))
			tabNames = [...tabNames,...gulatTabs]
			if(this.root.model.entmod && this.root.model.entmod.visflg){
				if(tabNames.indexOf('entmod') < 0){
					tabNames.push('entmod')
				}
			}
		}
    walkNode(this.CHAIN_HEAD,node=>{
        if(tabNames.includes(node.key)){
            node.skip = false;
        }
        else{
          if((node.key == "setfeg" || node.key == "setcode" || node.key == "glepan") && tabNames.includes("setglg")){
            node.skip = false;
            //如果liauni的话,则允许liaall和liaccv
          }else if((node.key == "liaall" || node.key == "liaccv") && tabNames.includes("liauni")){
            node.skip = false;
          }
          else{  
            node.skip = true;
          }
        }
    })
}

MacBalance.prototype.isBeforeMode=function(){
  return this.mode == 1;
}

MacBalance.prototype.isAfterMode=function(){
  return this.mode == 2;
}

MacBalance.prototype.setBeforeMode=function(){
  this.mode = 1;
}

MacBalance.prototype.setAfterMode=function(){
  this.mode = 2;
}