package com.brilliance.isc.common.trndoc.service.impl;

import cn.hutool.core.lang.Assert;
import com.brilliance.mda.runtime.mda.CodetableItem;
import com.brilliance.mda.runtime.mda.IStream;
import com.brilliance.mda.runtime.mda.impl.Argument;
import com.brilliance.mda.runtime.mda.impl.StreamImpl;
import com.brilliance.mda.runtime.mda.util.*;
import com.brilliance.isc.bo.*;
import com.brilliance.isc.common.cache.atpbch.AtpBchCacheService;
import com.brilliance.isc.common.cache.pta.PtaCacheService;
import com.brilliance.isc.common.cache.ptm.PtmCacheService;
import com.brilliance.isc.common.codetable.service.CodetableService;
import com.brilliance.isc.common.component.PtsptaToolComponent;
import com.brilliance.isc.common.context.AppEnv;
import com.brilliance.isc.common.context.SettleContext;
import com.brilliance.isc.common.context.SpringEnvContext;
import com.brilliance.isc.common.counter.service.CounterService;
import com.brilliance.isc.common.doc.ITransactionDocSet;
import com.brilliance.isc.common.doc.TextResultVo;
import com.brilliance.isc.common.docimm.service.DocimmService;
import com.brilliance.isc.common.exception.CommonServiceException;
import com.brilliance.isc.common.sysmod.SysmodService;
import com.brilliance.isc.common.tools.service.ObjectStroeToolService;
import com.brilliance.isc.common.transaction.help.TransactionHelpService;
import com.brilliance.isc.common.trndoc.service.DoceotService;
import com.brilliance.isc.common.trndoc.service.TrndocService;
import com.brilliance.isc.common.trndoc.vo.CorTypeWfmEnum;
import com.brilliance.isc.common.trndoc.vo.DoceotVo;
import com.brilliance.isc.common.trndoc.vo.TrndocVo;
import com.brilliance.isc.common.trnism.service.TrnismService;
import com.brilliance.isc.common.util.SettleExceptionUtils;
import com.brilliance.isc.common.util.Utils;
import com.brilliance.isc.common.vo.PtsptaVo;
import com.brilliance.isc.mda.dao.ApfMapper;
import com.brilliance.isc.mda.dao.CtyMapper;
import com.brilliance.isc.mda.dao.EtaMapper;
import com.brilliance.isc.mda.dao.SmhMapper;
import com.brilliance.isc.common.util.DocUtils;
import com.brilliance.isc.utils.StringUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
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.io.ByteArrayInputStream;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

import static com.brilliance.mda.runtime.mda.Constants.CR;
import static com.brilliance.mda.runtime.mda.Constants.NULLSTR;

@Service
public class DoceotServiceImpl implements DoceotService {

    private static final Set<String> TECHNICAL_CORTYP = new HashSet<>(
            Arrays.asList("SWT", "TLX", "FAX", "EML", "EMA", "TCO", "TCA", "RTG", "TAR", "DTE", "DTA", "BOL", "BOA", "FIL", "TXT", "IZV", "ERX")
    );
    private static Logger log = LoggerFactory.getLogger(TrndocServiceImpl.class);
    @Autowired
    private TrndocService trndocService;

    @Autowired
    private PtsptaToolComponent ptsptaToolComponent;

    @Autowired
    private CodetableService codetableService;

    @Autowired
    private TransactionHelpService transactionHelpService;

    @Autowired
    private CounterService counterService;

    @Autowired
    private DocimmService docimmService;

    @Autowired
    private TrnismService trnismService;

    @Autowired
    private AppEnv appEnv;

    @Autowired
    private PtaCacheService ptaCacheService;

    @Autowired
    private SmhMapper smhMapper;

    @Autowired
    private EtaMapper etaMapper;

    @Autowired
    private ApfMapper apfMapper;

    @Autowired
    private CtyMapper ctyMapper;

    @Autowired
    private SysmodService sysmodService;

    @Autowired
    private ObjectStroeToolService objectStroeToolService;

    @Autowired
    private PtmCacheService ptmCacheService;


    @Autowired
    private AtpBchCacheService atpBchCacheService;


    /**
     * source:doceot.0052.script
     */
    public void setSRTKEY(DoceotVo doceot) {
        // Set SRTKEY for this entry
        // - to determine order of display (copies following original)
        // - to assert that original is saved before copies
        String srtadd = NULLSTR;
        switch (doceot.getLev()) {
            case "1":
                doceot.setSrtkey(doceot.getRole() + doceot.getId());
                break;
            case "2":
            case "3":
                // order `send to` before `copy`
                if ("S".equals(doceot.getOriflg())) {
                    srtadd = "1";
                } else {
                    srtadd = "2";
                }
                doceot.setSrtkey(doceot.getRole() + Strings.mid(doceot.getIdref(), 1, 12) + "   " + srtadd + Strings.mid(doceot.getId(), 13));
                break;
            case "4": // additional document
                doceot.setSrtkey(doceot.getRole() + doceot.getId());
                break;
            case "5": // attachment
                doceot.setSrtkey(doceot.getRole() + Strings.mid(doceot.getIdatt(), 1, 15) + "5" + doceot.getId());
                break;
        }
    }

    /**
     * source:doceot.0080.script
     */
    public void setAddressingInfo(DoceotVo doceot, List<PtsptaVo> ptsptaList) {
        //goto skipreread
        // reread ADR required for ADR\\BIC ...
        String sql = NULLSTR;
        if (!MdaUtils.isEmpty(doceot.getPtainr())) {
            //   use cached read of PTAOBJINR instead of SdbRead( PTA, PTAINR )
            doceot.setPtainfo(NULLSTR);
            Pta pta = ptaCacheService.getPtaByInr(doceot.getPtainr());
            if (pta != null) {
                doceot.setPtaadrinr(pta.getObjinr());
                doceot.setPtaptyinr(pta.getPtyinr());
            }
            doceot.setPtainfo(sysmodService.midObjinr(doceot.getPtaadrinr()) + sysmodService.midObjinr(doceot.getPtaptyinr()));
            doceot.setPtainrold(doceot.getPtainr());
        } else {
            doceot.setPtainfo(NULLSTR);
            doceot.setPtaadrinr(NULLSTR);
            doceot.setPtaptyinr(NULLSTR);
        }
        PtsptaVo ptspta = null;
        if (!MdaUtils.isEmpty(doceot.getPtainr())) {
            ptspta = ptsptaToolComponent.getPtsptaFromPtaINR(doceot.getPtainr());
            ptspta.reset();
            ptspta.getPts().setRol(doceot.getRole());
            ptspta.getPts().setPtainr(doceot.getPtainr());
            for (PtsptaVo bean : ptsptaList) {
                if (doceot.getPtainr().equals(bean.getPtainr())) {
                    ptspta.getPts().setExtkey(bean.getExtkey());
                    ptspta.getPts().setAdrblk(bean.getAdrblk());
                }
            }
        } else {
            ptspta = new PtsptaVo();
            ptspta.reset();
            if (!MdaUtils.isEmpty(doceot.getAdrblk())) {
                ptspta.getPts().setAdrblk(doceot.getAdrblk());
            }
        }
        doceot.setRcv(ptspta);
        // #######TODO 改写 LABEL与GOTO   ####    label skipreread
        if (!doceot.isModified("adrbic") && !doceot.isModified("adrbicaut")) {
            doceot.setAdrbic(ptspta.getAdr().getBic());
            doceot.setAdrbicaut(getPtmField(doceot.getPtainr(), "SWT", "AUTFLG"));
        }
        if (!doceot.isModified("adrtlx")) {
            doceot.setAdrtlx(ptspta.getAdr().getTlx());
        }
        if (!doceot.isModified("adrtlxaut")) {
            doceot.setAdrtlxaut(getPtmField(doceot.getPtainr(), "TLX", "AUTFLG"));
            if (MdaUtils.isEmpty(doceot.getAdrtlxaut())) {
                doceot.setAdrtlxaut("N");
            }
        }
        if (!doceot.isModified("adrfax")) {
            doceot.setAdrfax(ptspta.getAdr().getFax1());
        }
        if (!doceot.isModified("adreml")) {
            doceot.setAdreml(ptspta.getAdr().getEml());
        }
        String frm = SettleContext.getTransName();
        if ((!doceot.isModified("adrblk")) && (!MdaUtils.isEmpty(ptspta.getPts().getAdrblk()))) {
            if (MdaUtils.compareTo(Strings.mid(Strings.toUpper(frm), 1, 3), "DIT") == 0 || MdaUtils.compareTo(Strings.mid(Strings.toUpper(frm), 1, 3), "BDT") == 0 || MdaUtils.compareTo(Strings.mid(Strings.toUpper(frm), 1, 3), "DET") == 0 || MdaUtils.compareTo(Strings.mid(Strings.toUpper(frm), 1, 3), "BFT") == 0) {
                doceot.setAdrblk(ptspta.getDbfadrblkcn());
            } else {
                doceot.setAdrblk(ptspta.getPts().getAdrblk());
            }
        }
        if (!doceot.isModified("adrtid")) {
            doceot.setAdrtid(ptspta.getAdr().getTid());
        }
        if (!doceot.isModified("adrdtacid")) {
            doceot.setAdrdtacid(ptspta.getAdr().getDtacid());
        }
        if (!doceot.isModified("adrdtecid")) {
            doceot.setAdrdtecid(ptspta.getAdr().getDtecid());
        }
        if (!doceot.isModified("adrrid")) {
            doceot.setAdrrid(getPtmField(doceot.getPtainr(), "BOL", "CORADR"));
        }
        if (MdaUtils.compareTo(doceot.getRoladr(), "OTH") == 0) {
            //Systems.setVisible(this,"adrref");
            //Systems.setEnabled(this,"adrref");
            if (!doceot.isModified("adrref")) {
                doceot.setAdrref(NULLSTR);
            }
        } else {
            //Systems.setVisible(this,"adrref");
            //Dynamic.disableAndClearField( MdaDriver.getDatafield(this,"adrref") );
            ptspta = ptsptaToolComponent.getPtsFromListByRol(ptsptaList, doceot.getRoladr());
            if (ptspta != null) {
                doceot.setAdrref(ptspta.getRef());
            }
        }
    }

