package com.brilliance.isc.common.trndia.service;

import com.brilliance.mda.runtime.mda.util.Dates;
import com.brilliance.mda.runtime.mda.util.MdaUtils;
import com.brilliance.mda.runtime.mda.util.Strings;
import com.brilliance.isc.bo.Cbb;
import com.brilliance.isc.bo.Dia;
import com.brilliance.isc.bo.Pty;
import com.brilliance.isc.common.component.DyncDaoService;
import com.brilliance.isc.common.contants.CommonContants;
import com.brilliance.isc.common.context.SettleContext;
import com.brilliance.isc.common.context.SpringEnvContext;
import com.brilliance.isc.common.converter.DtoMapper;
import com.brilliance.isc.common.exception.CommonServiceException;
import com.brilliance.isc.common.quemod.service.QuemodService;
import com.brilliance.isc.common.register.diasav.DiasavRegisterFactory;
import com.brilliance.isc.common.sysmod.SysmodService;
import com.brilliance.isc.common.transaction.help.TransactionHelpService;
import com.brilliance.isc.common.trndia.registermodule.IDiaryRegisterModule;
import com.brilliance.isc.common.trndia.vo.DiaVo;
import com.brilliance.isc.common.trndia.vo.TrndiaVo;
import com.brilliance.isc.common.util.StringUtils;
import com.brilliance.isc.common.util.Utils;
import com.brilliance.isc.common.vo.BizInfoVo;
import com.brilliance.isc.common.vo.SimpleModuleVo;
import com.brilliance.isc.mda.dao.DiaMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static com.brilliance.mda.runtime.mda.Constants.*;

@Service
public class TrndiaServiceImpl implements TrndiaService {

    private static Logger log = LoggerFactory.getLogger(TrndiaServiceImpl.class);

    @Autowired
    private DiasavRegisterFactory diasavRegisterFactory;

    @Autowired
    private SysmodService sysmodService;

    @Autowired
    private QuemodService quemodService;

    @Autowired
    private DiaMapper diaMapper;

    @Autowired
    private TransactionHelpService transactionHelpService;

    @Autowired
    private DyncDaoService dyncDaoService;

    /**
     *   source:trndia.0011.script
     *   获取前手交易的Diaries列表
     */
    public void getDiaries(TrndiaVo trndiaVo) {
        BizInfoVo rec = trndiaVo.getRec();
        String objinr = rec.getObjinr();
        String objtyp = rec.getObjtyp();
        log.debug("获取objinr {}, objtyp{}的备忘录数据", objinr, objtyp);
        List<Dia> dias = new ArrayList<>();
        if (StringUtils.isNotEmpty(objinr) && StringUtils.isNotEmpty(objtyp)) {
            List<Dia> diaries = diaMapper.getDiaByObjtypAndObjinr(objtyp, objinr);
            if (diaries != null) {
                dias.addAll(diaries);
            }
        }
        log.debug("根据业务品种注册其他业务模型");
        IDiaryRegisterModule diaryRegisterModule = null;
        try {
            diaryRegisterModule = SpringEnvContext.getBean(objtyp.toLowerCase() + ".diaryRegisterModule");
        } catch (NoSuchBeanDefinitionException e) {
            log.warn("没有找到业务{}的Diary注册模型实现类", objtyp);
        }
        if (diaryRegisterModule != null) {
            diaryRegisterModule.registerModule(trndiaVo);
        }
        List<SimpleModuleVo> registerSimpleModules = trndiaVo.getRegisterSimpleModules();
        if (registerSimpleModules != null && registerSimpleModules.size() > 0) {
            log.debug("获取注册简易模型的备忘录数据");
            for (SimpleModuleVo simpleModuleVo: registerSimpleModules) {
                String moduleObjtyp = simpleModuleVo.getObjtyp();
                String moduleObjinr = simpleModuleVo.getObjinr();
                log.debug("获取SimleModule objinr {}, objtyp{}的备忘录数据", moduleObjinr, moduleObjtyp);
                if (StringUtils.isNotEmpty(moduleObjinr) && StringUtils.isNotEmpty(moduleObjtyp)) {
                    List<Dia> diaries = diaMapper.getDiaByObjtypAndObjinr(moduleObjtyp, moduleObjinr);
                    if (diaries != null) {
                        dias.addAll(diaries);
                    }
                }
            }
        }
        if (dias.size() > 0) {
            List<DiaVo> diaVos = DtoMapper.INSTANCE.transferDiaListToDiaVoList(dias);
            diaVos.forEach(diaVo -> {
                if("X".equals(diaVo.getDonflg())) {
                    diaVo.setDiamodflg(CommonContants.SET_TO_DONE_DB_DIARY);
                } else {
                    diaVo.setDiamodflg(CommonContants.READ_FROM_DB);
                }
                diaVo.setObjmodpath(Utils.toJson(SimpleModuleVo.buildModule(diaVo.getObjinr(), diaVo.getObjtyp())));
            });
            trndiaVo.setDias(diaVos);
        }
    }

    /**
     * 根据dia数据 计算diamodflg
     * @param diaVo
     */
    public void calculateDiamodflg(DiaVo diaVo) {
        log.debug("inr:{},diatyp:{},modify:{},donflg:{}",diaVo.getInr(),diaVo.getDiatyp(),diaVo.getModifySet(),diaVo.getDonflg());
        if (CommonContants.READ_FROM_DB.equals(diaVo.getDiamodflg())
                && diaVo.getModifySet().size() == 0
                && StringUtils.isEmpty(diaVo.getDonflg())) {
            log.debug("Diary来源于数据库且没有修改");
            return;
        }
        String first = "";
        String second = "";
        String thrid = "";
        if (StringUtils.isNotEmpty(diaVo.getInr())) {
            first = "S";
        } else {
            first = "N";
        }
        if ("MANUAL".equalsIgnoreCase(diaVo.getDiatyp()) || modifyOtherField(diaVo)) {
            second = "M";
        } else {
            second = "F";
        }
        if ("X".equals(diaVo.getDonflg())) {
            thrid = "D";
        } else {
            thrid = "N";
        }
        diaVo.setDiamodflg(first+second+thrid);
        log.debug("计算diamofflg结果 {}", diaVo.getDiamodflg());
    }