    /**
     * source:doceot.0059.script
     */
    public String getPtmField(String argInr, String argCortyp, String argSeaFld) {
        List<Ptm> ptms = ptmCacheService.getPtmListByPtainr(argInr);
        if (ptms == null || ptms.size() == 0) {
            return "";
        }
        Ptm tempPtm = null;
        for (Ptm ptm : ptms) {
            if (argCortyp.equalsIgnoreCase(ptm.getCortyp())) {
                tempPtm = ptm;
                break;
            }
        }
        if (tempPtm != null) {
            return Utils.getFieldValue(tempPtm, argSeaFld.toLowerCase());
        }
        return "";
    }

    /**
     * source:doceot.0086.script
     */
    public void setDOCCORSEA(DoceotVo doceot) {
        // SetDOCCORSEA determines, which CORTYPes are possible
        // depending on the list of available structures (DOCSTRSEA)
        // SetDOCCORSEA depends on the available communication channels within
        // an installation and their technical structure
        // (e.g. on availability and formatting features of a FAX gateway)
        // list must be generated in order of preference
        // Depending on available communication chanels with the addressee
        // this list will be reduced to be used as selection list for CORTYP
        IStream sortStream = new StreamImpl();
        Streams.streamClear(sortStream);
        String addcortyp = NULLSTR;
        String cortyp = NULLSTR;
        for (int idx = 2; idx <= Strings.len(doceot.getDocstrsea()); idx += 3) {
            String structure = Strings.mid(doceot.getDocstrsea(), idx, 1);
            switch (structure) {
                case "S":  //SWIFT
                    addcortyp = "1SWT 4TLX 7FAX 9EML";
                    break;
                case "X":  //Telex
                    addcortyp = "2SWT 3TLX 7FAX 9EML";
                    break;
                case "L":  // Letter
                    addcortyp = "5LET 6SWT 7TLX 7TCO 8FAX 9EML";
                    break;
                case "T":  //TradeConnect
                    addcortyp = "1TCO";
                    break;
                case "D": // DocX
                    addcortyp = "1TCX";
                    break;
                case "R":  // RTGS Plus Target
                    addcortyp = "0RTG 1TAR";
                    break;
                case "I":  // Internal
                    addcortyp = "0INT";
                    break;
                case "B":        // Internal
                    addcortyp = "0BOL";
                    break;
                case "U": // TSU
                    addcortyp = "0TSU";
                    break;
                case "A":  // Internal
                    addcortyp = "0DTA";
                    break;
                case "E":        // Internal
                    addcortyp = "0DTE";
                    break;
                case "G": // DO5DOS.007282 - DTA Guarantees
                    addcortyp = "0DTG";
                    break;
                case "J":
                    addcortyp = "0TXT"; // ASCII text
                    break;
                case "Z":
                    addcortyp = "0IZV"; // DTAUS / IZV
                    break;
                case "P":
                    addcortyp = "0SPA"; // SEPA
                    /**
                     case "C"
                     $ADDCORTYP = "0SIC" // SIC / EuroSIC
                     **/
                    break;
                case "O":
                    addcortyp = "0SWT"; // SWIFT Score
                    //境内外币支付
                    break;
                case "Q":
                    addcortyp = "0FMT"; //FMT
                    //##Add by byte for ERS Load
                    break;
                case "F":
                    addcortyp = "0ERX"; //ERS XML Document
                    break;
                case "M":
                    addcortyp = "0ERC"; //ERC XML Document
                    //电证
                    break;
                case "C":
                    addcortyp = "0ELC"; //ELC
                    break;
            }
            for (int i = 1; i <= Strings.len(addcortyp); i += 5) {
                cortyp = Strings.mid(addcortyp, i, 4);
                Streams.streamInsert(sortStream, 0, cortyp);
            }
        }
        // Build DOCCORSEA in order of preferences
        doceot.setDoccorsea(NULLSTR);
        Streams.streamSort(sortStream);
        int stmCnt = Streams.streamCount(sortStream);
        for (int i = 1; i <= stmCnt; i++) {
            cortyp = Strings.mid(Strings.getLine(sortStream, i), 2, 4);
            if (Strings.pos(doceot.getDoccorsea(), cortyp) == 0) {
                doceot.setDoccorsea(doceot.getDoccorsea() + cortyp);
            }
        }
    }


    public List<String> getEnableCortypList(DoceotVo doceot) {
        try {
            //账务模块的面函，则应该从账务模块取
            if (doceot.getId().startsWith("SET")) {
                ITransactionDocSet transactionDocSet = SpringEnvContext.getBean("settle.docset");
                return transactionDocSet.getEnableCortypes(doceot);
            }
            ITransactionDocSet transactionDocSet = SpringEnvContext.getBean(atpBchCacheService.getSdTransNameForRegister().toLowerCase() + ".docset");
            return transactionDocSet.getEnableCortypes(doceot);
        } catch (NoSuchBeanDefinitionException e) {
            return trndocService.getCortypeList();
        }
    }

    /**
     * source:doceot.0000.script
     */
    public void setCORTYP(DoceotVo doceot) {
        // set (in DOCEOTGRID) selectable CORTYP depending on addressing info and DOCCORSEA
        if (MdaUtils.compareTo(doceot.getLev(), "5") == 0) {
            //Systems.resetEnabled(this,"cortyp");
            //Systems.setValues(this,"cortyp",this.getCortyp());
            return;
        }
        if (specialCorTypDef(doceot)) {
            return;
        }
        //Systems.setEnabled(this,"cortyp");
        // if passed PTA has changed, redefault of CORTYP is triggered in defdoceot via `if DOCEOT( $i )\\argptainr <> $ptainr then Clear( DOCEOT( $i ) )`
        // If CORTYP was not modified manually, redefault should give same or better result
        // (e.g. in case CORTYPList was changed meanwhile)
        if (!doceot.isModified("cortyp")) {
            doceot.setCortyp(NULLSTR);
        }
        String setval = "";
        String codtim = NULLSTR;
        String method = NULLSTR;
        String atpBus = SettleContext.getUserSession().getAtp().getBus();
        String atpCod = SettleContext.getUserSession().getAtp().getCod();
        //获取当前文档类型支持的输出渠道
        List<String> cortypList = getEnableCortypList(doceot);
        //检查一遍，可能支持的Cortyp，是否对当前处理角色(ptspta)适合
        for (int idx = 0; idx < cortypList.size(); idx++) {
            String cortyp = cortypList.get(idx);
            if (!MdaUtils.isEmpty(doceot.getValcortyp())) {
                if (Strings.searchBlock(doceot.getValcortyp(), cortyp) == 0) {
                    continue; //   ####   goto NextIdx
                }
            }
            switch (cortyp) {
                case "SWT":
                    if (!MdaUtils.isEmpty(doceot.getAdrbic()) && (MdaUtils.compareTo(doceot.getAdrbicaut(), "A") == 0 || MdaUtils.compareTo(doceot.getAdrbicaut(), "C") == 0)) {
                        setval = setval + cortyp + CR;
                    }
                    break;
                case "RTG":
                    if (!MdaUtils.isEmpty(doceot.getAdrbic())) {
                        // if not isempty ADR\\RTGFLG
                        setval = setval + cortyp + CR;
                    }
                    break;
                case "TAR":
                    if (!MdaUtils.isEmpty(doceot.getAdrbic())) {
                        // if not isempty ADR\\TARFLG
                        setval = setval + cortyp + CR;
                    }
                    break;
                case "TCO":
                    // TCO Messages for business sectors in list only
                    switch (atpBus) {
                        // case "LE", "LI", "BO", "BC", "GI", "BR"
                        case "LI":
                        case "BR":  //国内证暂时不出TCO
                            codtim = Strings.mid(atpCod, 1, 3);
                            if (MdaUtils.compareTo(codtim, "LIT") == 0 || MdaUtils.compareTo(codtim, "BRT") == 0) {
                                if (!MdaUtils.isEmpty(doceot.getAdrtid())) {
                                    setval = setval + cortyp + CR;
                                }
                            }
                            break;
                    }
                    break;
                case "DTA":
                    switch (atpBus) {
                        case "LI":
                        case "BR":
                            if (!MdaUtils.isEmpty(doceot.getAdrdtacid())) {
                                setval = setval + cortyp + CR;
                            }
                            break;
                    }
                    break;
                case "DTE":
                    switch (atpBus) {
                        case "LE":
                        case "BE":
                            if (!MdaUtils.isEmpty(doceot.getAdrdtecid())) {
                                setval = setval + cortyp + CR;
                            }
                            break;
                    }
                    break;
                case "TLX":
                    if (!MdaUtils.isEmpty(doceot.getAdrtlx()) || MdaUtils.compareTo(doceot.getAdrtlxaut(), "Y") == 0) {
                        setval = setval + cortyp + CR;
                    }
                    break;
                case "FAX":
                    if (!MdaUtils.isEmpty(doceot.getAdrfax())) {
                        setval = setval + cortyp + CR;
                    }
                    break;
                case "EML":
                case "EMA":
                    if (!MdaUtils.isEmpty(doceot.getAdreml())) {
                        setval = setval + cortyp + CR;
                    }
                    break;
                case "BOL":
                    if (!MdaUtils.isEmpty(doceot.getAdrrid())) {
                        setval = setval + cortyp + CR;
                    }
                    break;
                case "LET":
                case "INT":
                case "TXT":
                    setval = setval + cortyp + CR;
                    break;
                case "IZV":
                    setval = setval + cortyp + CR;
                    //境内外币
                    break;
                case "FMT":
                    setval = setval + cortyp + CR;
                    //电证
                    break;
                case "ELC":
                    setval = setval + cortyp + CR;
                    break;
                case "ERC":
                case "ERX":
                    setval = setval + cortyp + CR;
                    break;
                default:
                    setval = setval + cortyp + CR;
                    // CORTYP specific check to be implemented on level 6
                    /*method = MdaDriver.getModuleInfo(this,tdModuleInfoFullName) + ".CheckCORTYP" + cortyp;
                    Modules.invokeExpress(this,method,-1);
                    if( ctx.getErrorCode() == 0 ) {
                        setval = setval + cortyp + CR;
                    }*/
            }
            //    ####    label NextIdx
        }
        // if CORTYP is not allowed, ignore manual input and redefault
        if (Strings.searchBlock(setval, doceot.getCortyp()) == 0) {
            doceot.resetModified("cortyp");
            doceot.setCortyp(NULLSTR);
        }
        if (!doceot.isModified("cortyp")) {
            if (MdaUtils.isEmpty(setval)) {
                //Systems.resetEnabled(this,"cortyp");
            }
        }
        //Systems.setValues(this,"cortyp",setval);
        if (MdaUtils.isEmpty(doceot.getCortyp())) {
            if ((!MdaUtils.isEmpty(doceot.getRcv().getAdr().getCortyp())) && (Strings.searchBlock(setval, doceot.getRcv().getAdr().getCortyp()) > 0)) {
                doceot.setCortyp(doceot.getRcv().getAdr().getCortyp());
            } else {
                if (MdaUtils.isEmpty(doceot.getCortyp())) {
                    doceot.setCortyp(Strings.getLine(setval, 1));
                }
            }
        }
        // disable CORTYP if no choice available
        if (MdaUtils.isEmpty(Strings.getLine(setval, 2))) {
            //Systems.resetEnabled(this,"cortyp");
        }
        //    ####    label nodef
        setOldValues(doceot);
        //if IsModified( CORTYP ) then
        //  ResetModified( CORTYP )
        //endif
        //报文加押标志
        if ("SWT".equals(doceot.getCortyp()) && "A".equals(doceot.getAdrbicaut())) {
            doceot.setStaflg("");
        }
    }

    /**
     * source:doceot.0082.script
     */
    public boolean specialCorTypDef(DoceotVo doceot) {
        //! for special type documtents (e.g. recognized by DOCPANCORTYP, SMH\\CORTYP, APF
        if (MdaUtils.compareTo(Strings.mid(doceot.getDocstrsea(), 2, 1), "I") == 0) {
            doceot.setCortyp("INT");
            //Systems.setValues(this,"cortyp",this.getCortyp());
            //Systems.resetEnabled(this,"cortyp");
            return true;
        } else if (MdaUtils.compareTo(doceot.getCortyp(), "TCA") == 0) {
            //Systems.setValues(this,"cortyp",this.getCortyp());
            //Systems.resetEnabled(this,"cortyp");
            return true;
        }
        return false;
    }

    /**
     * source:doceot.0010.script
     */
    public void setOldValues(DoceotVo doceot) {
        Utils.setFieldValue(doceot, "oldadrblk", doceot.getAdrblk());
        Utils.setFieldValue(doceot, "oldadrbic", doceot.getAdrbic());
        Utils.setFieldValue(doceot, "oldcortyp", doceot.getCortyp());
    }

    /**
     * source:doceot.0081.script
     */
    public void setLang(DoceotVo doceot) {
        if (MdaUtils.compareTo(doceot.getCortyp(), "SWT") == 0) {
            doceot.setDocuil("EN");
        } else {
            doceot.setDocuil("CN");
        }
    }

    /**
     * source:doceot.0023.script
     */
    public void setApfFlag(TrndocVo trndocVo, DoceotVo doceot, boolean panelVisibleFlag) {
        if (MdaUtils.compareTo(doceot.getLev(), "5") == 0) {
            // first three digits of APF are fixed by creation, CORTYP cannot be changed
            setAttachmentAPF(doceot);
        } else {
            if (MdaUtils.isEmpty(doceot.getApf())) {
                doceot.setApf(doceot.getCortyp());
            }
            // for technical type of correspondence application form depends on CORTYP
            if (MdaUtils.compareTo(Strings.mid(doceot.getApf(), 1, 3), doceot.getCortyp()) != 0) {
                // if CORTYP is changed back from technical type to letter,
                if (MdaUtils.compareTo(doceot.getCortyp(), "LET") == 0) {
                    if (TECHNICAL_CORTYP.contains(Strings.mid(doceot.getApf(), 1, 3))) {
                        doceot.setApf(doceot.getOldapf());
                    }
                }
            }
            if (TECHNICAL_CORTYP.contains(doceot.getCortyp())) {
                if (Strings.len(doceot.getApf()) > 3) {
                    doceot.setApf(doceot.getCortyp() + Strings.mid(doceot.getApf(), 4, Strings.len(doceot.getApf()) - 3));
                } else {
                    doceot.setApf(doceot.getCortyp());
                }
                // DO5WLB / 001621 / #CT000100 must not be printed
                doceot.setApfcpy5(0);
                doceot.setApfcpy6(0);
                doceot.setApfcpy7(0);
            }
        }

        // check if APFCOD exists and, if not set to first existing)
        List<CodetableItem> allapfItems = codetableService.selectList("APFTXT", "CN");
        int allCodFirst = -1;
        int threeCodeFirst = -1;
        if (allapfItems != null) {
            for (int i = 0; i < allapfItems.size(); i++) {
                String apfCode = allapfItems.get(i).getValue();
                if (apfCode.startsWith(doceot.getApf())) {
                    allCodFirst = i;
                }
                if (apfCode.startsWith(Strings.mid(doceot.getApf(), 1, 3))) {
                    threeCodeFirst = i;
                }
                if (allCodFirst > -1 && threeCodeFirst > -1) {
                    break;
                }
            }
        }
        if (allCodFirst > -1 && allapfItems !=null) {
            doceot.setApf(allapfItems.get(allCodFirst).getValue());
        } else {
            doceot.setApf("");
        }


        //TODO 根据 threeCodeFirst判断生产 APF的下拉选项，这块准备写成一个借口，供前端调用
        //根据APF，查出完整的APF CODE，例如SWT 会更新为SWT001
        // APF is set. Now set types of that application form
        List<Apf> apfList = new ArrayList<>();
        if (!MdaUtils.isEmpty(doceot.getApf())) {
            apfList = apfMapper.getApfListByCode(doceot.getApf());
        }
        int nxt = 0;
        for (nxt = 1; nxt <= apfList.size(); nxt++) {
            Apf apf = apfList.get(nxt - 1);
            String typ = apf.getTyp();
            String edtflg = apf.getEdtflg();
            int cnt = apf.getCnt();
            switch (nxt) {
                case 1:
                    doceot.setApftyp1(typ);
                    if (MdaUtils.isEmpty(edtflg)) {
                        if (doceot.isModified("apfcpy1")) {
                            // reset modified and thus value for manual input but not for SetOriCount modifications
                            doceot.resetModified("apfcpy1");
                        }
                    }

                    if (!doceot.isModified("apfcpy1")) {
                        doceot.setApfcpy1(cnt);
                    }
                    break;
                case 2:
                    doceot.setApftyp2(typ);
                    if (MdaUtils.isEmpty(edtflg)) {
                        doceot.resetModified("apfcpy2");
                    }

                    if (!doceot.isModified("apfcpy2")) {
                        if (doceot.getApfcpymli() < 0) {     // only if # copies is not set by MLI
                            doceot.setApfcpy2(cnt);
                        }
                    }
                    if (MdaUtils.compareTo(doceot.getOriflg(), "C") == 0) {
                        if (!doceot.isModified("apfcpy5")) {
                            doceot.setApfcpy5(cnt);
                        }
                    }
                    break;
                case 3:
                    doceot.setApftyp3(typ);
                    if (MdaUtils.isEmpty(edtflg)) {
                        doceot.resetModified("apfcpy3");
                    }

                    if (!doceot.isModified("apfcpy3")) {
                        doceot.setApfcpy3(cnt);
                    }
                    if (MdaUtils.compareTo(doceot.getOriflg(), "C") == 0) {
                        if (!doceot.isModified("apfcpy6")) {
                            doceot.setApfcpy6(cnt);
                        }
                    }
                    break;
                case 4:
                    doceot.setApftyp4(typ);
                    if (MdaUtils.isEmpty(edtflg)) {
                        doceot.resetModified("apfcpy4");
                    }
                    if (!doceot.isModified("apfcpy4")) {
                        doceot.setApfcpy4(cnt);
                    }
                    if (MdaUtils.compareTo(doceot.getOriflg(), "C") == 0) {
                        if (!doceot.isModified("apfcpy7")) {
                            doceot.setApfcpy7(cnt);
                        }
                    }
                    break;
            }
        }
        //for Copy To and Send To means
        // APFCPY5 = APFCPY2 for original
        // APFCPY6 = APFCPY3 for original
        // APFCPY7 = APFCPY4 for original
        // # of originals=0 for technical messages
        if (TECHNICAL_CORTYP.contains(doceot.getCortyp())) {
            doceot.setApfcpy1(0);
        }
        // visible/invisibel APF-Fields
        if (nxt <= 1) {
            doceot.setApfcpy1(0);
            doceot.setApf(NULLSTR);
        }

        if (nxt <= 2) {
            doceot.setApfcpy5(0);
            doceot.setApfcpy2(0);
        }

        // Reset APFTYP und APFCPY if new form set contains less entries
        if (nxt <= 3) {
            doceot.setApfcpy3(0);
            doceot.setApftyp3(NULLSTR);
            doceot.setApfcpy6(0);
        }
        if (nxt <= 4) {
            doceot.setApfcpy4(0);
            doceot.setApftyp4(NULLSTR);
            doceot.setApfcpy7(0);
        }
        // Continue if detailspanel should be visible only
        if (!panelVisibleFlag) {
            return;
        }

        //for #CT000101 # of copies for original are taken from original
        /**
         if ORIFLG.is ( "S" ) or ORIFLG.is ( "C" ) then
         **/
        if (MdaUtils.compareTo(doceot.getCortyp(), "SWT") == 0) {
            doceot.setApflabcpycov("Cover");
            doceot.setApflabcpyori("Document");
            doceot.setKeyadd1("Sender to Rec.");
            doceot.setKeyadd2("Information");
        } else {
            /**
             KEYADD1 = 'L0000106'
             KEYADD2 = 'L0000107'
             **/
            doceot.setKeyadd1("Remark");
            doceot.setKeyadd2("");
        }
        if (MdaUtils.compareTo(getUseCORTYP(doceot), "LET") == 0 && MdaUtils.compareTo(doceot.getOriflg(), "S") == 0) {
            docEOTCopyOriAPF(trndocVo, doceot);
        }

        if (!MdaUtils.isEmpty(doceot.getSupcovflg())) {
            if (MdaUtils.compareTo(doceot.getOriflg(), "S") == 0 || MdaUtils.compareTo(doceot.getOriflg(), "C") == 0) {
                // if cover letter is suppressed, reset+disable copies
                doceot.setApfcpy1(0);
                doceot.setApfcpy2(0);
                doceot.setApfcpy3(0);
                doceot.setApfcpy4(0);
            }
        }
    }