    /**
     * 是否修改了其他属性值，不包含donflg
     * @param diaVo
     * @return
     */
    public boolean modifyOtherField(DiaVo diaVo) {
        Set<String> modifies = diaVo.getModifySet();
        if (modifies.size() == 0) {
            return false;
        } else {
            if (modifies.size() == 1 && modifies.contains("donflg")) {
                return false;
            }
        }
        return true;
    }

    /**
     * 将交易产生的diary删除 防止交易注册的时候重复
     * @param trndiaVo
     */
    public void resetTrndia(TrndiaVo trndiaVo) {
        log.debug("将交易产生的diary删除,防止交易注册的时候diary数据重复");
        if (trndiaVo.getDias() != null && trndiaVo.getDias().size() > 0) {
            List<DiaVo> dias = trndiaVo.getDias().stream().filter(diaVo ->
                StringUtils.isNotEmpty(diaVo.getInr()) || "MANUAL".equalsIgnoreCase(diaVo.getDiatyp()) || diaVo.getModifySet().size() > 0
            ).collect(Collectors.toList());
            trndiaVo.setDias(dias);
        }
        log.debug("如果ownref有变更，需要重新设置ownref");
        if (StringUtils.isNotEmpty(trndiaVo.getRec().getOwnref())) {
            trndiaVo.getDias().forEach(diaVo -> {
                if (StringUtils.isEmpty(diaVo.getInr())
                        && trndiaVo.getRec().getObjtyp().equals(diaVo.getObjtyp())) {
                    //跟rec同一个业务品种
                    diaVo.setObjref(trndiaVo.getRec().getOwnref());
                }
            });
        }
    }
    /**
     *   source:trndia.0012.script
     */
    public void assertDiaries(TrndiaVo trndia) {
        //! rule used to automatically post all diasav rules found in the current
        //! transaction
        // set picked diary to done, if exist
        resetTrndia(trndia);
        log.debug("是否已经读取过前手交易或者关联业务的Diaries数据,{}", trndia.getOldredflg());
        if (StringUtils.isEmpty(trndia.getOldredflg())) {
            getDiaries(trndia);
            trndia.setOldredflg("X");
        }
        setDoneIfContractClosed(trndia);
        //LIASAV register
        log.debug("执行交易{}备忘录注册", SettleContext.getTransName());
        diasavRegisterFactory.getDiasavRegister(SettleContext.getTransName()).diasav(trndia);
        log.debug("根据Diary数据确定diamodflg");
        trndia.getDias().forEach(diaVo -> {
            calculateDiamodflg(diaVo);
        });
        log.debug("交易{}备忘录试算结束", SettleContext.getTransName());
    }

    /**
     *   source:trndia.0010.script
     */
    public void saveNewDiaries(TrndiaVo trndia) {
        // during save is to allow for control entry
        // control entry has 4 parts:
        // 1.character:  loaded from data base("S") / still not into data base (N)
        // 2.character:  unchanged (N) / automatically modified ("F") / manually changed ("M")
        // 3.character:  don`t delete (N) / is to be deleted ("D")
        // depending on whether entry found in DB or not, the actions is the following
        // --------------------------------------------------------------------
        // control entry          # found in DB             # don`t found in DB
        // --------------------------------------------------------------------
        //   NNN                       %                            %
        //   NMN                    update                       insert
        //   NFN                    update                       insert
        //   SNN                       %                            %
        //   SMN                    update(field to field)       insert
        //   SFN                    update(field to field)       insert
        //   NND                    update(update field DONFLG)    %
        //   NMD                    update                         %
        //   NFD                    update                         %
        //   SND                    update(update field DONFLG)    %
        //   SMD                    update                         %
        //   SFD                    update                         %
        // --------------------------------------------------------------------
        // To guarantee that diaries are loaded, if users has not opened the diary panel,
        // and to regenerate the entries with latest data, GetNewDiaries is called here
        log.debug("备忘录公共组件开始存盘");
        String trninr = transactionHelpService.getTrninr();
        BizInfoVo bizInfoVo = trndia.getRec();
        String objtyp = bizInfoVo.getObjtyp();
        String objinr = bizInfoVo.getObjinr();
        log.debug("获取trninr:{},objtyp:{},objinr:{}", trninr, objtyp, objinr);
        if (trndia.getDias() == null || trndia.getDias().size() == 0) {
            log.debug("没有备忘录数据，不执行存盘逻辑");
            return;
        }
        for (int i=0; i<trndia.getDias().size(); i++) {
            DiaVo diaVo = trndia.getDias().get(i);
            if (StringUtils.isEmpty(diaVo.getInr()) && "X".equals(diaVo.getDonflg())) {
                log.debug("新增的备忘录daiType:{}数据donflg为X(逻辑删除)，不会存盘", diaVo.getDiatyp());
                continue;
            }
            String objmodpath = diaVo.getObjmodpath();
            SimpleModuleVo linkModule = null;
            if (StringUtils.isNotEmpty(objmodpath)) {
                linkModule = Utils.toObject(SimpleModuleVo.class, objmodpath);
                if (!linkModule.getObjtyp().equals(objtyp)) {
                    //不同的业务品种
                    if (StringUtils.isEmpty(linkModule.getObjinr())) {
                        throw new CommonServiceException("备忘录存盘，objtyp = "+ linkModule.getObjtyp() + "的主键不能为空");
                    }
                } else {
                    linkModule = SimpleModuleVo.buildModule(trndia.getRec());
                }
            } else {
                linkModule = SimpleModuleVo.buildModule(trndia.getRec());
            }
            if(MdaUtils.isEmpty(diaVo.getOwnusr())) {
                diaVo.setOwnusr(internalGetOwnUsrForDia(linkModule));
            }
            internalSetAddFldForDia(diaVo);
            if(MdaUtils.isEmpty(diaVo.getObjinr())) {
                diaVo.setObjinr(linkModule.getObjinr());
                diaVo.setObjtyp(linkModule.getObjtyp());
            }
            if (StringUtils.isEmpty(diaVo.getObjref())) {
                diaVo.setObjref(bizInfoVo.getOwnref());
            }
            diaVo.setUsr(SettleContext.getUserSession().getUsr().getExtkey());
            diaVo.setCretyp("TRN");
            diaVo.setCreinr(trninr);
            if ("GITCOM".equals(diaVo.getFrm()) || "NITCOM".equals(diaVo.getFrm())) {
                if (StringUtils.isEmpty(diaVo.getDiatyp())) {
                    diaVo.setDiatyp(Utils.fmtDate(diaVo.getDat(), "yyMMdd"));
                }
            }
            if(MdaUtils.isEmpty(diaVo.getBchkeyinr())) {
                if (SettleContext.getUserSession().getBch() != null) {
                    diaVo.setBchkeyinr(SettleContext.getUserSession().getBch().getInr());
                }
            }
            if(MdaUtils.isEmpty(diaVo.getBranchinr())) {
                if (SettleContext.getUserSession().getWrkbch() != null) {
                    diaVo.setBranchinr(SettleContext.getUserSession().getWrkbch().getInr());
                }
            }
            //最大长度60
            if (diaVo.getNam().length() > 60) {
                diaVo.setNam(diaVo.getNam().substring(0, 60));
            }
            //最大长度396
            if (StringUtils.isNotEmpty(diaVo.getInftxt())) {
                if (diaVo.getInftxt().length() > 396) {
                    diaVo.setInftxt(diaVo.getInftxt().substring(0, 396));
                }
            }
            //最大长度100
            if (StringUtils.isNotEmpty(diaVo.getPtynam())) {
                if (diaVo.getPtynam().length() > 100) {
                    diaVo.setPtynam(diaVo.getPtynam().substring(0, 100));
                }
            }
            Dia dia = DtoMapper.INSTANCE.transfer(diaVo);
            if (StringUtils.isNotEmpty(dia.getInr())) {
                sysmodService.sdbUpdateWithLog(dia);
            } else {
                sysmodService.sdbInsertWithLog(dia);
            }
        }
        log.debug("备忘录公共组件存盘完成,diary相关的que在复核成功处理");
    }