    public void docEOTCopyOriAPF(TrndocVo trndocVo, DoceotVo doceotVo) {
        //取得上下文
        //! Copy # of copies from original to `Send To` entry
        // argument is index of `Send To` entry in DOCEOT

        String refid = doceotVo.getIdref();
        int gridcnt = trndocVo.getDoceot().size();
        for (int i = 0; i < gridcnt; i++) {
            if (MdaUtils.compareTo(trndocVo.getDoceot().get(i).getId(), refid) == 0) {
                doceotVo.setApfcpyori(trndocVo.getDoceot().get(i).getApfcpy1());
                doceotVo.setApfcpy5(trndocVo.getDoceot().get(i).getApfcpy2());
                doceotVo.setApfcpy6(trndocVo.getDoceot().get(i).getApfcpy3());
                doceotVo.setApfcpy7(trndocVo.getDoceot().get(i).getApfcpy4());
            }
        }

    }

    /**
     * source:doceot.0101.script
     */
    public void setAttachmentAPF(DoceotVo doceot) {
        //! Set APF for attachment
        switch (doceot.getAtttyp()) {
            case "SMH":
                // APF = "TCO"
                doceot.setApf("NOP");
                break;
            case "FIL":
                doceot.setApf("NOP");
                break;
            case "EOT":
                //APF = "NOP"
                doceot.setApf("TCO");
                break;
            default:
        }
    }

    /**
     * source:doceot.0012.script
     */
    public String getDocRul(String argDOCNAM, String structure, String execution) {
        // GetTemplates creates rule resp. panel names
        // in:
        //   document name (with structure byte removed)
        //   structure (2nd last Byte of rule)
        //   execution mode ( document panel or method or static function )
        // out:
        //   corresponding name (panel or method or static function)
        String pfx = Strings.mid(argDOCNAM, 1, Strings.len(argDOCNAM) - 1);
        String nbr = Strings.mid(argDOCNAM, Strings.len(argDOCNAM), 1);
        switch (execution) {
            case "P":  // Panel
                return pfx + structure + nbr;
            case "R":  // Method
                // to construct method name, search for last occurence of backslash or dot
                for (int idx = Strings.len(pfx); idx >= 2; idx --) {
                    if (MdaUtils.compareTo(Strings.mid(pfx, idx, 1), "\\") == 0) {
                        // backslash found, replace by dot and return as method name
                        return Strings.mid(pfx, 1, idx - 1) + "." + Strings.mid(pfx, idx + 1, Strings.len(pfx) - idx) + structure + nbr;
                    } else {
                        // dot found
                        if (MdaUtils.compareTo(Strings.mid(pfx, idx, 1), ".") == 0) {
                            return pfx + structure + nbr;
                        }
                    }
                }
                if (MdaUtils.compareTo(Strings.mid(pfx, 1, 1), "\\") == 0) {
                    return "\\." + Strings.mid(pfx, 2) + structure + nbr;
                } else {
                    return "\\." + pfx + structure + nbr;
                }
                // break;
            case "S":   // static text function
                // to extract function name, search for last occurence of backslash
                for (int idx = Strings.len(pfx); idx >= 1; idx --) {
                    if (MdaUtils.compareTo(Strings.mid(pfx, idx, 1), "\\") == 0) {
                        // backslash found, function name follows backslash
                        return Strings.mid(pfx, idx + 1, Strings.len(pfx) - idx) + structure + nbr;
                    }
                }
                return pfx + structure + nbr;
            default:
                String error = Strings.formatText("Illegal Execution Flag \'$1\'", execution);
                throw new CommonServiceException(error);
        }
    }

    /**
     * source:doceot.0092.script
     */
    public void setPanDsc(DoceotVo doceot) {
        // construct pandsc for current DOCEOT
        // to be used for copies only (LEV=2)
        if (MdaUtils.compareTo(doceot.getLev(), "2") == 0) {
            if (MdaUtils.compareTo(doceot.getOriflg(), "C") == 0) {
                doceot.setPandsc("cc: ");
            } else {
                if (MdaUtils.compareTo(doceot.getOriflg(), "S") == 0) {
                    doceot.setPandsc("send to: ");
                } else {
                    doceot.setPandsc("??: ");
                }
            }
            if (MdaUtils.compareTo(doceot.getRoladr(), "OTH") == 0) {
                doceot.setPandsc(doceot.getPandsc() + getSNDKEY(doceot));
            } else {
                doceot.setPandsc(doceot.getPandsc() + codetableService.getTblLabel(doceot.getRoladr(), "ROLALL") + ", " + getSNDKEY(doceot));
            }
        }
    }

    @Override
    public boolean isCORTYPTechnical(String cortyp) {
        return TECHNICAL_CORTYP.contains(cortyp);
    }

    /**
     * source:doceot.0078.script
     * 最大长度50
     */
    public String getSNDKEY(DoceotVo doceot) {
        // gets SNDKEY (for SMH and PANDSC of copies)
        String sndkey = "";
        switch (doceot.getCortyp()) {
            case "SWT":
            case "RTG":
            case "TAR":
            case "IZV":
                sndkey = doceot.getAdrbic();
                break;
            case "EML":
            case "EMA":
                sndkey = doceot.getAdreml();
                break;
            case "TLX":
                sndkey = doceot.getAdrtlx();
                break;
            case "FAX":
                sndkey = doceot.getAdrfax();
                break;
            case "TCO":
                sndkey = doceot.getAdrtid();
                break;
            case "DTA":
                sndkey = doceot.getAdrdtacid();
                break;
            case "DTE":
                sndkey = doceot.getAdrdtecid();
                break;
            case "BOL":
                sndkey = doceot.getAdrrid();
                break;
            case "LET":
                sndkey = adrLine(doceot);
                break;// may be another field, but now it works proper with BIC
            default:
                break;
        }
        if (sndkey.length() > 50) {
            sndkey = sndkey.substring(0, 50);
        }
        return sndkey;
    }

    /**
     * source:doceot.0007.script
     */
    public String adrLine(DoceotVo doceot) {
        String res = "";
        String dlm = "";
        IStream adrStm = new StreamImpl();
        String lin = NULLSTR;
        if (MdaUtils.isEmpty(doceot.getRcv().getAdr().getInr())) {
            Streams.streamSet(adrStm, doceot.getAdrblk());
            int cnt = Streams.streamCount(adrStm);
            for (int i = 1; i <= cnt; i++) {
                lin = Strings.getLine(adrStm, i);
                if (!MdaUtils.isEmpty(lin)) {
                    res = res + dlm + lin;
                    dlm = ", ";
                }
            }
        } else {
            res = doceot.getRcv().getAdr().getNam1() + ", " + doceot.getRcv().getAdr().getLoczip() + " " + doceot.getRcv().getAdr().getLoctxt();
        }
        return res;
    }

    /**
     * source:doceot.0001.script
     */
    public Smh savdoc(DoceotVo doceotVo, TrndocVo trndocVo) {
        //! save document for this DOCEOT
        // store execution language
        if (MdaUtils.compareTo(doceotVo.getDelflg(), "D") == 0 || MdaUtils.isEmpty(doceotVo.getId())) {
            return null;
        }
        Smh argSMH = new Smh();
        Object rec = transactionHelpService.getTransactionStoreSet().getRec();
        String objtyp = "";
        String objinr = "";
        if (rec != null) {
            objtyp = Utils.recGetObj(rec);
            objinr = Utils.recGetInr(rec);
        }
        argSMH.setObjtyp(objtyp);
        argSMH.setObjinr(objinr);
        Trn trn = transactionHelpService.getTransactionStoreSet().getTrnmodVo().getTrn();
        if (trn == null) {
            SettleExceptionUtils.sysDump("Cannot get \\TRNMOD\\TRN\\INR");
        }
        Assert.notNull(trn);
        argSMH.setTrnsub(trn.getSmhnxt());
        argSMH.setCortyp(doceotVo.getCortyp());
        argSMH.setApfcnt(doceotVo.getApfcnt());
        if (MdaUtils.isEmpty(doceotVo.getPtainr())) {
            argSMH.setPtainr(doceotVo.getRcv().getPta().getInr());
        } else {
            argSMH.setPtainr(doceotVo.getPtainr());
        }
        argSMH.setTrntyp("TRN");
        argSMH.setTrninr(trn.getInr());
        argSMH.setNam(doceotVo.getRole() + " " + doceotVo.getPandsc());
        argSMH.setExtkey(trn.getInr() + ":" + doceotVo.getPandsc());
        argSMH.setDir(">");
        // DOCNAM is INR
        argSMH.setCreusr(SettleContext.getUserSession().getUsr().getExtkey());
        argSMH.setCredattim(Dates.now());
        argSMH.setCrefrm(SettleContext.getTransName());
        argSMH.setSndkey(getSNDKEY(doceotVo));
        argSMH.setApf(doceotVo.getApf());
        argSMH.setApfcnt(getAPFCNT(doceotVo));
        argSMH.setOriflg(doceotVo.getOriflg());
        //加押标志
        argSMH.setStaflg(doceotVo.getStaflg());
        /**
         //普通的报文 FOR Casmf MOD ADD BY WCX
         if CORTYP == "SWT" and argSMH\\MSGTYP <> "103" and argSMH\\MSGTYP <> "202" then
         argSMH\\SWTNUM = Trim( GetContent( "\\\\TRNMOD\\\\TRNDOC\\\\SWTNUM" ) )
         endif
         **/
        // set additional fields if this exists
       /* String rulename = MdaDriver.getModuleInfo(this,tdModuleInfoFullName) + ".StoreAdditionalSMHFields ( " + Platform.recGetPath(argSMH) + ")";
        Modules.invokeExpress(this,rulename,-1);
        String sMHUpdateRule = NULLSTR;
        if( ctx.getErrorCode() <= 0 ) {
            sMHUpdateRule = rulename;
        } else {
            sMHUpdateRule = "";
        }*/
        String docfdr = NULLSTR;
        String docpth = NULLSTR;
        String docfil = NULLSTR;
        String docfxt = NULLSTR;
        String tmpfdr = NULLSTR;
        done:
        while (true) {
            if (MdaUtils.compareTo(doceotVo.getLev(), "5") == 0) {
                // attachment
                // set group leader and sequence number
                argSMH.setGrpinr(trndocService.docEOTGetORISMHINR(trndocVo.getDoceot(), doceotVo.getIdatt()));
                argSMH.setGrpseq(doceotVo.getGrpseq());
                switch (doceotVo.getAtttyp()) {
                    case "SMH":
                        argSMH.setOrismhinr(doceotVo.getAttinr());
                        argSMH.setOriflg("A");
                        if (MdaUtils.isEmpty(argSMH.getOrismhinr())) {
                            SettleExceptionUtils.sysDump("ORISMH for attachment not set!");
                        }
                        /**
                         // retrieve CORTYP of original message
                         DBExecuteSQLVar( "SELECT CORTYP FROM SMH WHERE INR = ?", argSMH\\ORISMHINR )
                         StreamClear( $ORICORTYPSTM )
                         DBFetchStream( $ORICORTYPSTM )
                         argSMH\\CORTYP = StreamGetLine( $ORICORTYPSTM, 1 )
                         **/
                        //取在message页面显示的cortyp，否则在trnrel界面显示的是连个swt，上面的代码做如下修改。
                        if (MdaUtils.isEmpty(argSMH.getCortyp())) {
                            // retrieve CORTYP of original message
                            Smh orgSmh = new Smh();
                            orgSmh.setInr(argSMH.getOrismhinr());
                            orgSmh = smhMapper.selectByPrimaryKey(orgSmh);
                            if (orgSmh != null) {
                                argSMH.setCortyp(orgSmh.getCortyp());
                            }
                        }
                        if (MdaUtils.isEmpty(argSMH.getCortyp())) {
                            SettleExceptionUtils.sysDump("Cannot determine CORTYP from ORISMH for attachment!");
                        }
                        argSMH.setInr(counterService.dbCounterFormat("SMH"));
                        smhMapper.insert(argSMH);
                        doceotVo.setSmhinr(argSMH.getInr());
                        // return ; //    goto done
                        break done;
                    case "FIL":
                        argSMH.setCortyp("FIL");
                        argSMH.setInr(counterService.dbCounterFormat("SMH"));
                        // create copy of file in data/docs + SMH
                        docfdr = appEnv.addNodeToPath(getdoclib(), doceotVo.getAttinr());
                        // separate path and extension
                        Argument<String> docpthBox = new Argument<String>();
                        Argument<String> docfilBox = new Argument<String>();
                        Argument<String> docfxtBox = new Argument<String>();
                        docimmService.splitFileName(docfdr, docpthBox, docfilBox, docfxtBox);

                        docpth = docpthBox.value;
                        docfil = docfilBox.value;
                        docfxt = docfxtBox.value;

                        argSMH.setDocpth(docpth);
                        argSMH.setDocfil(argSMH.getInr()); // create unique filename
                        argSMH.setDocfxt(docfxt);
                        docfdr = docimmService.getDocumentFdr(argSMH);
                        tmpfdr = appEnv.getFullName("tmp", doceotVo.getAttinr());
                        Files.fileCopy(tmpfdr, docfdr);
                        argSMH.setOriflg("F");
                        smhMapper.insert(argSMH);
                        doceotVo.setSmhinr(argSMH.getInr());
                        break done; //    goto done
                    case "INT":
                        // document from this transaction just created or still to be created
                        argSMH.setOrismhinr(trndocService.docEOTGetORISMHINR(trndocVo.getDoceot(), doceotVo.getIdref()));
                        doceotVo.setAttinr(argSMH.getOrismhinr());
                        argSMH.setOriflg("A");
                        argSMH.setCortyp(docEOTGetField(trndocVo.getDoceot(), doceotVo.getIdref(), "CORTYP"));
                        if (MdaUtils.isEmpty(argSMH.getCortyp())) {
                            SettleExceptionUtils.sysDump(Strings.formatText("Cannot determine CORTYP from $1 for attachment!", doceotVo.getIdref()));
                        }
                        argSMH.setInr(counterService.dbCounterFormat("SMH"));
                        smhMapper.insert(argSMH);
                        doceotVo.setSmhinr(argSMH.getInr());
                        break done; //    goto done
                    default:
                        // attachment is a document that has to be created now
                        // SMH\\CORTYP is set to the CORTYP of the content
                        // attachments property is carried via GRPINR/GRPSEQ
                        String corTyp = null == doceotVo.getApf() ? "" : doceotVo.getApf().substring(0, 3);
                        if (isCORTYPTechnical(corTyp)) {
                            argSMH.setCortyp(corTyp);
                        } else {
                            argSMH.setCortyp("LET");
                        }
                        argSMH.setOriflg("D");
                }
            } else {
                if ("C".equals(doceotVo.getOriflg())
                        || "S".equals(doceotVo.getOriflg())) {
                    argSMH.setOrismhinr(trndocService.docEOTGetORISMHINR(trndocVo.getDoceot(), doceotVo.getIdref()));
                }
            }
            argSMH.setInr(counterService.dbCounterFormat("SMH"));
            smhMapper.insert(argSMH);
            doceotVo.setSmhinr(argSMH.getInr());
            if (doceotVo.getGrpseq() > 0 && !(MdaUtils.compareTo(doceotVo.getLev(), "5") == 0)) {
                // document has attachments
                argSMH.setGrpseq(0);
                argSMH.setGrpinr(argSMH.getInr());
            }
            argSMH.setDocfil(argSMH.getInr());
            argSMH.setDocpth(getdoclib());
            prepareDocument(doceotVo, trndocVo);
            argSMH.setApf(doceotVo.getApf());
            argSMH.setApfcnt(getAPFCNT(doceotVo)); // if APF is modified in SetAPF under PrepareDocument (because CORTYP was modified?)
            TextResultVo textResultVo = trndocService.outputMessage(doceotVo);

            if (textResultVo == null) {
                log.error("生成面函报文文件role:{},docNam:{},corTyp:{}报错", doceotVo.getRole(), doceotVo.getDocnam(), doceotVo.getCortyp());
                throw new CommonServiceException("生成面函报文文件发生错误");
            }
            //设置文件后缀名
            argSMH.setDocfxt(textResultVo.getExtension());
            docfdr = docimmService.getDocumentFdr(argSMH);
            List<Smh> splitSmh = new ArrayList<>();
            Object formatData = textResultVo.getFormatData();
            try {
                if ("SWT".equalsIgnoreCase(doceotVo.getCortyp()) && formatData instanceof List) {
                    ObjectMapper objectMapper = new ObjectMapper();

                    //存储分片部分的记录与报文
                    if (((List) formatData).size() > 1) {
                        log.info("产生切片报文");
                        List swfMessageList = (List) formatData;
                        StringJoiner sj = new StringJoiner(",");
                        for (int i = 0; i < swfMessageList.size(); i++) {
                            Object swfMessageObj = swfMessageList.get(i);
                            String mt = Utils.getFieldValue(swfMessageObj, "mt", "");
                            String msg = Utils.getFieldValue(swfMessageObj, "message", "");
                            log.info("保存报文{}:{}", mt, msg);
                            Smh subSmh = MdaUtils.deepClone(argSMH);
                            subSmh.setInr(counterService.dbCounterFormat("SMH"));
                            subSmh.setGrpseq(i + 1);
                            subSmh.setGrpinr(argSMH.getInr());
                            subSmh.setDocfil(subSmh.getInr());
                            subSmh.setMsgtyp(mt);
                            subSmh.setNam(argSMH.getNam()+" "+ (i+1) +"/"+swfMessageList.size());
                            smhMapper.insert(subSmh);
                            splitSmh.add(subSmh);
                            String filPath = appEnv.getSubDataPath(Utils.replacePath(subSmh.getDocpth()), subSmh.getDocfil() + "." + subSmh.getDocfxt());
                            InputStream ins = new ByteArrayInputStream(msg.getBytes());
                            boolean bool = objectStroeToolService.saveObjectFileByStream(ins, filPath);
                            if (!bool) {
                                throw new CommonServiceException("文件存储失败!");
                            }

                            // 存储分片报文格式化JSON
                            String subJsonStr = objectMapper.writeValueAsString(Collections.singletonList(swfMessageObj));
                            String subfilePath = appEnv.getSubDataPath(Utils.replacePath(subSmh.getDocpth()), subSmh.getDocfil() + ".json");
                            objectStroeToolService.saveObjectFileByStream(new ByteArrayInputStream(subJsonStr.getBytes()), subfilePath);

                            sj.add(subSmh.getInr());
                        }
                        doceotVo.setSmhinr(sj.toString());
                    } else if (((List) formatData).size() == 1) {
                        // 存储报文格式化JSON
                        String jsonStr = objectMapper.writeValueAsString(formatData);
                        String filePath = appEnv.getSubDataPath(Utils.replacePath(argSMH.getDocpth()), argSMH.getDocfil() + ".json");
                        objectStroeToolService.saveObjectFileByStream(new ByteArrayInputStream(jsonStr.getBytes()), filePath);
                    }
                }

                byte[] binary = textResultVo.getSourceBinary();
                if (binary != null) {
                    //FileUtils.writeByteArrayToFile(new File(docfdr), binary);
                    //对象存储存储面函文件
                    String filPath = appEnv.getSubDataPath(Utils.replacePath(argSMH.getDocpth()), argSMH.getDocfil() + "." + argSMH.getDocfxt());
                    InputStream ins = new ByteArrayInputStream(binary);
                    boolean bool = objectStroeToolService.saveObjectFileByStream(ins, filPath);
                    if (!bool) {
                        throw new CommonServiceException("文件存储失败!");
                    }
                    if (textResultVo.getSourceContent() != null && textResultVo.getSourceExtension() != null) {
                        //源内容被设置了，存放一个同名文件
                        String sourceFilPath = appEnv.getSubDataPath(Utils.replacePath(argSMH.getDocpth()), argSMH.getDocfil() + "." + textResultVo.getSourceExtension());
                        InputStream insOfContent = new ByteArrayInputStream(textResultVo.getSourceContent());
                        boolean boolOfContent = objectStroeToolService.saveObjectFileByStream(insOfContent, sourceFilPath);
                        if (!boolOfContent) {
                            throw new CommonServiceException("源文件存储失败!");
                        }
                        log.info("保存源文件成功filepath:{}", sourceFilPath);
                    }
                    log.info("生成对象存储面函成功filepath:{}", filPath);
                }

            } catch (Exception e) {
                log.error("存储面函报文文件发生错误", e);
                throw new CommonServiceException("存储面函报文文件发生错误");
            }
            /**
             if GetFramename == "CPTOPN" then
             **/
            String transName = SettleContext.getDirectTransName();
            if (MdaUtils.compareTo(transName, "CPTOPN") == 0
                    || MdaUtils.compareTo(transName, "CPTECO") == 0) {
                String swftyp = Utils.getFieldValue(trndocVo.getRec(), "swftyp");
                if (MdaUtils.compareTo(swftyp, "202") == 0) {
                    argSMH.setMsgtyp("202");
                } else {
                    argSMH.setMsgtyp(doceotVo.getMt());
                }
            } else {
                if (MdaUtils.compareTo(argSMH.getCortyp(), "ELC") == 0) {
                    argSMH.setMsgtyp(doceotVo.getPandsc());
                } else {
                    argSMH.setMsgtyp(doceotVo.getMt());
                }
            }
            //argSMH\\MSGTYP = MT
            /**
             if IsEmpty( STAFLG ) and not IsEmpty( MT ) then
             **/
            IStream mtlist = new StreamImpl();
            String mtblk = NULLSTR;
            int line = 0;
            if (MdaUtils.compareTo(doceotVo.getCortyp(), "SWT") == 0
                    && !MdaUtils.isEmpty(doceotVo.getMt())) {
                // SWIFT改造部分报文直接发报
                Streams.streamClear(mtlist);
                //国结系统所有交易下的MT799发报实现直通
                mtblk = Inis.getIniBlock("tdtrans.ini", "ALL", "MESSAGE");
                Streams.streamSet(mtlist, mtblk);
                line = Streams.streamSearch(mtlist, doceotVo.getMt());
                if (line > 0) {
                    argSMH.setStaflg("E");
                    splitSmh.forEach(smh -> smh.setStaflg("E"));
                } else {
                    mtblk = Inis.getIniBlock("tdtrans.ini", transName, "MESSAGE");
                    Streams.streamSet(mtlist, mtblk);
                    line = Streams.streamSearch(mtlist, doceotVo.getMt());
                    if (line > 0) {
                        argSMH.setStaflg("E");
                        splitSmh.forEach(smh -> smh.setStaflg("E"));
                    }
                }
            }
            //人民币跨境结算   根据MSGTYP的值判断存WFE表的内容
            String typ = NULLSTR;
            if (MdaUtils.compareTo(transName, "BRTSET") == 0
                    || MdaUtils.compareTo(transName, "BCTSET") == 0
                    || MdaUtils.compareTo(transName, "GITSET") == 0
                    || MdaUtils.compareTo(transName, "GITPSE") == 0
                    || MdaUtils.compareTo(transName, "NITSET") == 0
                    || MdaUtils.compareTo(transName, "NITPSE") == 0
                    || MdaUtils.compareTo(transName, "DFTSET") == 0
                    || MdaUtils.compareTo(transName, "DFTMSG") == 0) {
                typ = trndocVo.getRec().getSwftyp();
                if (MdaUtils.compareTo(typ, "CMT") == 0
                        && MdaUtils.compareTo(Strings.mid(doceotVo.getId(), 1, 6), "TRNCMT") == 0) {
                    argSMH.setMsgtyp("CMT");
                } else {
                    if (MdaUtils.compareTo(typ, "HVQ") == 0
                            && MdaUtils.compareTo(Strings.mid(doceotVo.getId(), 1, 6), "TRNHVQ") == 0) {
                        argSMH.setMsgtyp("HVQ");
                    } else {
                        if (MdaUtils.compareTo(typ, "CIV") == 0
                                && MdaUtils.compareTo(Strings.mid(doceotVo.getId(), 1, 6), "TRNPAY") == 0) {
                            argSMH.setMsgtyp("CIV");
                        }
                    }
                }
            }
            /**
             if $framename == "CPTOPN" then
             **/
            if (MdaUtils.compareTo(transName, "CPTOPN") == 0
                    || MdaUtils.compareTo(transName, "CPTECO") == 0) {
                typ = trndocVo.getRec().getSwftyp();
                if (MdaUtils.compareTo(typ, "CMT") == 0
                        && MdaUtils.compareTo(Strings.mid(doceotVo.getId(), 1, 6), "TRNCMT") == 0) {
                    argSMH.setMsgtyp("CMT");
                } else {
                    if (MdaUtils.compareTo(typ, "HVP") == 0
                            && MdaUtils.compareTo(Strings.mid(doceotVo.getId(), 1, 6), "TRNHVP") == 0) {
                        argSMH.setMsgtyp("HVP");
                    } else {
                        if (MdaUtils.compareTo(typ, "HVQ") == 0
                                && MdaUtils.compareTo(Strings.mid(doceotVo.getId(), 1, 6), "TRNHVQ") == 0) {
                            argSMH.setMsgtyp("HVQ");
                        } else {
                            if (MdaUtils.compareTo(typ, "CIU") == 0
                                    && MdaUtils.compareTo(Strings.mid(doceotVo.getId(), 1, 6), "TRNPAY") == 0) {
                                argSMH.setMsgtyp("CIU");
                            } else {
                                if (MdaUtils.compareTo(typ, "CIV") == 0
                                        && MdaUtils.compareTo(Strings.mid(doceotVo.getId(), 1, 6), "TRNPAY") == 0) {
                                    argSMH.setMsgtyp("CIV");
                                }
                            }
                        }
                    }
                }
            }
            smhMapper.updateByPrimaryKeySelective(argSMH);
            splitSmh.forEach(smh -> smhMapper.updateByPrimaryKey(smh));
            break done;
        }

        if (!sysmodService.isSdhBusiness()) {
            //通过Cortyp和Msgtyp确定wfmAdd的method方法
            String msgtyp = argSMH.getMsgtyp();
            if ("ERX".equalsIgnoreCase(argSMH.getCortyp())) {
                if (MdaUtils.compareTo(Strings.mid(argSMH.getMsgtyp(), 1, 1), "T") == 0
                        && Strings.len(argSMH.getMsgtyp()) > 3) {
                    msgtyp = "YPTGNZ";
                } else {
                    msgtyp = "ERX";
                }
            }
            String wfm = CorTypeWfmEnum.getWfmByCorTypeAndMsgType(argSMH.getCortyp(), msgtyp);
            try {
                Method method = trnismService.getClass().getDeclaredMethod(wfm, String.class);
                if (method != null) {
                    method.invoke(trnismService, argSMH.getCortypsub());
                }
            } catch (NoSuchMethodException e) {
                log.warn("没有找到对于的wfm方法, CorType:" + argSMH.getCortyp() + " MsgType:" + argSMH.getMsgtyp());
            } catch (InvocationTargetException e) {
                log.warn("执行方法{" + wfm + "}报错" , e);
            } catch (IllegalAccessException e) {
                log.warn("执行方法{" + wfm + "}报错" , e);
            }
        }
        return argSMH;
    }