    /**
     *   从 trnmod.getTrorescon
     */
    public void setDoneIfContractClosed(TrndiaVo trndia) {
        //! Set entries for all contracts in transaction with CLSDAT set to done
        // This is implemented as backup if a transaction sets the CLSDAT but does not call TrnDiaSetDone
        // a) get reserved contracts OBJ`s in transaction
        log.debug("如果交易闭卷，相关diaries的Donflg需要设置成X");
        BizInfoVo rec = trndia.getRec();
        Date clsdat = Utils.getFieldValue(rec, "clsdat");
        log.debug("交易闭卷日期{}", clsdat);
        if (clsdat != null) {
            log.debug("交易闭卷需要设置所有的donflg为X");
            trndia.getDias().forEach(diaVo -> {
                diaVo.setDonflg("X");
            });
        } else {
            log.debug("交易没有闭卷,需要回滚donflg");
            String objtyp = rec.getObjtyp();
            String objinr = rec.getObjinr();
            //查询到数据库donflg=X的数据 这类数据不会回滚
            List<String> dbDonDiaInrs = diaMapper.getInrByObj(objtyp, objinr);
            trndia.getDias().forEach(diaVo -> {
                if (StringUtils.isNotEmpty(diaVo.getDonflg())
                        && !diaVo.isModified("donflg")
                        && (dbDonDiaInrs == null || !dbDonDiaInrs.contains(diaVo.getInr()))) {
                    diaVo.setDonflg("");
                }
            });
        }
    }

    public void trnDiaSetDone(TrndiaVo trndiaVo, String argDiaTyp) {
        internalDiaSetDone(trndiaVo, argDiaTyp, "");
    }

    public void trnDiaSubSetDone(TrndiaVo trndiaVo, String argDiaTyp, String argSubKey) {
        internalDiaSetDone(trndiaVo, argDiaTyp, argSubKey);
    }

    public void internalDiaSetDone(TrndiaVo trndiaVo, String argDiaTyp, String argSubkey) {
        BizInfoVo bizInfoVo = trndiaVo.getRec();
        String objtyp = bizInfoVo.getObjtyp();
        String objinr = bizInfoVo.getObjinr();
        log.debug("将objtyp:{},objinr:{},argSubkey:{},diatyp:{}对应的Diary记录donflg设置成X(逻辑删除)",objtyp,objinr,argSubkey,argDiaTyp);
        if (StringUtils.isEmpty(argDiaTyp)) {
            log.debug("将所有Diary记录donflg设置成X(逻辑删除)");
            trndiaVo.getDias().forEach(diaVo -> {
                diaVo.setDonflg("X");
                calculateDiamodflg(diaVo);
            });
            return;
        }
        int find = -1;
        for (int i=0; i<trndiaVo.getDias().size(); i++) {
            DiaVo diaVo = trndiaVo.getDias().get(i);
            if (objtyp.equals(diaVo.getObjtyp())
                    && objinr.equals(diaVo.getObjinr())
                    && argSubkey.equals(diaVo.getSubkey())
                    && argDiaTyp.equals(diaVo.getDiatyp())) {
                find = i;
                break;
            }
        }
        if (find == -1) {
            log.debug("没有找到对应的Diary记录");
            return;
        }
        trndiaVo.getDias().get(find).setDonflg("X");
        log.debug("根据Diary数据确定diamodflg");
        calculateDiamodflg(trndiaVo.getDias().get(find));
    }

    public void trnDiaSetDone(TrndiaVo trndiaVo, SimpleModuleVo linkModule, String argDiaTyp) {
        internalDiaSetDone(trndiaVo, linkModule, argDiaTyp, "");
    }

    public void trnDiaSubSetDone(TrndiaVo trndiaVo, SimpleModuleVo linkModule, String argDiaTyp, String argSubKey) {
        internalDiaSetDone(trndiaVo, linkModule, argDiaTyp, argSubKey);
    }

    public void internalDiaSetDone(TrndiaVo trndiaVo, SimpleModuleVo linkModule, String argDiaTyp, String argSubkey) {
        if (linkModule == null) {
            throw new CommonServiceException("模型为空，无法删除对应的diary记录");
        }
        String objtyp = linkModule.getObjtyp();
        String objinr = linkModule.getObjinr();
        if (StringUtils.isEmpty(objtyp) || StringUtils.isEmpty(objinr)) {
            throw new CommonServiceException("无效的模型，无法删除对应的diary记录");
        }
        log.debug("将objtyp:{},objinr:{},argSubkey:{},diatyp:{}对应的Diary记录donflg设置成X(逻辑删除)",objtyp,objinr,argSubkey,argDiaTyp);
        if (StringUtils.isEmpty(argDiaTyp)) {
            log.debug("将所有Diary记录donflg设置成X(逻辑删除)");
            trndiaVo.getDias().forEach(diaVo -> {
                if (objtyp.equals(diaVo.getObjtyp())
                    && objinr.equals(diaVo.getObjinr())) {
                    diaVo.setDonflg("X");
                    calculateDiamodflg(diaVo);
                }
            });
            return;
        }
        int find = -1;
        for (int i=0; i<trndiaVo.getDias().size(); i++) {
            DiaVo diaVo = trndiaVo.getDias().get(i);
            if (objtyp.equals(diaVo.getObjtyp())
                    && objinr.equals(diaVo.getObjinr())
                    && argSubkey.equals(diaVo.getSubkey())
                    && argDiaTyp.equals(diaVo.getDiatyp())) {
                find = i;
                break;
            }
        }
        if (find == -1) {
            log.debug("没有找到对应的Diary记录");
            return;
        }
        trndiaVo.getDias().get(find).setDonflg("X");
        log.debug("根据Diary数据确定diamodflg");
        calculateDiamodflg(trndiaVo.getDias().get(find));
    }

    public void trnDiaClearDonFlg(TrndiaVo trndiaVo, String argDiaTyp) {
        internalDiaClearDonFlg(trndiaVo, argDiaTyp,"");
    }

    public void trnDiaSubClearDonFlg(TrndiaVo trndiaVo, String argDiaTyp, String argSubKey) {
        internalDiaClearDonFlg(trndiaVo, argDiaTyp, argSubKey);
    }

    public void internalDiaClearDonFlg(TrndiaVo trndiaVo, String argDiaTyp, String argSubkey) {
        BizInfoVo bizInfoVo = trndiaVo.getRec();
        String objtyp = bizInfoVo.getObjtyp();
        String objinr = bizInfoVo.getObjinr();
        log.debug("将objtyp:{},objinr:{},argSubkey:{},diatyp:{}对应的Diary记录donflg设置成空字符串(逻辑上不删除)",objtyp,objinr,argSubkey,argDiaTyp);
        int find = -1;
        for (int i=0; i<trndiaVo.getDias().size(); i++) {
            DiaVo diaVo = trndiaVo.getDias().get(i);
            if (objtyp.equals(diaVo.getObjtyp())
                    && objinr.equals(diaVo.getObjinr())
                    && argSubkey.equals(diaVo.getSubkey())
                    && argDiaTyp.equals(diaVo.getDiatyp())) {
                find = i;
                break;
            }
        }
        if (find == -1) {
            log.debug("没有找到对应的Diary记录");
            return;
        }
        trndiaVo.getDias().get(find).setDonflg("");
        log.debug("根据Diary数据确定diamodflg");
        calculateDiamodflg(trndiaVo.getDias().get(find));
    }


    /**
     *   source:trndia.0021.script
     */
    public void trnDiaSet(TrndiaVo trndiaVo, String argDiaTyp,Date argDat,String argCod,String argNam,String argFrm, String argWriteFlag) {
        this.trnDiaSubSet(trndiaVo,"", "", argDiaTyp, argDat, argCod, argNam, argFrm, argWriteFlag);
    }

    /**
     *   source:trndia.0021.script
     */
    public void trnDiaSubSet(TrndiaVo trndiaVo, String argSubtyp, String argSubKey, String argDiaTyp,Date argDat,String argCod,String argNam,String argFrm, String argWriteFlag) {
        this.trnDiaSubSet(trndiaVo, argSubtyp, argSubKey, argDiaTyp, argDat, argCod, argNam, argFrm, argWriteFlag, null, null);
    }
    /**
     *   source:trndia.0053.script
     */
    public String internalGetOwnUsrForDia(SimpleModuleVo linkModule) {
        //! function used to get the responsible user for a diary-entry dependent on associated contract.
        //! Internaly the follwoing searchsequence takes place
        //! OWNUSR of contract, OWNUSR of maincontract as passed to TRNDIA, Current-User
        //! ArgLbl holds a control entry
        String ownusr = "";
        if (StringUtils.isNotEmpty(linkModule.getObjinr()) && StringUtils.isNotEmpty(linkModule.getObjtyp())) {
            ownusr = dyncDaoService.dyncReadFieldByInr(linkModule.getObjtyp(), linkModule.getObjinr(), "ownusr");
        }
        if (StringUtils.isEmpty(ownusr)) {
            ownusr = SettleContext.getUserSession().getUsr().getExtkey();
        }
        return ownusr;
    }