    /**
     * source:doceot.0025.script
     */
    public String getAPFCNT(DoceotVo doceotVo) {
        // Convert list of APFTYP and # of copyies into one string for SMH record
        String ret = Strings.mid(doceotVo.getApftyp1(), 1, 3) + MdaUtils.toString(doceotVo.getApfcpy1(), -2);
        ret = ret + Strings.mid(doceotVo.getApftyp2(), 1, 3) + MdaUtils.toString(doceotVo.getApfcpy2(), -2);
        ret = ret + Strings.mid(doceotVo.getApftyp3(), 1, 3) + MdaUtils.toString(doceotVo.getApfcpy3(), -2);
        ret = ret + Strings.mid(doceotVo.getApftyp4(), 1, 3) + MdaUtils.toString(doceotVo.getApfcpy4(), -2);
        // No of copies for original
        ret = ret + Strings.mid(doceotVo.getApftyp2(), 1, 3) + MdaUtils.toString(doceotVo.getApfcpy5(), -2);
        ret = ret + Strings.mid(doceotVo.getApftyp3(), 1, 3) + MdaUtils.toString(doceotVo.getApfcpy6(), -2);
        ret = ret + Strings.mid(doceotVo.getApftyp4(), 1, 3) + MdaUtils.toString(doceotVo.getApfcpy7(), -2);
        return ret;

    }

    /**
     * source:doceot.0002.script
     */
    public String getdoclib() {
        return "DOCS\\" + MdaUtils.toString(Dates.getYear(Dates.today()), -4) + MdaUtils.toString(Dates.getMonth(Dates.today()), -2);
    }

    /**
     * source:trndoc.0042.script
     */
    public String docEOTGetField(List<DoceotVo> doceots, String refid, String fieldName) {
        if (doceots != null) {
            Optional<DoceotVo> doceotOption = doceots.stream().filter(doceot -> refid.equals(doceot.getId())).findFirst();
            if (doceotOption != null) {
                DoceotVo doceotVo = doceotOption.get();
                return Utils.getFieldValue(doceotVo, fieldName);
            }
        }
        return "";
    }