    public void internalSetAddFldForDia(DiaVo argDia) {
        //! function used to set additional fields dependent on associated contract.
        //! ArgDia holds an actual diary
        //! ArgLbl holds the Label (as in the control stream)
        // in product contains no logic
        switch (argDia.getDiatyp()) {
            case "EXPLIO":
                argDia.setInftxt("Please cancel this L/C.");
                break;
            case "RQTPAY":
                argDia.setInftxt("Request client to effect payment, please!");
                break;
            case "RQTACP":
                argDia.setInftxt("Please cancel this L/C");
                break;
            case "EXPLSG":
                argDia.setInftxt("Request client to return expired S/G!");
                break;
            case "SGDNRV":
                argDia.setInftxt("Documents under S/G not received yet!");
                break;
            case "TRTDUE":
                argDia.setInftxt("Remind client of maturity date of Import Loan.");
                break;
            case "EXPBCT":
                argDia.setInftxt("Dead collection, cancel it? Contact drawee or remitting bank, please!");
                break;
            case "UNAUTH":
                argDia.setInftxt("Unauthenticated Credit instrument or Amendment! Or the instrument is not operative!");
                break;
            case "BEARBT":
                argDia.setInftxt("Send Reimbursement Claim, please! (tele-transmission)");
                break;
            case "BEARBL":
                argDia.setInftxt("Send Reimbursement Claim, please! (letter)");
                break;
            case "BEPRBT":
                argDia.setInftxt("Proceeds not received yet! Contact reimbursing bank please!(tele-claim)");
                break;
            case "BEPRBL":
                argDia.setInftxt("Proceeds not received yet! Contact reimbursing bank please!(mail-claim)");
                break;
            case "CLMRBL":
                argDia.setInftxt("Proceeds not received yet! Contact reimbursing bank please!(mail-claim)");
                break;
            case "BEPIBT":
                argDia.setInftxt("Proceeds not received yet! Contact issuing bank please! (tele-transmission)");
                break;
            case "BEPIBL":
                argDia.setInftxt("Proceeds not received yet! Contact issuing bank please!(letter)");
                break;
            case "BEAIBT":
                argDia.setInftxt("Overdue! But proceeds not received yet! Contact issuing bank please! (tele-transmission)");
                break;
            case "BEAIBL":
                argDia.setInftxt("Overdue! But proceeds not received yet! Contact issuing bank please! (letter)");
                break;
            case "EXPLTT":
                argDia.setInftxt("Transferable L/C expired!");
                break;
            case "CLMBED":
                argDia.setInftxt("Proceeds under negotiated bill not received yet! ");
                break;
            case "CLMBOD":
                argDia.setInftxt("Loan under this bill is due today! Contact the client please! ");
                break;
            case "EXPLEO":
                argDia.setInftxt("Cancel this export L/C! ");
                break;
            case "EXPGIO":
                argDia.setInftxt("Please cancel this Guarantee! ");
                break;
            case "EXPGUA":
                argDia.setInftxt("Please cancel this Guarantee! ");
                break;
            case "EXPGCM":
                argDia.setInftxt("Please process this Guarantee Cliam! ");
                break;
            default:
                if (MdaUtils.compareTo(Strings.mid(argDia.getDiatyp(), 1, 3), "BET") == 0) {
                    argDia.setInftxt("Proceeds not received yet! Contact reimbursing bank please!");
                }
                if (MdaUtils.compareTo(Strings.mid(argDia.getDiatyp(), 1, 3), "GID") == 0) {
                    argDia.setInftxt("Please Product fee of this Guarantee");
                }
                if (MdaUtils.compareTo(Strings.mid(argDia.getDiatyp(), 1, 3), "GET") == 0) {
                    argDia.setInftxt("Please Product fee of this Guarantee");
                }
        }

    }
    /**
     *   source:trndia.0068.script
     */
    public void setDiaPty(TrndiaVo trndia, DiaVo argDia,String argDiaTyp) {
        String rol = getPtyRol(trndia.getRec());
        Pty pty = sysmodService.getPtyobj(rol, trndia.getPtsList());
        if (pty != null) {
            if(!argDia.isModified("ptyextkey")) {
                argDia.setPtyextkey(pty.getExtkey());
            }
            if(!argDia.isModified("ptynam")) {
                argDia.setPtynam(pty.getNam1());
            }
        }
        /*String frame = SettleContext.getTransName();
        //所有承兑、付款增加客户信息
        if( MdaUtils.compareTo(frame,"LITDCK") == 0
                || MdaUtils.compareTo(frame,"DITDCK") == 0
                || MdaUtils.compareTo(frame,"BRTUDP") == 0
                || MdaUtils.compareTo(frame,"BDTUDP") == 0
                || MdaUtils.compareTo(frame,"BCTDAV") == 0 ) {
            String diatyp = Strings.mid(argDiaTyp,1,4);
            String diatyp3 = Strings.mid(argDiaTyp,1,3);
            if( MdaUtils.compareTo(argDiaTyp,"RQTPAY") == 0 || MdaUtils.compareTo(argDiaTyp,"RQTACP") == 0 || MdaUtils.compareTo(argDiaTyp,"BCTPAY") == 0 || MdaUtils.compareTo(diatyp,"RQTP") == 0 || MdaUtils.compareTo(diatyp,"CLMI") == 0 || MdaUtils.compareTo(diatyp3,"BET") == 0 ) {
                String rol = getPtyRol(trndia.getRec());
                Pty pty = sysmodService.getPtyobj(rol, trndia.getPtsList());
                if (pty != null) {
                    if(!argDia.isModified("ptyextkey")) {
                        argDia.setPtyextkey(pty.getExtkey());
                    }
                    if(!argDia.isModified("ptynam")) {
                        argDia.setPtynam(pty.getNam1());
                    }
                }
            }
        }*/
    }
    /**
     *   source:trndia.0066.script
     */
    public String getPtyRol(BizInfoVo rec) {
        String frame = SettleContext.getTransName();
        String rol = NULLSTR;
        String hndtyp = NULLSTR;
        String ownref = NULLSTR;
        switch( Strings.mid(frame,1,2) ) {
            case "LT":
            case "BT":
                rol = "BE1";
                break;
            case "LE":
            case "BE":
            case "BF":
                rol = "BEN";
                break;
            case "TR":
                rol = "FIP";
                break;
            case "BP":
                rol = "FIA";
                break;
            case "BC":
                rol = "DRE";
                break;
            case "BO":
                rol = "DRR";
                break;
            case "LI":
            case  "DI":
            case  "BR":
            case  "BD":
                rol = "APL";
                break;
            case "NE":
            case "GE":
                rol = "BEN";
                break;
            case "GI":
            case "NI":
            case "HI":
                rol = "APL";
                if( MdaUtils.compareTo(Strings.mid(frame,1,3),"GIT") == 0
                    || MdaUtils.compareTo(Strings.mid(frame,1,3),"NIT") == 0
                    || MdaUtils.compareTo(Strings.mid(frame,1,3),"HIT") == 0) {
                    hndtyp = Utils.getFieldValue(rec, "hndtyp", "");
                    if( MdaUtils.compareTo(hndtyp,"OT") == 0 ) {
                        rol = "BEN";
                    } else {
                        rol = "APL";
                    }
                }
                break;
            case "CP":
                switch( frame ) {
                    case "CPTOPN":
                    case  "CPTATO":
                        rol = "ORC";
                        break;
                    case "CPTADV":
                    case  "CPTATI":
                        rol = "PYE";
                        break;
                    default:
                        ownref = Utils.getFieldValue(rec, "ownref", "");
                        if( MdaUtils.compareTo(Strings.mid(ownref,1,2),"TT") == 0 ) {
                            rol = "ORC";
                        } else {
                            rol = "PYE";
                        }
                }
                break;
            default:
                rol = "APL";
        }
        return  rol;

    }
    /**
     *   source:trndia.0065.script
     */
    public void internSetDatOfDia(DiaVo argDia, Date argDat, String argFlg) {
        //! set date fo diary
        //! ArgDia holds the loaded content
        //! ArgData holds assigned value
        //! ArgFlg used to determine whether InternDiaSet called by automaticaly or manualy created diaries.
        //! it can contain follow values: "F" - for diaries created by transaction and "M" - for manualy created diaries
        if(!argDia.isModified("dat")) {
            argDia.setDat( argDat);
            if( MdaUtils.isEmpty(argDia.getDat()) ) {
                log.warn(Strings.getText("Are you sure that you want to set a diary \\'$1\\' without date?",argDia.getNam()));
                //Dynamic.sysWarningSet( SYSWRNTypeWarning, Strings.getText("Are you sure that you want to set a diary \\'$1\\' without date?",argDia.getNam()), argDia.getDiatyp() + "OLDDAT" );
            } else {
                if( Dates.diff(argDia.getDat(),Dates.today())<0 ) {
                    log.warn(Strings.getText("Diary \\'$1\\': The Date of Diary \\'$2\\' is in the past.",argDia.getNam(),argDia.getDat()));
                    //Dynamic.sysWarningSet( SYSWRNTypeWarning, Strings.getText("Diary \\'$1\\': The Date of Diary \\'$2\\' is in the past.",argDia.getNam(),argDia.getDat()), argDia.getDiatyp() + "OLDDAT" );
                } else {
                    //Dynamic.sysWarningSet( SYSWRNTypeWarning, "", argDia.getDiatyp() + "OLDDAT" );
                }
            }
        } else {
            // this warning to be set always if field modified by user
            if( MdaUtils.compareTo(argFlg,"F") == 0 ) {
                log.warn(Strings.getText("Diary \\'$1\\': The Date of Diary \\'$2\\' has been modified.\\nThis user input will not automatically be overwritten in this transaction.",argDia.getNam(),argDia.getDat()));
                //Dynamic.sysWarningSet( SYSWRNTypeWarning, Strings.getText("Diary \\'$1\\': The Date of Diary \\'$2\\' has been modified.\\nThis user input will not automatically be overwritten in this transaction.",argDia.getNam(),argDia.getDat()), argDia.getDiatyp() + "MODDAT" );
            }
            // clear other warning
            //Dynamic.sysWarningSet( SYSWRNTypeWarning, "", argDia.getDiatyp() + "OLDDAT" );
        }

    }

    public void syncDealQueByDia(String objtyp,String objinr){
        List<Dia> diaList =diaMapper.getDiaByObjtypAndObjinr(objtyp,objinr);
        diaList.forEach(dia->{
            quemodService.saveEntryByDia(dia);
        });
    }

    @Override
    public void trnDiaSetInftxt(TrndiaVo trndiaVo, String argDiaTyp, String inftxt) {
        BizInfoVo rec = trndiaVo.getRec();
        String objinr = rec.getObjinr();
        String objtyp = rec.getObjtyp();
        log.debug("更新objinr {}, objtyp{}, 类型{}的备忘录的描述信息", objinr, objtyp, argDiaTyp);
        int find = -1;
        for (int i=0; i<trndiaVo.getDias().size(); i++) {
            DiaVo diaVo = trndiaVo.getDias().get(i);
            if (objtyp.equals(diaVo.getObjtyp())
                    && objinr.equals(diaVo.getObjinr())
                    && "".equals(diaVo.getSubkey())
                    && argDiaTyp.equals(diaVo.getDiatyp())) {
                find = i;
                break;
            }
        }
        if (find == -1) {
            log.debug("没有找到对应的Diary记录");
            return;
        }
        trndiaVo.getDias().get(find).setInftxt(inftxt);
    }

    /**
     *   备忘录注册扩展方法
     */
    @Override
    public void trnDiaSet(TrndiaVo trndiaVo, String argDiaTyp, Date argDat, String argCod, String argNam, String argFrm, String argWriteFlag, SimpleModuleVo linkModule, String argObjref) {
        this.trnDiaSubSet(trndiaVo,"", "", argDiaTyp, argDat, argCod, argNam, argFrm, argWriteFlag, linkModule, argObjref);
    }