    /**
     * source:doceot.0020.script
     */
    public void prepareDocument(DoceotVo doceotVo, TrndocVo trndocVo) {
        //! Tasks that a required before creation of a document
        //Clear( KEYAMT ) # used to be set by SetCurrentKeyAmount, now by SetKeyAmount
        //Clear( KEYCUR ) # used to be set by SetCurrentKeyAmount, now by SetKeyAmount
        //Clear( KEYTXT ) # used to be set by SetCurrentKeyText, now by SetKeyAmount
        setAddressingInfo(doceotVo, trndocVo.getPtsptas());
        setApfFlag(trndocVo, doceotVo, true);
        /*trndocVo.setMsginvflg(NULLSTR);
        trndocVo.setMsginvtxt(NULLSTR);
        //! make current DOCEOT available in DOCCUR
        trndocVo.setDoccur(doceotVo);
        //do5lbw.102472 registeraddtxt may use data from contract save event (i.e. reference number)
        int cnt = 0;
        if(!MdaUtils.isEmpty(doceotVo.getId())) {
            if(!doceotVo.isModified("addtxt") && ! doceotVo.isModified("addstr") ) {
                ctx.absGet(Trnmod.class).getTrndoc().setAddtxt(NULLSTR);
                cnt = Platform.postAllFittingMethods(ctx.getRoot(),"REGISTERADDTXT",MdaDriver.getModuleInfo(ctx.absGet(Trnmod.class).getTrndoc().getDoccur(),tdModuleInfoFullName),true,-1);
                ctx.absGet(Trnmod.class).getTrndoc().getDoccur().setAddtxt( ctx.absGet(Trnmod.class).getTrndoc().getAddtxt());
                if( MdaUtils.compareTo(this.getCortyp(),"SWT") == 0 )
                {
                    ctx.absGet(Trnmod.class).getTrndoc().getDoccur().setAddstr( ctx.absGet(Trnmod.class).getTrndoc().getAddtxt());
                }
                Datas.setModuleContent(this,ctx.absGet(Trnmod.class).getTrndoc().getDoccur());
            }
        }*/
        trndocVo.setDoccuroricortyp(doceotVo.getCortyp());
        doceotVo.setCortyp(getUseCORTYP(doceotVo));
        String etaExtkey = SettleContext.getUserSession().getUsr().getEtaextkey();
        Eta eta = etaMapper.getEtaByExtkey(etaExtkey);
        if (eta != null) {
            trndocVo.setOwnrid(eta.getBolrid());
        }
    }

    /**
     * source:doceot.0096.script
     */
    public String getUseCORTYP(DoceotVo doceotVo) {
        //! determine which CORTYP is to be used for current DOCEOT row
        // this rule is used in DetermineConversion and savdoc/showdoc to determine the `templates` to use
        // examples:
        // 1. if FAX and /or EML is done by sending .pdf images from Letters
        //    if CORTYP = "FAX" or CORTYP = "EML" then = "LET"
        // 2. if FAX and /or EML is done by sending an ASCII text
        //    if CORTYP = "FAX" or CORTYP = "EML" then = "TLX"
        if (MdaUtils.compareTo(doceotVo.getLev(), "5") == 0) {
            // for attachments the format to be used for generation/display must be determined from APF
            String corTyp = doceotVo.getApf().substring(0, 3);
            if (isCORTYPTechnical(corTyp)) {
                return corTyp;
            } else {
                return "LET";
            }
        } else {
            if (MdaUtils.compareTo(doceotVo.getCortyp(), "FAX") == 0
                    || MdaUtils.compareTo(doceotVo.getCortyp(), "EML") == 0) {
                return "TLX";
            } else {
                return doceotVo.getCortyp();
            }
        }
    }

    public void setDocSendFormat(DoceotVo doceotVo) {

        switch (doceotVo.getCortyp()) {
            case "LET":
                if (MdaUtils.compareTo(Strings.mid(doceotVo.getApf(), 1, 3), "GUA") == 0 || MdaUtils.compareTo(Strings.mid(doceotVo.getApf(), 1, 3), "REV") == 0) {
                    doceotVo.setDocsnf("");
                } else {
                    if (!doceotVo.isModified("docsnf")) {
                        Argument<String> pathBox = new Argument<String>("", doceotVo.getDocsnf());
                        getDocsnf(doceotVo.getRole(), doceotVo.getDocnam(), pathBox);

                        doceotVo.setDocsnf(pathBox.value);

                    }
                    if (MdaUtils.isEmpty(doceotVo.getDocsnf())) {
                        doceotVo.setDocsnf(doceotVo.getCortyp());
                    }
                }
                break;
            case "SWT":
                if (MdaUtils.compareTo(doceotVo.getAdrbicaut(), "A") != 0) {
                    doceotVo.setDocsnf("SWT999");
                } else {
                    doceotVo.setDocsnf("");
                }
                //##Add by byte for ERS Load##############
                break;
            case "ERX":
            case "ERC":
                doceotVo.setDocsnf(doceotVo.getCortyp());
                //#################################
                break;
            default:
                doceotVo.setDocsnf("");
        }
    }

    public void getDocsnf(String rol, String nam, Argument<String> doc) {
        doc.value = "";
        String name = SettleContext.getTransName();
        switch (name) {
            case "LITOPN":
            case "LITOPN1":
                //---信开信用证格式
                if (MdaUtils.compareTo(nam, "LITBEN1") == 0) {
                    doc.value = "LETCOU";
                }
                break;
            case "LITAME":
            case "LITAME1":
                //---信开信用证修改格式
                if (MdaUtils.compareTo(nam, "LITADV1") == 0) {
                    doc.value = "LETCOU";
                }
                break;
            case "GETCRQ":
                //---出口保函项下索赔通知
                if (MdaUtils.compareTo(nam, "GITAPL1") == 0) {
                    doc.value = "LETCOU";
                }
                break;
            case "BETSND":
                //---出口信用证寄单面函\\信索面函
                if (MdaUtils.compareTo(nam, "BETAPL1") == 0 || MdaUtils.compareTo(nam, "BETAPL2") == 0 || MdaUtils.compareTo(nam, "BETPRB4") == 0 || MdaUtils.compareTo(nam, "RMBCLM\\LETCLMR") == 0) {
                    doc.value = "LETCOU";
                }
                break;
            case "BETRCL":
            case "BTTRCL":
                //---信索面函
                if (MdaUtils.compareTo(nam, "RMBCLM\\LETCLMR") == 0) {
                    doc.value = "LETCOU";
                }
                break;
            case "BTTDCR":
                //---转让信用证项下拒付通知
                if (MdaUtils.compareTo(nam, "BTTBE11") == 0 || MdaUtils.compareTo(nam, "BTTBE21") == 0) {
                    doc.value = "LETCOU";
                }
                break;
            case "BTTSND":
                //---转让信用证寄单面函\\信索面函
                if (MdaUtils.compareTo(nam, "BTTPAY1") == 0 || MdaUtils.compareTo(nam, "BTTPAY2") == 0 || MdaUtils.compareTo(nam, "RMBCLM\\LETCLMR") == 0) {
                    doc.value = "LETCOU";
                }
                break;
            case "BOTDAV":
            case "BOTDAV1":
                //---出口托收寄单面函
                if (MdaUtils.compareTo(nam, "BOTCOL1") == 0) {
                    doc.value = "LETCOU";
                }
                break;
            case "BOTRAD":
                //---出口托收寄单面函
                if (MdaUtils.compareTo(nam, "BOTCOL1") == 0 || MdaUtils.compareTo(nam, "BOTCOL2") == 0) {
                    doc.value = "LETCOU";
                }
                break;
            case "CCTDAV":
                //---光票托收面函
                if (MdaUtils.compareTo(nam, "CCTDAV1") == 0) {
                    doc.value = "LETCOU";
                }
                break;
            case "CLTDAV":
                //---光票托收面函
                if (MdaUtils.compareTo(nam, "CLTDAV1") == 0) {
                    doc.value = "LETCOU";
                }
                break;
            case "DITOPN":
                //---信开信用证格式
                if (MdaUtils.compareTo(nam, "\\LITBEN1") == 0) {
                    doc.value = "LETCOU";
                }
                break;
            case "DITAME":
                //---信开信用证修改格式
                if (MdaUtils.compareTo(nam, "LITADV1") == 0) {
                    doc.value = "LETCOU";
                }
                break;
        }

    }

    /**
     * source:doceot.0126.script
     */
    public void xmlPrintClass_TRX(Map<String, List<String[]>> dataMap, DoceotVo doceotVo) {
        String snf;
        if (MdaUtils.compareTo(doceotVo.getDocsnf(), "LET") == 0) {
            snf = "";
        } else {
            snf = codetableService.getTblLabel(doceotVo.getDocsnf(), "DOCSNF", doceotVo.getDocuil());
        }
        DocUtils.putData(dataMap, "snf", snf);
    }