    /**
     *   备忘录注册扩展方法
     */
    @Override
    public void trnDiaSubSet(TrndiaVo trndiaVo, String argSubtyp, String argSubKey, String argDiaTyp, Date argDat, String argCod, String argNam, String argFrm, String argWriteFlag, SimpleModuleVo linkModule, String argObjref) {
        //! Routine to define a diary entry to be created or updated by the calling transaction.
        //! ArgRec has to hold the owning contract group.
        //! ArgDiaTyp is a per contract unique identification of diary entries.
        //!  If this field is left empty it is defaulted with the contents auf ArgCod.
        //! ArgDat holds the date of the new / updated diary entry.
        //! ArgCod holds the COD of the created / updated diary entry.
        //! ArgNam holds the Descriptiontext of the created / updated diary entry.
        //! ArgFrm holds the Target Transaction to be executed of the created / updated diary entry.
        //! ArgWriteFlag controls the behaviour.
        // The function gets a flag handed over (ArgWriteFlag), which steers whether the function is to delete
        // first all existing dates of the contract to the handed over type of date or not.
        // Normally this function is to be used in such a way that the existing dates are deleted.
        //! The possible ArgWriteFlag values are made available as figurative constant.
        //! The suggested values:  DiaToReplace (=R), DiaToWrite(=W), DiaFirstOfSet(=F), DiaNextOfSet(=N)
        //! DiaToReplace means: update the possibly already existing date set otherwise add a new entry. That is a standard case
        //! DiaToWrite means: add a new entry if diary doesn`t already exist. If a diaryexists and is read from DB, add a new one,
        //! otherwise a found diary is to be replaced. Used for homogeneous, from each other independent dates.
        //! DiaFirstOfSet means: This is the first diary of the group of diaries.
        //! First from the group is replaced, if exists otherwise is added, further are deleted.
        //! DiaNextOfSet means: add a new diary. If already exists, determine a new SubId to the ArgDiaTyp and add a new one
        // check, if ATC record for the actual transaction and ArgDiaTyp is defined.
        // If so: no action here, will be executed later.
        if (linkModule == null) {
            linkModule = SimpleModuleVo.buildModule(trndiaVo.getRec());
        }
        if (StringUtils.isEmpty(argObjref)) {
            argObjref = trndiaVo.getRec().getOwnref();
        }
        String objtyp = linkModule.getObjtyp();
        String objinr = linkModule.getObjinr();
        log.debug("{},{}插入或者新增备忘录数据,DiaSubTyp:{},DiaSubKey:{},DiaType:{},DiaDate:{},DiaCode:{},DiaName:{},DiaFrm:{}", objtyp, objinr, argSubtyp, argSubKey, argDiaTyp, argDat, argCod, argNam, argFrm);
        int find = -1;
        for (int i=0; i<trndiaVo.getDias().size(); i++) {
            DiaVo diaVo = trndiaVo.getDias().get(i);
            if (objtyp.equals(diaVo.getObjtyp())
                    && objinr.equals(diaVo.getObjinr())
                    && argSubKey.equals(diaVo.getSubkey())
                    && argDiaTyp.equals(diaVo.getDiatyp())) {
                find = i;
                break;
            }
        }
        DiaVo diaVo = null;
        if (find == -1) {
            log.debug("没有找到记录，将会新增一条备忘录");
            diaVo = new DiaVo();
            trndiaVo.getDias().add(diaVo);
        } else {
            log.debug("找到了备忘录记录");
            diaVo = trndiaVo.getDias().get(find);
        }
        if (MdaUtils.compareTo(argWriteFlag,DiaToReplace) == 0 && find > -1) {
            argNam = diaVo.getNam();
        }
        internalTrnDiaSet(trndiaVo, diaVo, argSubtyp, argSubKey, argDiaTyp, argDat, argCod, argNam, argFrm, argWriteFlag, linkModule, argObjref);
    }

    @Override
    public void updateDiaObjmodpath(TrndiaVo trndiaVo, String argSubKey, String argDiaTyp, SimpleModuleVo linkModule) {
        if (linkModule == null) {
            log.debug("模型为空，无法更新");
            return;
        }
        for (int i=0; i<trndiaVo.getDias().size(); i++) {
            DiaVo diaVo = trndiaVo.getDias().get(i);
            if (linkModule.getObjtyp().equals(diaVo.getObjtyp())
                    && argSubKey.equals(diaVo.getSubkey())
                    && argDiaTyp.equals(diaVo.getDiatyp())) {
                if (StringUtils.isEmpty(diaVo.getObjinr())) {
                    diaVo.setObjmodpath(Utils.toJson(linkModule));
                }
            }
        }
    }

    /**
     *   备忘录注册扩展方法
     */
    public void internalTrnDiaSet(TrndiaVo trndia, DiaVo diaVo, String argSubTyp, String argSubKey, String argDiaTyp, Date argDat, String argCod, String argNam, String argFrm, String argWriteFlag, SimpleModuleVo linkModule, String argObjref) {
        //! Routine to define a diary entry to be created or updated by the calling transaction.
        //! ArgRec has to hold the owning contract group.
        //! ArgDiaTyp is a per contract unique identification of diary entries.
        //!  If this field is left empty it is defaulted with the contents auf ArgCod.
        //! ArgDat holds the date of the new / updated diary entry.
        //! ArgCod holds the COD of the created / updated diary entry.
        //! ArgNam holds the Descriptiontext of the created / updated diary entry.
        //! ArgFrm holds the Target Transaction to be executed of the created / updated diary entry.
        //! ArgWriteFlag controls the behaviour.
        //! ArgWrkStm holds the entries of type ArgDiaTyp
        if( MdaUtils.compareTo(argWriteFlag,DiaToWrite) != 0 && MdaUtils.compareTo(argWriteFlag,DiaToReplace) != 0 ) {
            throw new CommonServiceException("TRNDIA: TrnDiaSet called with unknown WriteFlag.");
        }
        if(Strings.len(argDiaTyp) > 6) {
            throw new CommonServiceException("TRNDIA: TrnDiaSet called with too long DIATYP. Database field DIATYP may not be longer as 6 digits.");
        }
        if(MdaUtils.isEmpty(argDiaTyp)) {
            argDiaTyp = argCod;
        }
        internDiaSet(trndia, diaVo, argSubTyp, argSubKey, argDiaTyp, argDat, argCod, argNam, argFrm, linkModule, argObjref);
    }