    /**
     * source:doceot.0085.script
     */
    public void printAddressBlock(Map<String, List<String[]>> dataMap, DoceotVo doceotVo) {
        if (trndocService.getCurrentCORLineLength(doceotVo) == -2) {
            // skip adress for SWIFT
            return;
        }
//        if( trndocService.getCurrentCORLineLength(doceotVo) == -1 )
//        {
        // for letter only
            /*
             print vertical ( 40, tdUnitmm, tdPosAbsolute )
             */
//        }
//        else
        if (trndocService.getCurrentCORLineLength(doceotVo) != -1) {
            // for telex
            DocUtils.putData(dataMap, "receiver", "Receiver of message:");
        }
        String blk;
        String adrFmtKey;
        String zipTown;
        String locCty;
        IStream adrStm = new StreamImpl();
        int cnt;
        String lin;
        if (doceotVo.getRcv().getAdr() != null && StringUtils.isNotEmpty(doceotVo.getRcv().getAdr().getInr())) {
            adrFmtKey = getAdrFormat(doceotVo, SettleContext.getOwnPts().getAdr().getLoccty());
            if (MdaUtils.isEmpty(adrFmtKey)) {
                // use default format
                // connect zip code and town 1st to start always at a new line, also if zip code is empty
                zipTown = trndocService.xmlGetTxtSepTxt(doceotVo.getRcv().getAdr().getLoczip(), " ", doceotVo.getRcv().getAdr().getLoctxt());
                // Do not display country, if dispatch is domestic
                locCty = "";
                if (MdaUtils.compareTo(doceotVo.getRcv().getAdr().getLoccty(), SettleContext.getOwnPts().getAdr().getLoccty()) != 0) {
                    // Output of the country in entity language
                    locCty = codetableService.getTblLabel(doceotVo.getRcv().getAdr().getLoccty(), "CTYTXT", SettleContext.getOwnPts().getAdr().getUil());
                }
                blk = trndocService.xmlGetTxtSepTxt("", "", doceotVo.getRcv().getAdr().getNam1());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, doceotVo.getRcv().getAdr().getNam2());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, doceotVo.getRcv().getAdr().getNam3());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, doceotVo.getRcv().getAdr().getStr1());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, doceotVo.getRcv().getAdr().getStr2());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, zipTown);
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, doceotVo.getRcv().getAdr().getLoc2());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, locCty);
            } else {
                blk = getFmtAdrBlk(doceotVo, adrFmtKey);
            }
            DocUtils.putData(dataMap, "blk", blk);
            // do also output free text addresses (not stored in database)
        } else {
            if (!MdaUtils.isEmpty(doceotVo.getAdrblk())) {
                Streams.streamSet(adrStm, doceotVo.getAdrblk());
                cnt = Streams.streamCount(adrStm);
                for (int i = 1; i <= cnt; i++) {
                    lin = Strings.getLine(adrStm, i);
                    // do not output empty lines
                    if (!MdaUtils.isEmpty(lin)) {
                        DocUtils.putData(dataMap, "lin", lin);
                    }
                }
            }
        }

    }

    public void printAddress(Map<String, List<String[]>> dataMap, DoceotVo doceotVo) {
        if (trndocService.getCurrentCORLineLength(doceotVo) == -2) {
            // skip adress for SWIFT
            return;
        }
//        if( trndocService.getCurrentCORLineLength(doceotVo) == -1 )
//        {
        // for letter only
            /*
             print vertical ( 40, tdUnitmm, tdPosAbsolute )
             */
//        }
//        else
        if (trndocService.getCurrentCORLineLength(doceotVo) != -1) {
            // for telex
            DocUtils.putData(dataMap, "receiver", "Receiver of message:");
        }
        String blk;
        String adrFmtKey;
        String zipTown;
        String locCty;
        IStream adrStm = new StreamImpl();
        int cnt;
        String lin;
        if (doceotVo.getRcv().getAdr() != null && StringUtils.isNotEmpty(doceotVo.getRcv().getAdr().getInr())) {
            adrFmtKey = getAdrFormat(doceotVo, SettleContext.getOwnPts().getAdr().getLoccty());
            if (MdaUtils.isEmpty(adrFmtKey)) {
                // use default format
                // connect zip code and town 1st to start always at a new line, also if zip code is empty
                zipTown = trndocService.xmlGetTxtSepTxt(doceotVo.getRcv().getAdr().getLoczip(), " ", doceotVo.getRcv().getAdr().getLoctxt());
                // Do not display country, if dispatch is domestic
                locCty = "";
                if (MdaUtils.compareTo(doceotVo.getRcv().getAdr().getLoccty(), SettleContext.getOwnPts().getAdr().getLoccty()) != 0) {
                    // Output of the country in entity language
                    locCty = codetableService.getTblLabel(doceotVo.getRcv().getAdr().getLoccty(), "CTYTXT", SettleContext.getOwnPts().getAdr().getUil());
                }
                blk = trndocService.xmlGetTxtSepTxt("", "", doceotVo.getRcv().getAdr().getNam1());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, doceotVo.getRcv().getAdr().getNam2());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, doceotVo.getRcv().getAdr().getNam3());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, doceotVo.getRcv().getAdr().getStr1());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, doceotVo.getRcv().getAdr().getStr2());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, zipTown);
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, doceotVo.getRcv().getAdr().getLoc2());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, locCty);
            } else {
                blk = getFmtAdrBlk(doceotVo, adrFmtKey);
            }
            DocUtils.putData(dataMap, "blk", blk);
            // do also output free text addresses (not stored in database)
        } else {
            if (!MdaUtils.isEmpty(doceotVo.getAdrblk())) {
                Streams.streamSet(adrStm, doceotVo.getAdrblk());
                cnt = Streams.streamCount(adrStm);
                String linTemp = "";
                for (int i = 1; i <= cnt; i++) {
                    lin = Strings.getLine(adrStm, i);
                    // do not output empty lines
                    if (!MdaUtils.isEmpty(lin)) {
                        linTemp += lin + "\n";
                    }
                }
                DocUtils.putData(dataMap, "lin", linTemp);
            }
        }

    }
    /**
     * source:doceot.0072.script
     */
    public String getAdrFormat(DoceotVo doceotVo, String argEtyCty) {
        //! Get address format from table CTY.
        // ArgEtyCty = Country key of current entity. Get via "GetCtyOfEty".
        if (MdaUtils.isEmpty(argEtyCty)) {
            SettleExceptionUtils.sysDump("GetAdrFormat: Called with an empty country key of entity!");
        }
        // if receiver is situated in the same country as entity
        Cty cty = ctyMapper.selectByCod(doceotVo.getRcv().getAdr().getLoccty());
        if (cty != null) {
            if (MdaUtils.compareTo(doceotVo.getRcv().getAdr().getLoccty(), argEtyCty) == 0) {
                // Domestic address
                return cty.getFmtdomadrtyp();
            } else {
                // Address abroad
                return cty.getFmtintadrtyp();
            }
        }
        return null;
    }

    /**
     * source:doceot.0107.script
     */
    public String getFmtAdrBlk(DoceotVo doceotVo, String argAdrFmt) {
        //! Function for formatting the address block of the receiver
        // ArgAdrFmt = Content of fields CTY\\FMTdomADRTYP (domestic) or
        //             CTY\\FMTintADRTYP (abroad) and
        //             is filled via "GetAdrFormat".
        // Do not display country, if dispatch is domestic
        String locCty = "";
        if (MdaUtils.compareTo(doceotVo.getRcv().getAdr().getLoccty(), SettleContext.getOwnPts().getAdr().getLoccty()) != 0) {
            // Output of the country in entity language
            locCty = Codetables.getCodetableLabelOfTd(doceotVo.getRcv().getAdr().getLoccty(), "CTYTXT", SettleContext.getOwnPts().getAdr().getUil());
        }
        // for postal address ("A") and all other
        String strPob = trndocService.xmlGetTxtSepTxt(doceotVo.getRcv().getAdr().getStr1(), CR, doceotVo.getRcv().getAdr().getStr2());
        String zip = doceotVo.getRcv().getAdr().getLoczip();
        String town = doceotVo.getRcv().getAdr().getLoctxt();
        String province = "";
        if (!MdaUtils.isEmpty(doceotVo.getRcv().getAdr().getLoc2())) {
            province = Strings.formatText("($1)", doceotVo.getRcv().getAdr().getLoc2());
        }
        // Location/Destination of receiver always display in capital letters, if it is international dispatch
        if (MdaUtils.compareTo(doceotVo.getRcv().getAdr().getLoccty(), SettleContext.getOwnPts().getAdr().getLoccty()) != 0) {
            town = Strings.toUpper(town);
            // show province in upper case too
            province = Strings.toUpper(province);
        }
        String blk = "";
        String zipTown = NULLSTR;
        switch (Strings.toUpper(argAdrFmt)) {
            // Domestic DE ["Zip Code Location" - Address or P.O. Box]
            case "A":
                blk = trndocService.xmlGetTxtSepTxt(blk, "", doceotVo.getRcv().getAdr().getNam1());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, doceotVo.getRcv().getAdr().getNam2());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, doceotVo.getRcv().getAdr().getNam3());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, doceotVo.getPtcnam());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, doceotVo.getRcv().getAdr().getDpt());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, strPob);
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, zip);
                blk = trndocService.xmlGetTxtSepTxt(blk, " ", town);
                // Abroad ["Location Zip Code (Province)" - only Address]
                break;
            case "B":
                blk = trndocService.xmlGetTxtSepTxt(blk, "", doceotVo.getRcv().getAdr().getNam1());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, doceotVo.getRcv().getAdr().getNam2());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, doceotVo.getRcv().getAdr().getNam3());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, doceotVo.getPtcnam());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, doceotVo.getRcv().getAdr().getDpt());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, strPob);
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, town);
                blk = trndocService.xmlGetTxtSepTxt(blk, " ", zip);
                blk = trndocService.xmlGetTxtSepTxt(blk, " ", province);
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, locCty);
                // Domestic GB ["Location
                //               Zip Code" - only Address]
                break;
            case "C":
                blk = trndocService.xmlGetTxtSepTxt(blk, "", doceotVo.getRcv().getAdr().getNam1());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, doceotVo.getRcv().getAdr().getNam2());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, doceotVo.getRcv().getAdr().getNam3());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, doceotVo.getPtcnam());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, doceotVo.getRcv().getAdr().getDpt());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, strPob);
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, town);
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, zip);
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, locCty);
                // Abroad ["Zip Code Location (Province)" - only Address]
                break;
            case "D":
                blk = trndocService.xmlGetTxtSepTxt(blk, "", doceotVo.getRcv().getAdr().getNam1());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, doceotVo.getRcv().getAdr().getNam2());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, doceotVo.getRcv().getAdr().getNam3());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, doceotVo.getPtcnam());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, doceotVo.getRcv().getAdr().getDpt());
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, strPob);
                // connect zip code and town 1st to start always at a new line, also if zip code is empty
                zipTown = trndocService.xmlGetTxtSepTxt(zip, " ", town);
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, zipTown);
                blk = trndocService.xmlGetTxtSepTxt(blk, " ", province);
                blk = trndocService.xmlGetTxtSepTxt(blk, CR, locCty);
                break;
            default:
                // z.Z. nix
        }
        return blk;

    }
}