    /**
     *   备忘录注册扩展方法
     */
    public void internDiaSet(TrndiaVo trndia, DiaVo diaVo, String argSubTyp,String argSubKey,String argDiaTyp,Date argDat,String argCod,String argNam,String argFrm, SimpleModuleVo linkModule, String argObjref) {
        //! fill a new dia record with mandatory fields
        //! ArgPth holds the path of contract the Diary entry is associated to
        //! ArgDia holds the loaded content
        //! ArgDiaTyp,ArgDat,ArgCod,ArgNam,ArgFrm are assigned values
        //! ArgFlg used to determine whether InternDiaSet called by automaticaly or manualy created diaries.
        //! it can contain follow values: "F" - for diaries created by transaction and "M" - for manualy created diaries
        // Refers to InternSetRestOfFieldsToDia
        // set argument fields if they are not modified
        log.debug("更新Diary数据");
        diaVo.setDiatyp( argDiaTyp);
        if(!diaVo.isModified("cod") ) {
            diaVo.setCod( argCod);
        }
        if(!diaVo.isModified("nam") ) {
            diaVo.setNam( argNam);
        }
        if(!diaVo.isModified("frm") ) {
            diaVo.setFrm( argFrm);
        }
        if (linkModule == null) {
            linkModule = SimpleModuleVo.buildModule(trndia.getRec());
        }
        if (StringUtils.isEmpty(argObjref)) {
            argObjref = trndia.getRec().getOwnref();
        }
        diaVo.setObjmodpath(Utils.toJson(linkModule));
        // set rest of fields
        if(MdaUtils.isEmpty(diaVo.getObjtyp())) {
            diaVo.setObjtyp(linkModule.getObjtyp());
        }
        if(MdaUtils.isEmpty(diaVo.getObjinr())) {
            diaVo.setObjinr(linkModule.getObjinr());
        }
        diaVo.setSubtyp(argSubTyp);
        diaVo.setSubkey(argSubKey);
        if(MdaUtils.isEmpty(diaVo.getObjref())) {
            diaVo.setObjref(argObjref);
        }
        setDiaPty(trndia, diaVo, argDiaTyp );
        BigDecimal payamt = BigDecimal.ZERO;
        String frame = SettleContext.getDirectTransName();
        switch(frame) {
            case  "BRTSET":
            case  "BCTSET":
            case  "CPTOPN":
            case  "CPTATO":
            case  "GITSET":
            case  "NITSET":
            case  "CPTADD":
            case  "BRTADD":
            case  "BCTADD":
            case  "GCTADD":
            case  "NCTADD":
                BizInfoVo rec = trndia.getRec();
                if( MdaUtils.compareTo(argCod,"RAM") == 0 ) {
                    String rol = getPtyRol(rec);
                    Pty pty = sysmodService.getPtyobj(rol, trndia.getPtsList());
                    if (pty != null) {
                        if(!diaVo.isModified("ptyextkey")) {
                            diaVo.setPtyextkey( pty.getExtkey());
                        }
                        if(!diaVo.isModified("ptynam")) {
                            diaVo.setPtynam( pty.getNam1());
                        }
                    }
                    if(!diaVo.isModified("prechkdat")) {
                        /**
                         $prechkdat = GetContentDate( ArgPth + "\\\\PRECHKDAT" )
                         **/
                        // 付款、修改交易取各自栏位上的预计核验日期
                        Date prechkdat = Utils.getFieldValue(rec, "prechkdat");
                        diaVo.setPrechkdat(prechkdat);
                    }
                    if(!diaVo.isModified("paycur") ) {
                        diaVo.setPaycur(trndia.getSetcur());
                    }
                    if(!diaVo.isModified("payamt") ) {
                        switch( frame ) {
                            //刘文青要求都取单据金额
                            case "CPTOPN":
                            case "CPTATO":
                                payamt = trndia.getSetamt();
                                break;
                            case "BRTSET":
                            case  "BCTSET":
                            case  "GITSET":
                            case  "NITSET":
                            case  "CPTADD":
                            case  "BRTADD":
                            case  "BCTADD":
                            case  "GCTADD":
                            case  "NCTADD":
                                Cbb cbb = trndia.getCbsMap().getOrDefault("MAX", new Cbb());
                                payamt = cbb.getAmt();
                                break;
                        }
                        diaVo.setPayamt( payamt);
                    }
                }
                break;
            default:
        }
        if(MdaUtils.isEmpty(diaVo.getSubid()) ) {
            diaVo.setSubid("00");
        }
        if(MdaUtils.isEmpty(diaVo.getUsr())) {
            diaVo.setUsr(SettleContext.getUserSession().getUsr().getExtkey());
        }
        if( MdaUtils.isEmpty(diaVo.getOwnusr()) ) {
            diaVo.setOwnusr(internalGetOwnUsrForDia(linkModule));
        }
        // if diary created by transaction and was set to done in transaction (= with TrnDiaSetDone)
        // then by TrnDiaSet DONFLG must be reseted (sample usage in GITAME.diasav)
        if(!diaVo.isModified("donflg") && !MdaUtils.isEmpty(diaVo.getDonflg()) ) {
            diaVo.setDonflg("");
        }
        if(!diaVo.isModified("dat")) {
            diaVo.setDat(argDat);
        }
        internalSetAddFldForDia(diaVo);

    }
}
