package com.brilliance.isc.swift.swtmsg;

import com.brilliance.mda.runtime.mda.impl.Argument;
import com.brilliance.mda.runtime.mda.util.Decimals;
import com.brilliance.mda.runtime.mda.util.MdaUtils;
import com.brilliance.mda.runtime.mda.util.Numerics;
import com.brilliance.mda.runtime.mda.util.Strings;
import com.brilliance.isc.bo.Bch;
import com.brilliance.isc.bo.Fee;
import com.brilliance.isc.bo.model.Gidgrp;
import com.brilliance.isc.bo.model.Nidgrp;
import com.brilliance.isc.common.api.bch.service.BchService;
import com.brilliance.isc.common.codetable.service.CodetableService;
import com.brilliance.isc.common.component.PtsptaToolComponent;
import com.brilliance.isc.common.context.SettleContext;
import com.brilliance.isc.common.setfeg.service.SetfegService;
import com.brilliance.isc.common.setfeg.vo.SetfegVo;
import com.brilliance.isc.common.setfeg.vo.SetfelVo;
import com.brilliance.isc.common.setfog.service.SetfogService;
import com.brilliance.isc.common.setfog.vo.SetfogVo;
import com.brilliance.isc.common.setfog.vo.SetfolVo;
import com.brilliance.isc.common.setglg.service.SetglgService;
import com.brilliance.isc.common.setglg.vo.SetglgVo;
import com.brilliance.isc.common.setgll.vo.SetgllVo;
import com.brilliance.isc.common.setmod.service.SetmodService;
import com.brilliance.isc.common.setmod.vo.SetmodVo;
import com.brilliance.isc.common.transaction.help.TransactionHelpService;
import com.brilliance.isc.common.transaction.vo.BaseTransactionVo;
import com.brilliance.isc.common.trndoc.vo.DoceotVo;
import com.brilliance.isc.common.util.StringUtils;
import com.brilliance.isc.common.util.Utils;
import com.brilliance.isc.common.vo.FremsgVo;
import com.brilliance.isc.common.vo.PtsptaVo;
import com.brilliance.isc.mda.dao.FeeMapper;
import com.brilliance.isc.swift.objmtconvert.model.commontag.ActnoBicAdrTagXXX;
import com.brilliance.isc.swift.objmtconvert.model.commontag.DcDateCurAmtTagXXX;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.*;

@Component
public class SwiftMessageComponent {

    public static final String UilSwift = "UilSwift";
    @Autowired
    private BchService bchService;
    @Autowired
    private CodetableService codetableService;
    @Autowired
    private PtsptaToolComponent ptsptaToolComponent;

    @Autowired
    private SetglgService setglgService;

    @Autowired
    private SetfogService setfogService;

    @Autowired
    private SetfegService setfegService;

    @Autowired
    private SetmodService setmodService;

    @Autowired
    private TransactionHelpService transactionHelpService;

    @Autowired
    private FeeMapper feeMapper;

    /**
     * 代码出处 Setmod.swtPrtFeesForRole
     */
    public ActnoBicAdrTagXXX swtPrtFeesForRole(
            SetmodVo setmodVo, String tag, String mtType, String role, String dirFlg, String dspFlg) {
        List<SetfelVo> setfels = setmodVo.getSetfeg().getSetfel();
        List<SetfolVo> setfols = setmodVo.getSetfog().getSetfol();
        Map<String, CurAmtInfo> map = new LinkedHashMap<>();
        for (SetfelVo setfel : setfels) {
            if (role.equals(setfel.getRol())
                    && ((setfel.getAmt().compareTo(BigDecimal.ZERO) > 0 && MdaUtils.compareTo(dirFlg, "C") != 0) || (MdaUtils.compareTo(setfel.getAmt(), 0) < 0 && MdaUtils.compareTo(dirFlg, "D") != 0))
                    && (MdaUtils.compareTo(setfel.getDsp(), dspFlg) == 0 || MdaUtils.isEmpty(dspFlg))) {
                String type = "";
                Fee fee = feeMapper.selectByCod(setfel.getFeecod());
                if (fee != null) {
                    type = codetableService.getTblLabel(fee.getSftcod(), "FEESFT");
                }
                String sgn = "";
                BigDecimal amt = setfel.getAmt();
                if (MdaUtils.compareTo(amt, 0) < 0) {
                    sgn = "-";
                } else {
                    sgn = "+";
                }
                if (MdaUtils.isEmpty(type)) {
                    type = sgn + "/MISC/";
                } else {
                    type = sgn + type;
                }
                if (map.containsKey(type)) {
                    BigDecimal addAmt = map.get(type).getAmt();
                    map.put(type, new CurAmtInfo(setfel.getCur(), Decimals.add(addAmt, setfel.getAmt())));
                } else {
                    map.put(type, new CurAmtInfo(setfel.getCur(), setfel.getAmt()));
                }
            }
        }
        for (SetfolVo setfol : setfols) {
            BigDecimal amt = BigDecimal.ZERO;
            if (MdaUtils.compareTo(setfol.getAmt(), 0) > 0
                    && (MdaUtils.compareTo(setfol.getDsp(), dspFlg) == 0 || MdaUtils.isEmpty(dspFlg))) {
                if (MdaUtils.compareTo(role, setfol.getPtypay()) == 0 && MdaUtils.compareTo(dirFlg, "D") != 0) {
                    amt = setfol.getAmt();
                }
                if (MdaUtils.compareTo(role, setfol.getPtydbt()) == 0 && MdaUtils.compareTo(dirFlg, "C") != 0) {
                    amt = setfol.getAmt().negate();
                }
                if (amt.compareTo(BigDecimal.ZERO) != 0) {
                    String type = "";
                    String sgn = "";
                    // use different codewords for debiting and paying foreign charges
                    if (MdaUtils.compareTo(amt, 0) < 0) {
                        sgn = "-";
                        // DO5CS.703597
                        if ("400".equals(mtType)) {
                            type = sgn + "/YOURCHAR/";
                        } else {
                            type = sgn + "/CORCOM/";
                        }
                    } else {
                        sgn = "+";
                        // DO5CS.703597
                        type = sgn + "/CORCOM/";
                        /*
                         select case ArgMT
                         case "750", "754", "400"
                         $Typ = $Sgn + "/YOURCHAR/"
                         case else
                         $Typ = $Sgn + "/CORCOM/"
                         end select
                         */
                    }
                    if (map.containsKey(type)) {
                        BigDecimal addAmt = map.get(type).getAmt();
                        map.put(type, new CurAmtInfo(setfol.getCur(), Decimals.add(addAmt, setfol.getAmt())));
                    } else {
                        map.put(type, new CurAmtInfo(setfol.getCur(), setfol.getAmt()));
                    }
                }
            }
        }
        if (map.size() > 0) {
            List<String> line = new ArrayList<>();
            map.keySet().forEach(key -> {
                if (line.size() < 6) {
                    CurAmtInfo curAmtInfo = map.get(key);
                    line.add(key.substring(1) + curAmtInfo.getCur() + Utils.fmtAmountSwift(curAmtInfo.getAmt().abs(), curAmtInfo.getCur()));
                }
            });
            StringBuilder lineStr = new StringBuilder();
            for (int i = 0; i < line.size(); i++) {
                if (i == line.size() - 1) {
                    lineStr.append(line.get(i));
                } else {
                    lineStr.append(line.get(i)).append("\n");
                }
            }
            ActnoBicAdrTagXXX actnoBicAdrTagXXX = new ActnoBicAdrTagXXX(tag);
            actnoBicAdrTagXXX.setNarrative(lineStr.toString());
            return actnoBicAdrTagXXX;
        }
        return null;
    }

    /**
     * source:setmod.0151.script
     */
    public String printSwiftFeeDetDspFun(
            SetmodVo setmodVo, String rol, String tag, String sel, String argmt, String argCharSet) {
        // sel fmt=ABC :  (for compatibility with other uses only supplying A or AB)
        // A is SETFEL: X = collected, V = advised in this transaction, P = Pool, A = all, N = advised and collected
        // B is SETFOL: optional, "O" = omit, "D" = debit only, "P" = pay only, " " = all
        // C is SETFOL: X = collected, V = advised in this transaction, P = Pool, " " = all
        String dsp = Strings.mid(sel, 1, 1);
        String forVar = Strings.mid(sel, 2, 1);
        String fds = Strings.mid(sel, 3, 1);
        Map<String, CurAmtInfo> map = new LinkedHashMap<>();

        /**
         SetDocPanelFormat( ArgCharSet )
         **/
        int allow = 0;
        switch (tag) {
            case "79":
                allow = 50;
                break;
            case "71M":
                if (MdaUtils.compareTo(argmt, "757") == 0 || MdaUtils.compareTo(argmt, "758") == 0) {
                    allow = 15;
                } else {
                    allow = 6;
                }
                break;
            default:
                allow = 6;
        }
        setmodVo.getSetfeg().getSetfel().forEach(setfel -> {
            if (rol.equals(setfel.getRol()) && dsp.equals(setfel.getDsp()) && setfel.getAmt().compareTo(BigDecimal.ZERO) != 0) {
                String type = "";
                Fee fee = feeMapper.selectByCod(setfel.getFeecod());
                if (fee != null) {
                    type = codetableService.getTblLabel(fee.getSftcod(), "FEESFT");
                }
                switch (tag) {
                    case "71B":
                    case "71M":
                    case "71D":
                        if (MdaUtils.isEmpty(type)) {
                            type = "/COMM/";
                        }
                        break;
                    case "73":
                    case "73A":
                        if (MdaUtils.isEmpty(type)) {
                            type = "/RETCOMM/";
                        }
                        break;
                    default:
                        break;
                }
                if (map.containsKey(type)) {
                    BigDecimal addAmt = map.get(type).getAmt();
                    map.put(type, new CurAmtInfo(setfel.getCur(), Decimals.add(addAmt, setfel.getAmt())));
                } else {
                    map.put(type, new CurAmtInfo(setfel.getCur(), setfel.getAmt()));
                }
            }
        });
        if (MdaUtils.compareTo(forVar, "O") != 0) {
            setmodVo.getSetfog().getSetfol().forEach(setfol -> {
                if (MdaUtils.compareTo(fds, setfol.getDsp()) == 0 || MdaUtils.compareTo(fds, " ") == 0) {
                    BigDecimal amt = BigDecimal.ZERO;
                    if (MdaUtils.compareTo(forVar, "P") == 0 || MdaUtils.compareTo(forVar, " ") == 0) {
                        if (MdaUtils.compareTo(rol, setfol.getPtypay()) == 0 && MdaUtils.compareTo(setfol.getAmt(), 0) != 0) {
                            amt = Decimals.sub(amt, setfol.getAmt());
                        }
                    }
                    if (MdaUtils.compareTo(forVar, "D") == 0 || MdaUtils.compareTo(forVar, " ") == 0) {
                        if (MdaUtils.compareTo(rol, setfol.getPtydbt()) == 0 && MdaUtils.compareTo(setfol.getAmt(), 0) != 0) {
                            amt = Decimals.add(amt, setfol.getAmt());
                        }
                    }
                    if (!MdaUtils.isEmpty(amt)) {
                        String type = "/CORCOM/";
                        if (map.containsKey(type)) {
                            BigDecimal addAmt = map.get(type).getAmt();
                            map.put(type, new CurAmtInfo(setfol.getCur(), Decimals.add(addAmt, amt)));
                        } else {
                            map.put(type, new CurAmtInfo(setfol.getCur(), amt));
                        }
                    }
                }
            });
        }
        if (map.size() > 0) {
            List<String> line = new ArrayList<>();
            int finalAllow = allow;
            map.keySet().forEach(key -> {
                if (line.size() < finalAllow) {
                    CurAmtInfo curAmtInfo = map.get(key);
                    line.add(key + curAmtInfo.getCur() + Utils.fmtAmountSwift(curAmtInfo.getAmt(), curAmtInfo.getCur()));
                }
            });
            StringBuilder lineStr = new StringBuilder();
            for (int i = 0; i < line.size(); i++) {
                if (i == line.size() - 1) {
                    lineStr.append(line.get(i));
                } else {
                    lineStr.append(line.get(i)).append("\n");
                }
            }
            return lineStr.toString();
        }
        return null;
    }

    /**
     *   source:setmod.0065.script
     */
    public String printSwiftFees(SetmodVo setmodVo, String rol, String tag, String argDirFlg, String argDspFlg, String argmt, Argument<String> argTotCur, Argument<BigDecimal> argTotAmt) {
        //! Print information about fees in SWIFT-Messages
        //! To be used with following ; to aviod empty lines in message
        //!
        //! Rol         : Role for which fees should be printed (usually TRNMOD\\TRNDOC\\DOCCUR\\ROLE )
        //!
        //! Tag         : Complete tag to be used
        //!
        //! ArgDirFlg   : If not empty, print only fees ..
        //!               D   debited
        //!               C   credited (usually foreign fees only)
        //!
        //! ArgDspFlg   : If empty, print all fees matching ArgDirFlg criteria, otherwise
        //!               V   advised fees only
        //!               X   Settled fees only ( if temporary settlement, "S" is checked)
        //!
        //! ArgLinNum   : Maximum number of lines of field according to SWIFT-Manual
        //!               If fees for more different SWIFT-Fee codes are found, the total sum is printed as \\MISC\\
        //!
        //! ArgTotCur, ArgTotAmt: Total amount listed; empty if different currencies
        //! ArgMT     : Message type
        //!
        String chkdspflg = argDspFlg;
        Map<String, CurAmtInfo> map = new LinkedHashMap<>();
        setmodVo.getSetfeg().getSetfel().forEach(setfel -> {
            if(MdaUtils.compareTo(rol, setfel.getRol()) == 0
                    && ((MdaUtils.compareTo(setfel.getAmt(), 0) > 0 && MdaUtils.compareTo(argDirFlg,"C") != 0) || (MdaUtils.compareTo(setfel.getAmt(),0) < 0 && MdaUtils.compareTo(argDirFlg,"D") != 0))
                    && ( MdaUtils.compareTo(setfel.getDsp(), chkdspflg) == 0 || MdaUtils.isEmpty(chkdspflg))){
                String type = "";
                Fee fee = feeMapper.selectByCod(setfel.getFeecod());
                if (fee != null) {
                    type = codetableService.getTblLabel(fee.getSftcod(), "FEESFT");
                }
                BigDecimal amt = setfel.getAmt();
                String sgn = "";
                if( MdaUtils.compareTo(amt,0)<0 ) {
                    sgn = "-";
                } else {
                    sgn = "+";
                }
                if( MdaUtils.isEmpty(type)) {
                    type = sgn + "/MISC/";
                } else {
                    type = sgn + type;
                }
                if (map.containsKey(type)) {
                    BigDecimal addAmt = map.get(type).getAmt();
                    map.put(type, new CurAmtInfo(setfel.getCur(), Decimals.add(addAmt, amt)));
                } else {
                    map.put(type, new CurAmtInfo(setfel.getCur(), amt));
                }

            }
        });
        setmodVo.getSetfog().getSetfol().forEach(setfol -> {
            String type = "";
            BigDecimal amt = new BigDecimal("0");
            if( MdaUtils.compareTo(rol, setfol.getPtypay()) == 0 && MdaUtils.compareTo(setfol.getAmt(),0) > 0 && MdaUtils.compareTo(argDirFlg,"D") != 0 && ( MdaUtils.compareTo(setfol.getDsp(), chkdspflg) == 0 || MdaUtils.isEmpty(chkdspflg))) {
                amt = Decimals.add(amt, setfol.getAmt());
            }
            if(MdaUtils.compareTo(rol, setfol.getPtydbt()) == 0 && MdaUtils.compareTo(setfol.getAmt(), 0) > 0 && MdaUtils.compareTo(argDirFlg,"C") != 0 && ( MdaUtils.compareTo(setfol.getDsp(), chkdspflg) == 0 || MdaUtils.isEmpty(chkdspflg))) {
                amt = Decimals.sub(amt, setfol.getAmt());
            }
            if(!MdaUtils.isEmpty(amt)) {
                // use different codewords for debiting and paying foreign charges
                if( MdaUtils.compareTo(amt,0) < 0 ) {
                    String sgn = "-";
                    // DO5CS.703597
                    switch(argmt) {
                        case "400":
                            type = sgn + "/YOURCHAR/";
                            break;
                        default:
                            type = sgn + "/CORCOM/";
                    }
                } else {
                    String sgn = "+";
                    // DO5CS.703597
                    type = sgn + "/CORCOM/";
                    /**
                     select case \\TRNMOD\\TRNDOC\\DOCCUR\\MT
                     case "750", "754"
                     $Typ = $Sgn + "/YOURCHAR/"
                     case else
                     $Typ = $Sgn + "/CORCOM/"
                     end select

                     **/
                }
                if (map.containsKey(type)) {
                    BigDecimal addAmt = map.get(type).getAmt();
                    map.put(type, new CurAmtInfo(setfol.getCur(), Decimals.add(addAmt, amt)));
                } else {
                    map.put(type, new CurAmtInfo(setfol.getCur(), amt));
                }
            }
        });
        if (map.size() > 0) {
            Map<String, BigDecimal> curamtMap = new HashMap<>();
            List<String> line = new ArrayList<>();
            int finalAllow = 6;
            map.keySet().forEach(key -> {
                if (line.size() < finalAllow) {
                    CurAmtInfo curAmtInfo = map.get(key);
                    line.add(key + curAmtInfo.getCur() + Utils.fmtAmountSwift(curAmtInfo.getAmt(), curAmtInfo.getCur()));
                    if (curamtMap.containsKey(curAmtInfo.getCur())) {
                        if (key.startsWith("+")) {
                            BigDecimal addAmt = map.get(key).getAmt();
                            curamtMap.put(curAmtInfo.getCur(), curamtMap.get(curAmtInfo.getCur()).add(addAmt));
                        } else {
                            BigDecimal addAmt = map.get(key).getAmt();
                            curamtMap.put(curAmtInfo.getCur(), curamtMap.get(curAmtInfo.getCur()).subtract(addAmt));
                        }
                    } else {
                        curamtMap.put(curAmtInfo.getCur(), map.get(key).getAmt());
                    }
                }
            });
            if (curamtMap.size() == 1) {
                String totalCur = "";
                for (String cur : curamtMap.keySet()) {
                    totalCur = cur;
                }
                argTotCur.value = totalCur;
                argTotAmt.value = curamtMap.get(totalCur);
            } else {
                argTotCur.value = "*";
                argTotAmt.value = new BigDecimal("0");
            }
            StringBuilder lineStr = new StringBuilder();
            for (int i = 0; i < line.size(); i++) {
                if (i == line.size() - 1) {
                    lineStr.append(line.get(i));
                } else {
                    lineStr.append(line.get(i)).append("\n");
                }
            }
            return lineStr.toString();
        }
        return null;
    }
    /**
     *   source:setmod.0053.script
     */
    public DcDateCurAmtTagXXX printSwiftFeeRolSumEUR(SetmodVo setmod, String dsp,String rol,String tag, boolean convertEUR) {
        BigDecimal sum = new BigDecimal("0");
        String cur = "";
        String wrnTxt = "";
        for(int d=0; d<setmod.getSetfeg().getSetfel().size(); d++) {
            SetfelVo setfelVo = setmod.getSetfeg().getSetfel().get(d);
            if(MdaUtils.compareTo(setfelVo.getRol(), rol) == 0 && (MdaUtils.compareTo(setfelVo.getDsp(), dsp) == 0 || MdaUtils.compareTo(dsp,"A") == 0)) {
                sum = Decimals.add(sum, setfelVo.getAmt());
                cur = setfelVo.getCur();
            }
        }
        if(MdaUtils.compareTo(sum,0) != 0) {
            DcDateCurAmtTagXXX totalAmountClaimed = new DcDateCurAmtTagXXX(tag);
            // Negativ amount needs (Abs) to avoid SYSDUMP, warning is set
            if(convertEUR) {
                totalAmountClaimed.setAmount(Numerics.abs(sum));
                totalAmountClaimed.setCurrency(cur);
            } else {
                totalAmountClaimed.setAmount(Numerics.abs(sum));
                totalAmountClaimed.setCurrency(cur);
            }
            return totalAmountClaimed;
        }
        return null;
    }
    /**
     *   source:setmod.0054.script
     */
    public DcDateCurAmtTagXXX printSwiftFeeRolSumEURWithVal(SetmodVo setmod, String dsp,String rol,String tag,boolean convertEUR,Date value) {
        // set dsp to "A" to get all fees for specified rol
        BigDecimal sum = new BigDecimal("0");
        String cur = "";
        String wrnTxt = "";
        for(int d=0; d<setmod.getSetfeg().getSetfel().size(); d++) {
            SetfelVo setfelVo = setmod.getSetfeg().getSetfel().get(d);
            if(MdaUtils.compareTo(setfelVo.getRol(), rol) == 0 && (MdaUtils.compareTo(setfelVo.getDsp(), dsp) == 0 || MdaUtils.compareTo(dsp,"A") == 0)) {
                sum = Decimals.add(sum, setfelVo.getAmt());
                cur = setfelVo.getCur();
            }
        }
        if(MdaUtils.compareTo(sum,0) != 0) {
            DcDateCurAmtTagXXX totalAmountClaimed = new DcDateCurAmtTagXXX(tag);
            // Negativ amount needs (Abs) to avoid SYSDUMP, warning is set
            if(convertEUR) {
                totalAmountClaimed.setDate(Utils.fmtDateSwift(value));
                totalAmountClaimed.setAmount(Numerics.abs(sum));
                totalAmountClaimed.setCurrency(cur);
            } else {
                totalAmountClaimed.setDate(Utils.fmtDateSwift(value));
                totalAmountClaimed.setAmount(Numerics.abs(sum));
                totalAmountClaimed.setCurrency(cur);
            }
            return totalAmountClaimed;
        }
        return null;
    }

    /**
     * 代码出处 Trndoc.swtPrtExtAccAdrAorWithoutLetter
     *
     * @param tag
     * @param ptsptaVo
     * @param acc
     * @param optF
     * @return
     */
    public ActnoBicAdrTagXXX swtPrtExtAccAdrAorWithoutLetter(String tag, PtsptaVo ptsptaVo, String acc, String optF) {
        //! format address  ArgPtsPta with tag with appropriate option (A or without letter option) and account acc
        //! if ArgOptF not empty, use letter Option F if possible
        //! DOKA knows 4 line address block, thus option B is not needed
        //! suppresses empty addresslines
        //! no output of option A for TCO messages
        if (ptsptaVo == null) return null;
        ActnoBicAdrTagXXX actnoBicAdrTagXXX = new ActnoBicAdrTagXXX(tag);
        if (StringUtils.isNotEmpty(acc)) {
            if ("59".equals(tag)) {
                actnoBicAdrTagXXX.setAcctno(acc);
            } else {
                actnoBicAdrTagXXX.setPartyIdentifier(acc);
            }
        }
        if (StringUtils.isEmpty(ptsptaVo.getPtainr())) {
            String adrblk = ptsptaVo.getNameAndAddress();
            if (StringUtils.isNotEmpty(adrblk)) {
                actnoBicAdrTagXXX.setAddress(StringUtils.convertBlock(adrblk, 4, 35));
            } else {
                return null;
            }
        } else {
            if (ptsptaVo.getAdr() != null && !MdaUtils.isEmpty(ptsptaVo.getAdr().getBic()) && Strings.pos(ptsptaVo.getPta().getPtytyp(), "B") > 0) {
                actnoBicAdrTagXXX.setBic(ptsptaVo.getAdr().getBic());
            }
            // Do5Dos 10122 Option F
            if (!MdaUtils.isEmpty(optF)) {
                String line = "1/" + ptsptaVo.getAdr().getNam1();
                if (line.length() > 35) {
                    line = line.substring(0, 35);
                }
                if (StringUtils.isNotEmpty(ptsptaVo.getAdr().getNam2())) {
                    String line1 = "1/" + ptsptaVo.getAdr().getNam2();
                    if (line1.length() > 35) {
                        line1 = line1.substring(0, 35);
                    }
                    line += "\n" + line1;
                }
                if (StringUtils.isNotEmpty(ptsptaVo.getAdr().getStr1())) {
                    String line2 = "2/" + ptsptaVo.getAdr().getStr1();
                    if (line2.length() > 35) {
                        line2 = line2.substring(0, 35);
                    }
                    line += "\n" + line2;
                }
                String line3 = "3/" + ptsptaVo.getAdr().getLoccty() + "/";
                if (!MdaUtils.isEmpty(ptsptaVo.getAdr().getLoczip())) {
                    line3 += ptsptaVo.getAdr().getLoczip() + " ";
                }
                line3 += ptsptaVo.getAdr().getLoctxt();
                if (line3.length() > 35) {
                    line3 = line3.substring(0, 35);
                }
                line += "\n" + line3;
                actnoBicAdrTagXXX.setAddress(StringUtils.convertBlock(line, 4, 35));
            } else {
                // without letter option
                actnoBicAdrTagXXX.setAddress(StringUtils.convertBlock(ptsptaVo.getNameAndAddress(), 4, 35));
            }
        }
        return actnoBicAdrTagXXX;
    }

    /**
     * 代码出处 Setmod.swtPrtExtAccAdrAD
     *
     * @param tag
     * @param ptsptaVo
     * @return
     */
    public ActnoBicAdrTagXXX swtPrtExtAccAdrAD(String tag, PtsptaVo ptsptaVo, String argAcc) {
        //! format address  ArgPtsPta with tag with appropriate option (A or D) and account acc
        //! DOKA knows 4 line address block, thus option B is not needed
        //! suppresses empty addresslines
        //! no output of option A for TCO messages
        if (ptsptaVo == null) return null;
        ActnoBicAdrTagXXX actnoBicAdrTagXXX = new ActnoBicAdrTagXXX(tag);
        if (StringUtils.isNotEmpty(argAcc)) {
            if ("59".equals(tag)) {
                actnoBicAdrTagXXX.setAcctno(argAcc);
            } else {
                actnoBicAdrTagXXX.setPartyIdentifier(argAcc);
            }
        }
        if (StringUtils.isEmpty(ptsptaVo.getPtainr())) {
            String adrblk = ptsptaVo.getNameAndAddress();
            if (StringUtils.isNotEmpty(adrblk)) {
                actnoBicAdrTagXXX.setAddress(StringUtils.convertBlock(adrblk, 4, 35));
            } else {
                return null;
            }
        } else {
            // DNGDEV.004584
            // in case adrblk is not the same as dbfadrblk print address block
            if (ptsptaVo.getAdr() != null && StringUtils.isNotEmpty(ptsptaVo.getAdr().getBic()) && ptsptaVo.getAdrblk().equals(ptsptaVo.getDbfadrblk())) {
                actnoBicAdrTagXXX.setBic(ptsptaVo.getAdr().getBic());
            }
            actnoBicAdrTagXXX.setAddress(StringUtils.convertBlock(ptsptaVo.getNameAndAddress(), 4, 35));
        }
        return actnoBicAdrTagXXX;
    }

    /**
     * 代码出处 Trndoc.swtPrtAccAdrAD
     *
     * @param tag
     * @param ptsptaVo
     * @return
     */
    public ActnoBicAdrTagXXX swtPrtAccAdrAD(String tag, PtsptaVo ptsptaVo) {
        //! format address  ArgPtsPta with tag with appropriate option (A or D) and account acc
        //! DOKA knows 4 line address block, thus option B is not needed
        //! suppresses empty addresslines
        //! no output of option A for TCO messages
        if (!ptsptaToolComponent.ptsIsRolSet(ptsptaVo)) return null;
        ActnoBicAdrTagXXX actnoBicAdrTagXXX = new ActnoBicAdrTagXXX(tag);
        if (ptsptaVo.getPts() != null && StringUtils.isNotEmpty(ptsptaVo.getPts().getExtact())) {
            actnoBicAdrTagXXX.setAcctno(ptsptaVo.getPts().getExtact());
        }
        if (StringUtils.isEmpty(ptsptaVo.getPtainr())) {
            String adrblk = ptsptaVo.getNameAndAddress();
            if (StringUtils.isNotEmpty(adrblk)) {
                actnoBicAdrTagXXX.setAddress(StringUtils.convertBlock(adrblk, 4, 35));
            } else {
                return null;
            }
        } else {
            // DNGDEV.004584
            // in case adrblk is not the same as dbfadrblk print address block
            if (ptsptaVo.getAdr() != null && StringUtils.isNotEmpty(ptsptaVo.getAdr().getBic().trim()) && ptsptaVo.getAdrblk().equals(ptsptaVo.getDbfadrblk())) {
                actnoBicAdrTagXXX.setBic(ptsptaVo.getAdr().getBic().trim());
            }
            actnoBicAdrTagXXX.setAddress(StringUtils.convertBlock(ptsptaVo.getNameAndAddress(), 4, 35));
        }
        return actnoBicAdrTagXXX;
    }

    /**
     * source:setmod.0173.script
     */
    public DcDateCurAmtTagXXX printSwiftTotalAmountOpt(SetglgVo setglgVo, String dsp, String rol, String tag) {
        DcDateCurAmtTagXXX dcDateCurAmtTagXXX = new DcDateCurAmtTagXXX(tag);
        // dsp = "A" means use all dispositions
        int found = 0;
        List<SetgllVo> setgllVos = setglgVo.getSetgll();
        for (int d = 1; d <= setgllVos.size(); d++) {
            if ((MdaUtils.compareTo(dsp, "A") == 0 || MdaUtils.compareTo(setgllVos.get(d - 1).getDsp(), dsp) == 0) && MdaUtils.compareTo(setgllVos.get(d - 1).getRol(), rol) == 0 && MdaUtils.compareTo(setgllVos.get(d - 1).getAcccpramt(), 0) != 0) {
                found = d;
            }
        }

        if (found != 0) {
            int foundIndex = found - 1;
            if (MdaUtils.compareTo(Strings.mid(setgllVos.get(foundIndex).getDsp(), 1, 2), "DA") != 0) {
//                Systems.printTemp(":", tag, "B:", setgllVos.get(found).getAcccur(), Utils.fmtAmountSwift(Numerics.abs(setgllVos.get(found).getAcccpramt()), setgllVos.get(found).getAcccur()));
                dcDateCurAmtTagXXX.setCurrency(setgllVos.get(foundIndex).getAcccur());
                dcDateCurAmtTagXXX.setAmount(Numerics.abs(setgllVos.get(foundIndex).getAcccpramt()));
            } else {
                if (MdaUtils.isEmpty(setgllVos.get(foundIndex).getValdat())) {
//                    Systems.printTemp(":", tag, "B:", setgllVos.get(found).getAcccur(), Utils.fmtAmountSwift(Numerics.abs(setgllVos.get(found).getAcccpramt()), setgllVos.get(found).getAcccur()));
                    dcDateCurAmtTagXXX.setCurrency(setgllVos.get(foundIndex).getAcccur());
                    dcDateCurAmtTagXXX.setAmount(Numerics.abs(setgllVos.get(foundIndex).getAcccpramt()));
                } else {
//                    Systems.printTemp(":" + tag + "D:" + Formats.format(setgllVos.get(found).getValdat(), "YYMMDD") + setgllVos.get(found).getAcccur() + Utils.fmtAmountSwift(Numerics.abs(setgllVos.get(found).getAcccpramt()), setgllVos.get(found).getAcccur()));
                    dcDateCurAmtTagXXX.setDate(printSwiftDate(setgllVos.get(foundIndex).getValdat()));
                    dcDateCurAmtTagXXX.setCurrency(setgllVos.get(foundIndex).getAcccur());
                    dcDateCurAmtTagXXX.setAmount(Numerics.abs(setgllVos.get(foundIndex).getAcccpramt()));
                }
            }
        }

        return dcDateCurAmtTagXXX;
    }

    /*代码出处 trndoc.swtPrtAdrBicOrAdr*/
    public ActnoBicAdrTagXXX swtPrtAdrBicOrAdr(String tag, PtsptaVo ptsptaVo, String cortyp) {
        if (ptsptaVo == null) {
            return null;
        }
        ActnoBicAdrTagXXX actnoBicAdrTagXXX = new ActnoBicAdrTagXXX(tag);
        if (StringUtils.isEmpty(ptsptaVo.getPtainr())) {
            if (StringUtils.isEmpty(ptsptaVo.getNameAndAddress())) {
                return null;
            }
            actnoBicAdrTagXXX.setAddress(StringUtils.convertBlock(ptsptaVo.getNameAndAddress(), 4, 35));
        } else {
            if (ptsptaVo.getAdr() != null && StringUtils.isNotEmpty(ptsptaVo.getAdr().getBic())
                    && (MdaUtils.compareTo(cortyp, "TCO") != 0 && MdaUtils.compareTo(cortyp, "TCX") != 0)
                    && MdaUtils.compareTo(ptsptaVo.getAdrblk(), ptsptaVo.getDbfadrblk()) == 0) {
                actnoBicAdrTagXXX.setBic(ptsptaVo.getAdr().getBic());
            }
            actnoBicAdrTagXXX.setAddress(StringUtils.convertBlock(ptsptaVo.getNameAndAddress(), 4, 35));
        }
        return actnoBicAdrTagXXX;
    }

    /*代码出处 setmod.printSwiftDoccurAmount*/
    public DcDateCurAmtTagXXX printSwiftDoccurAmount(
            List<SetgllVo> setglls, String argDsp, String argRol, String argTag) {
        //! Prints sum of amounts in ArgTag if there are only amounts in document currency of that role and disposition in SETGLG.
        //! Necessary for tags that are only allowed in same curreny as tag with document amount, e.g. tag 34 in MT 754
        //! The tag has to be an optional tag as it is omitted if other lines are available
        //! ArgDsp : Disposition (if empty all dispositions are matching)
        //! ArgRol : Role (mandatory)
        //! ArgTag : Tag to be printed (without option; if no or different value dates are available option B is used, otherwise option A)
        if (setglls == null || setglls.size() == 0) {
            return null;
        }
        DcDateCurAmtTagXXX dcDateCurAmtTagXXX = new DcDateCurAmtTagXXX(argTag);
        BigDecimal amtSum = new BigDecimal("0");
        Date valDat = null;
        int valDatCnt = 0;
        String doccur = "";
        for (int i = 0; i < setglls.size(); i++) {
            SetgllVo setgllVo = setglls.get(i);
            if ((argDsp.equals(setgllVo.getDsp()) || (StringUtils.isEmpty(argDsp) && !setmodService.isInternalDsp(setgllVo.getDsp()))) && argRol.equals(setgllVo.getRol())) {
                amtSum = amtSum.add(setgllVo.getAmt());
                doccur = setgllVo.getCur();
                if (setgllVo.getValdat() != null) {
                    if (valDat == null) {
                        valDat = setgllVo.getValdat();
                        valDatCnt = 1;
                    } else {
                        if (setgllVo.getValdat() != valDat) {
                            valDatCnt = valDatCnt + 1;
                        }
                    }
                }
            }
        }
        if (amtSum.compareTo(BigDecimal.ZERO) != 0) {
            if (valDat == null || valDatCnt > 1) {
                dcDateCurAmtTagXXX.setCurrency(doccur);
                dcDateCurAmtTagXXX.setAmount(amtSum.abs());
            } else {
                dcDateCurAmtTagXXX.setDate(Utils.fmtDateSwift(valDat));
                dcDateCurAmtTagXXX.setCurrency(doccur);
                dcDateCurAmtTagXXX.setAmount(amtSum.abs());
            }
            return dcDateCurAmtTagXXX;
        }
        return null;
    }

    /*代码出处 setmod.swtPrtAccAdrSpc*/
    public ActnoBicAdrTagXXX swtPrtAccAdrSpc(
            String argTag, String argMt, PtsptaVo argPtsPta, String argAcc, String argOptF) {
        //! print tag 53,54,55,56,57,58 with special functions as defined per overlay
        // ArgOptF : if set to not-empty, Letter Option F is used for Tag
        // Each output of this tags is handled via this function, except MT754, output of Tags 53/57. This is handled via SWTPrtTag53_57for754.
        ActnoBicAdrTagXXX actnoBicAdrTagXXX = null;
        switch (argTag) {
            case "53":
                switch (argMt) {
                    case "710":
                        //dngdev.001304: At least with SWIFT 2018 there is no reason for Tag 53 being printed only if the L/C is not available with ADV
                        actnoBicAdrTagXXX = swtPrtExtAccAdrAD(argTag, argPtsPta, argAcc);
                        break;
                    case "103":
                    case "202":
                    case "400":
                    case "752":
                    case "756":
                        actnoBicAdrTagXXX = swtPrtExtAccAdrAD(argTag, argPtsPta, argAcc);
                        break;
                    case "":
                        // no print of :53:
                        break;
                    default:
                        // (i.e. "T10" , "754", "700")
                        actnoBicAdrTagXXX = swtPrtExtAccAdrAD(argTag, argPtsPta, argAcc);
                }
                break;
            case "54":
                switch (argMt) {
                    case "103":
                    case "202":
                    case "202cv":
                    case "400":
                    case "752":
                    case "756":
                        if (MdaUtils.isEmpty(argPtsPta.getAdrblk())) {
                            if (!MdaUtils.isEmpty(argAcc)) {
                                actnoBicAdrTagXXX = new ActnoBicAdrTagXXX(argTag);
                                actnoBicAdrTagXXX.setPartyIdentifier(argAcc);
                            }
                        } else {
                            actnoBicAdrTagXXX = swtPrtExtAccAdrAD(argTag, argPtsPta, argAcc);
                        }
                        break;
                    case "":
                        // no print of :54:
                        break;
                    default:
                        actnoBicAdrTagXXX = swtPrtExtAccAdrAD(argTag, argPtsPta, argAcc);
                }
                break;
            case "55":
                // :55: is only available in sespay, mt103
                if (MdaUtils.isEmpty(argPtsPta.getNameAndAddress())) {
                    if (!MdaUtils.isEmpty(argAcc)) {
                        actnoBicAdrTagXXX = new ActnoBicAdrTagXXX(argTag);
                        actnoBicAdrTagXXX.setLocation(argAcc);
                    }
                } else {
                    actnoBicAdrTagXXX = swtPrtExtAccAdrAD(argTag, argPtsPta, argAcc);
                }
                break;
            case "56":
                // :56: is only available in sespay, mt103 and mt202
                if (MdaUtils.isEmpty(argPtsPta.getNameAndAddress())) {
                    if (!MdaUtils.isEmpty(argAcc)) {
                        actnoBicAdrTagXXX = new ActnoBicAdrTagXXX(argTag);
                        actnoBicAdrTagXXX.setPartyIdentifier(argAcc);
                    }
                } else {
                    actnoBicAdrTagXXX = swtPrtExtAccAdrAD(argTag, argPtsPta, argAcc);
                }
                break;
            case "57":
                switch (argMt) {
                    // :57C: is only available in sespay, mt103
                    case "103":
                        // Determine content of Tag 57c
                        String tag57C = "";
                        // In case no BIC for ADR is available try to print tag 57c. If BIC is available or Clearing Code is not available use old logic
                        if (MdaUtils.isEmpty(argPtsPta.getAdr().getBic())
                                && !MdaUtils.isEmpty(argPtsPta.getAdr().getClc())) {
                            tag57C = swtGetCLCfromCTY(argPtsPta.getAdr().getClc(), argPtsPta.getAdr().getLoccty());
                        }
                        if (!MdaUtils.isEmpty(tag57C)) {
                            actnoBicAdrTagXXX = new ActnoBicAdrTagXXX(argTag);
                            actnoBicAdrTagXXX.setPartyIdentifier(tag57C);
                        } else {
                            actnoBicAdrTagXXX = swtPrtExtAccAdrAD(argTag, argPtsPta, argAcc);
                        }
                        break;
                    case "202":
                    case "202cv":
                    case "400":
                    case "700":
                    case "720":
                    case "730":
                    case "754":
                    case "T05":
                    case "T10":
                        actnoBicAdrTagXXX = swtPrtExtAccAdrAD(argTag, argPtsPta, argAcc);
                        break;
                    case "756":
                        // no print of :57:
                        break;
                    case "710":
                        actnoBicAdrTagXXX = swtPrtExtAccAdrAD(argTag, argPtsPta, argAcc);
                        break;
                    default:
                        // in product version: 742, 750, x91 are handled in SWTPrtTag57Spc especially, all other MTs are printed via
                        // print SWTPrtExtAccAdrAD( ArgTag, ArgPtsPta, ArgAcc ) ;
                        actnoBicAdrTagXXX = swtPrtExtAccAdrAD(argTag, argPtsPta, argAcc);
                }
                break;
            case "58":
                switch (argMt) {
                    case "202":
                    case "202cv":
                    case "400":
                    case "742":
                    case "754":
                        actnoBicAdrTagXXX = swtPrtTag58Spc(argMt, argPtsPta, argAcc, null, null);
                        break;
                    default:
                        // (i.e. "705", "740")
                        actnoBicAdrTagXXX = swtPrtExtAccAdrAD(argTag, argPtsPta, argAcc);
                }
                break;
            case "59":
                actnoBicAdrTagXXX = swtPrtExtAccAdrAorWithoutLetter(argTag, argPtsPta, argAcc, argOptF);
                break;
            default:
                actnoBicAdrTagXXX = swtPrtExtAccAdrAD(argTag, argPtsPta, argAcc);
        }

        return actnoBicAdrTagXXX;
    }

    public ActnoBicAdrTagXXX swtPrtTag58Spc(
            String argMt, PtsptaVo argPtsPta, String argAcc, DoceotVo doceotVo, SetglgVo setglg) {
        ActnoBicAdrTagXXX actnoBicAdrTagXXX = null;
        switch (argMt) {
            case "742":
                if (StringUtils.isNotEmpty(argPtsPta.getPtainr()) && "BEB".equals(argPtsPta.getPts().getRol())) {
                    actnoBicAdrTagXXX = swtPrtAccAdrAD("58", argPtsPta);
                } else {
                    int issRow = setglgService.getSumtabRowForRole(setglg, "ISS");
                    if (issRow >= 0) {
                        String ptainr = setglg.getSetgll().get(issRow).getSetgrp().getApy().getPts().getPtainr();
                        if (ptainr != null && !ptainr.equals(doceotVo.getPtainr())) {
                            if (!isAccountTypNostro(setglg.getSetgll().get(issRow).getActrec().getTyp())) {
                                PtsptaVo actser = setglg.getSetgll().get(issRow).getSetgrp().getActser();
                                String inr = actser.getPta().getInr();
                                if (StringUtils.isNotEmpty(inr) && !inr.equals(SettleContext.getOwnPts().getPtainr())) {
                                    actnoBicAdrTagXXX = swtPrtExtAccAdrAD("58", actser, argAcc);
                                }
                            } else {
                                PtsptaVo acthol = setglg.getSetgll().get(issRow).getSetgrp().getActhol();
                                String inr = acthol.getPta().getInr();
                                if (StringUtils.isNotEmpty(inr) && !inr.equals(SettleContext.getOwnPts().getPtainr())) {
                                    actnoBicAdrTagXXX = swtPrtExtAccAdrAD("58", acthol, argAcc);
                                }
                            }
                        }
                    }
                }
                break;
            default:
                if (StringUtils.isEmpty(argPtsPta.getNameAndAddress())) {
                    if (StringUtils.isNotEmpty(argAcc)) {
                        actnoBicAdrTagXXX = new ActnoBicAdrTagXXX("58", argMt);
                        actnoBicAdrTagXXX.setPartyIdentifier(argAcc);
                    }
                } else {
                    actnoBicAdrTagXXX = swtPrtExtAccAdrAD("58", argPtsPta, argAcc);
                }
        }
        return actnoBicAdrTagXXX;
    }

    public boolean isAccountTypNostro(String typ) {
        return StringUtils.isNotEmpty(typ) && typ.startsWith("N");
    }

    /**
     * source:setmod.0116.script
     */
    public DcDateCurAmtTagXXX getSumFolFelByRolDsp(
            String argTag, SetfogVo setfogVo, SetfegVo setfegVo, String argRol, String argDsp) {
        String forCur;
        Argument<String> forCurBox = new Argument<>();
        BigDecimal forAmt;
        Argument<BigDecimal> forAmtBox = new Argument<>();
        setfogService.getCurForChgRolbyDsp(setfogVo, argRol, argDsp, forCurBox, forAmtBox);

        forCur = forCurBox.value;
        forAmt = forAmtBox.value;

        DcDateCurAmtTagXXX dcDateCurAmtTagXXX = new DcDateCurAmtTagXXX(argTag);
        // get own fees
        String feeCur;
        Argument<String> feeCurBox = new Argument<>();
        BigDecimal feeAmt;
        Argument<BigDecimal> feeAmtBox = new Argument<>();
        setfegService.getCurFeeRolbyDsp(setfegVo.getSetfel(), argRol, argDsp, feeCurBox, feeAmtBox);

        feeCur = feeCurBox.value;
        feeAmt = feeAmtBox.value;

        if (MdaUtils.isEmpty(forCur)) {
            dcDateCurAmtTagXXX.setCurrency(feeCur);
            dcDateCurAmtTagXXX.setAmount(feeAmt);
        }
        if (MdaUtils.isEmpty(feeCur)) {
            dcDateCurAmtTagXXX.setCurrency(forCur);
            dcDateCurAmtTagXXX.setAmount(forAmt);
        }
        if (!MdaUtils.isEmpty(forCur) && !MdaUtils.isEmpty(feeCur)) {
            if (MdaUtils.compareTo(forCur, feeCur) == 0) {
                dcDateCurAmtTagXXX.setCurrency(forCur);
                dcDateCurAmtTagXXX.setAmount(Decimals.add(forAmt, feeAmt));
            }
        }
        return dcDateCurAmtTagXXX;
    }


    /**
     * source:setmod.0185.script
     */
    public String swtGetCLCfromCTY(String argCLC, String argCty) {
        //! returns the SWIFT Clearing Code based on Countrycode and Clearing Code of ADR
        // ArgCLC holds the ClearingCode as stored in Field PtsPta\\ADR\\CLC
        // ArgCty holds the CountryCode of the relevant Address as stored in PtsPta\\ADR\\LOCTY
        String res = "";
        String swtclc = "";
        // detemine SWIFT Clearing Code Type based on Countrycode of ADR
        int cnt = 0;
        switch (argCty) {
            // normaly the Swift CLC Code equals the countrycode.
            case "AT":
            case "AU":
            case "ES":
            case "GR":
            case "HK":
            case "IE":
            case "IN":
            case "IT":
            case "NZ":
            case "PL":
            case "PT":
            case "RU":
            case "ZA":
            case "KR":
            case "LU":
                swtclc = argCty;
                // Swift CLC Code differs from CountryCode for the following countries
                break;
            case "DE": // Germany
                // Code "RT" Real Time Gross Settlement not suported in Tag 57C
                swtclc = "BL";
                break;
            case "CA": // Canada
                swtclc = "CC";
                break;
            case "US": // USA
                cnt = Strings.len(argCLC);
                switch (cnt) {
                    case 4:
                        swtclc = "CP";
                        break;
                    case 6:
                        swtclc = "CH";
                        break;
                    case 9:
                        swtclc = "FW";
                        break;
                    default:
                        // nothing to do as SWTCLC can not be identified
                }
                break;
            case "GB": // UK
                swtclc = "SC";
                break;
            case "CH": // Switzerland
                swtclc = "SW";
                break;
            default:
                // for all other countries no Swift CLC Code is available
        }
        if (!MdaUtils.isEmpty(swtclc)) {
            res = swtclc + argCLC;
        }
        return res;
    }

    public ActnoBicAdrTagXXX swtPrtTag24G(String delto, String deltoadr) {
        if (StringUtils.isNotEmpty(delto)) {
            String strPrintTxt = "";
            if (StringUtils.isNotEmpty(deltoadr)) {
                strPrintTxt = StringUtils.convertBlock(deltoadr, 12, 65);
            } else if (delto.equals("OTHR")) {
//                    messageIsInvalid( "No adresse specified for Tag 24G but code is \"OTHR\"" );
            }
            ActnoBicAdrTagXXX actnoBicAdrTagXXX = new ActnoBicAdrTagXXX("24");
            actnoBicAdrTagXXX.setCode(delto);//Code 4!c
            actnoBicAdrTagXXX.setAddress(strPrintTxt);//Address [12*65z]
            return actnoBicAdrTagXXX;
        }
        return null;
    }

    /**
     * source:gitdoc.0026.script
     */
    public String swtPrtTagPeriod(String argPerTyp, int argPerNbr, String argPerTxt) {
        // DNGDEV.001447
        if ("DAYS".equals(argPerTyp)) {
            return swtPrtTagApprul(argPerTyp, MdaUtils.toString(argPerNbr, -3));
        } else {
            return swtPrtTagApprul(argPerTyp, argPerTxt);
        }
    }

    /**
     * source:trndoc.0084.script
     */
    public String swtPrtTagApprul(String argApprul, String argApprulTxt) {
        //! prints Applicable Rule and (optional) App.rule text
        String apprul;
        if (StringUtils.isNotEmpty(argApprul)) {
            if (StringUtils.isEmpty(argApprulTxt)) {
                apprul = argApprul;
            } else {
                apprul = argApprul + "/" + argApprulTxt;
            }
            return apprul;
        }

        return null;
    }

    /**
     * source:gitdoc.0028.script
     */
    public ActnoBicAdrTagXXX swtPrtGISpecial(Gidgrp gidgrp, String argMT) {
        //! Returns formatted text for SWIFT tag/value combination for special cases
        //! Allows overriding the content for certain SWIFT tags inside this function
        //! ArgTag  : Tag to be printed
        //! ArgMT   : type of message
        //! ArgTagAndValueDefault: Default result as suggested by the product (incl. tag and content).
        //!                                  Return this value if the product default shall be used
        // DO5DZB.003683
        // returns ArgTagAndValueDefault, unless changed below
        // DNGDEV.001499
        // DNGDEV.002425 this rule shall only be used when the message is in the flow from the Applicant to the beneficiary (765 + 787 are in the reverse direction)
        String bchtyp = SettleContext.getUserSession().getBch().getBchtyp();
        switch (argMT) {
            case "759":
                if (gidgrp.getRec().getPurpos().equals("ISSU")) {
                    if (bchtyp.equals("4") || bchtyp.equals("5")) {
                        return swtPrtAccAdrAD("52", gidgrp.getIss());
                    } else {
                        return swtPrtAccAdrAD("52", SettleContext.getOwnPts());
                    }
                }
                if (gidgrp.getRec().getPurpos().equals("ADVI") || gidgrp.getRec().getPurpos().equals("ACNF")) {
                    return swtPrtAccAdrAD("52", gidgrp.getApl());
                }
                return swtPrtAccAdrAD("52", gidgrp.getIss());
            case "760":
            case "767":
            case "785":
            case "786":
                return swtPrtAccAdrAD("52", SettleContext.getOwnPts());
        }
        return null;

    }

    public ActnoBicAdrTagXXX swtPrtGISpecial(Nidgrp nidgrp, String argMT) {
        String bchtyp = SettleContext.getUserSession().getBch().getBchtyp();
        switch (argMT) {
            case "759":
                if (nidgrp.getRec().getPurpos().equals("ISSU")) {
                    if (bchtyp.equals("4") || bchtyp.equals("5")) {
                        return swtPrtAccAdrAD("52", nidgrp.getIss());
                    } else {
                        return swtPrtAccAdrAD("52", SettleContext.getOwnPts());
                    }
                }
                if (nidgrp.getRec().getPurpos().equals("ADVI") || nidgrp.getRec().getPurpos().equals("ACNF")) {
                    return swtPrtAccAdrAD("52", nidgrp.getApl());
                }
                return swtPrtAccAdrAD("52", nidgrp.getIss());
            case "760":
            case "767":
            case "785":
            case "786":
                // When PURPOS = ISSU, ISCO, ICCO -> Issuer = OWN, ADVI/ACNF ->APL
                if (nidgrp.getRec().getPurpos().equals("ISSU") || nidgrp.getRec().getPurpos().equals("ISCO") || nidgrp.getRec().getPurpos().equals("ICCO")) {
                    if (bchtyp.equals("4") || bchtyp.equals("5")) {
                        return swtPrtAccAdrAD("52", nidgrp.getIss());
                    } else {
                        return swtPrtAccAdrAD("52", SettleContext.getOwnPts());
                    }
                }
                if (nidgrp.getRec().getPurpos().equals("ADVI") || nidgrp.getRec().getPurpos().equals("ACNF")) {
                    return swtPrtAccAdrAD("52", nidgrp.getApl());
                }
                // DNGDEV.001807
                if (StringUtils.isEmpty(nidgrp.getRec().getPurpos()) && Strings.pos("FR FG", nidgrp.getRec().getHndtyp()) > 0) {
                    return swtPrtAccAdrAD("52", nidgrp.getApl());
                }
                break;
        }
        return null;
    }

    /**
     * source:trndoc.0087.script
     */
    public DcDateCurAmtTagXXX swtPrtTagAmount(String argTag, String argCur, BigDecimal argAmt) {
        if (StringUtils.isNotEmpty(argCur) && !argAmt.equals(BigDecimal.ZERO)) {
            DcDateCurAmtTagXXX dcDateCurAmtTagXXX = new DcDateCurAmtTagXXX(argTag);
            dcDateCurAmtTagXXX.setCurrency(argCur);
            dcDateCurAmtTagXXX.setAmount(argAmt.abs());
            return dcDateCurAmtTagXXX;
        } else {
            return null;
        }
    }

    public String getSendBic() {
        String bicCode = "";
        Bch bch = SettleContext.getUserSession().getBch();
        if (bch != null) {
           bicCode = bch.getSwfcod();
        }
        return bicCode;
    }

    public String linkStr(String str1, String str2, String linkCode) {
        if (StringUtils.isNotEmpty(str1)) {
            return com.brilliance.isc.utils.StringUtils.isEmpty(str2) ? str1 : str1 + linkCode + str2;
        } else {
            return "";
        }
    }

    public String printSwiftDate(Date date) {
        return date != null ? Utils.fmtDate(date, "yyMMdd") : null;
    }


    /**
     * 根据xxxgrp，直接获取 xxxgrp.getRec().getOwnref()
     *
     * @param obj xxxgrp，例如lidgrp，ledgrp
     * @return
     */
    public String swtPrtReference(Object obj) {
        String ownref = Utils.getFieldValue(obj, "rec//ownref");
        return StringUtils.isEmpty(ownref) ? "NONREF" : ownref;
    }

    /**
     * 根据xxxgrp，找到对应的role的reference信息
     *
     * @param xxxgrp xxxgrp，例如lidgrp，ledgrp
     * @param argRol role例如 "ISS","ADV"等
     * @return
     */
    public String swtPrtReference(Object xxxgrp, String argRol) {
        if (argRol.toUpperCase().equals("OWN")) {
            return swtPrtReference(xxxgrp);
        }
        PtsptaVo ptsptaVo = Utils.getFieldValue(xxxgrp, argRol.toLowerCase());
        String ref = (ptsptaVo != null ? ptsptaVo.getPts().getRef() : null);
        return StringUtils.isEmpty(ref) ? "NONREF" : ref;
    }

    /**
     * 根据当前的session context找到对应的Bo信息，然后再根据Bo找到对应的xxxgrp。
     * 得到xxxgrp，再查找对应的role的reference信息
     *
     * @param argRol role例如 "ISS","ADV"等
     * @return
     */
    public String swtPrtReference(String argRol) {
        String transName = SettleContext.getTransName();
        BaseTransactionVo transactionVo = transactionHelpService.getTransactionStoreSet().getTransactionVo();
        Object xxxgrp = null;
        String ref = "";
        if (transName.contains("GI") || transName.contains("GE") || transName.contains("GC")) {
            xxxgrp = Utils.getFieldValue(transactionVo, "gidgrp");
        } else if (transName.contains("NI") || transName.contains("NE") || transName.contains("NC")) {
            xxxgrp = Utils.getFieldValue(transactionVo, "nidgrp");
        } else {
            String xxgrpName = getXxxgrpName(transactionVo);
            xxxgrp = Utils.getFieldValue(transactionVo, xxgrpName);
        }
        if (argRol.toUpperCase().equals("OWN")) {
            ref = Utils.getFieldValue(xxxgrp, "rec//ownref");

        } else if (argRol.toUpperCase().equals("OTHMSG")) {
            FremsgVo fremsg = Utils.getFieldValue(transactionVo, "fremsg");
            ref = fremsg.getOthmsg().getPts().getRef();
        } else if (argRol.toUpperCase().equals("OTHCC")) {
            FremsgVo fremsg = Utils.getFieldValue(transactionVo, "fremsg");
            ref = fremsg.getOthcc().getPts().getRef();
        } else {
            PtsptaVo ptsptaVo = Utils.getFieldValue(xxxgrp, argRol.toLowerCase());
            ref = ptsptaVo != null ? ptsptaVo.getPts().getRef() : null;
        }
        return StringUtils.isEmpty(ref) ? "NONREF" : ref;
    }

    /**
     * source:trndoc.0038.script
     */
    public ActnoBicAdrTagXXX swtPrtFmtBlk(String argTag, String argField, int rows, int maxLength) {
        ActnoBicAdrTagXXX actnoBicAdrTagXXX = null;
        if (StringUtils.isNotEmpty(argField)) {
            actnoBicAdrTagXXX = new ActnoBicAdrTagXXX(argTag);
            actnoBicAdrTagXXX.setNarrative(StringUtils.convertBlock(argField, rows, maxLength));
        }
        return actnoBicAdrTagXXX;
    }

    /**
     * source:trndoc.0119.script
     */
    public DcDateCurAmtTagXXX swtPrtTagAmountABK(
            String argTag, String argTagOption, String argDocCur, BigDecimal argDocAmt, Date argMatDat,
            int argMatPerCnt, String argMatPerBeg, String argMatPerTyp, String argDocTypCod) {
        DcDateCurAmtTagXXX dcDateCurAmtTagXXX = new DcDateCurAmtTagXXX(argTag);
        // Method to Print Swift Tag 32a / 33a
        // ArgTagOption indicates which options are allowed, `AB` means A and B are allowed.
        //! Corresponding functions: SWTPrtTagAmount, SWTPrtTagAmountAB, SWTPrtTagAmountNul
        String matPerCntTxt = MdaUtils.toString(argMatPerCnt, -3);
        String matDatTxt = Utils.fmtDateSwift(argMatDat);
        String type = "";
        if (MdaUtils.isEmpty(argMatPerTyp)) {
            type = "D";
        } else {
            type = argMatPerTyp;
        }
        if (!MdaUtils.isEmpty(argTag)) {
            if (!MdaUtils.isEmpty(argMatDat)) {
                dcDateCurAmtTagXXX.setDate(matDatTxt);
                dcDateCurAmtTagXXX.setCurrency(argDocCur);
                dcDateCurAmtTagXXX.setAmount(argDocAmt);
            } else {
                // option K if Start of Maturity Period is set
                if (!MdaUtils.isEmpty(argMatPerBeg)) {
                    dcDateCurAmtTagXXX.setDayMonth(type);
                    dcDateCurAmtTagXXX.setNumberOfDaysMonths(matPerCntTxt);
                    dcDateCurAmtTagXXX.setCode(argMatPerBeg);
                    dcDateCurAmtTagXXX.setCurrency(argDocCur);
                    dcDateCurAmtTagXXX.setAmount(argDocAmt);
                } else {
                    if (Strings.pos(argTagOption, "K") > 0 && (MdaUtils.compareTo(argDocTypCod, "M") != 0)) {
                        dcDateCurAmtTagXXX.setDayMonth(type);
                        dcDateCurAmtTagXXX.setNumberOfDaysMonths(matPerCntTxt);
                        dcDateCurAmtTagXXX.setCode("ST");
                        dcDateCurAmtTagXXX.setCurrency(argDocCur);
                        dcDateCurAmtTagXXX.setAmount(argDocAmt);
                    } else {
//                        tag = tag + "B:";
                        dcDateCurAmtTagXXX.setCurrency(argDocCur);
                        dcDateCurAmtTagXXX.setAmount(argDocAmt);
                    }
                }
            }
        }
        return dcDateCurAmtTagXXX;
    }

    public boolean checkIfAnyFeeSettled(String rol, List<SetfelVo> setfelVos) {
        boolean found = false;
        if (setfelVos.size() > 0) {
            for (SetfelVo setfelVo : setfelVos) {
                if (setfelVo.getDsp() != null && setfelVo.getDsp().equals("X")) {
                    if (setfelVo.getRol().equals(rol)) {
                        found = true;
                    }
                }
            }
        }
        return found;
    }

    public boolean checkIfAnyFeeSettledDsp(String rol, String dsp, List<SetfelVo> setfelVos) {
        boolean found = false;
        if (setfelVos.size() > 0) {
            for (SetfelVo setfelVo : setfelVos) {
                if (setfelVo.getDsp() != null && setfelVo.getDsp().equals(dsp)) {
                    if (setfelVo.getRol() != null && setfelVo.getRol().equals(rol)) {
                        found = true;
                    }
                }
            }
        }
        return found;
    }

    public String getActforTAG72(String rol, List<SetgllVo> setgllVos) {
        String act = "";
        if (setgllVos.size() > 0) {
            for (int i = 0; i < setgllVos.size(); i++) {
                SetgllVo setgllVo = setgllVos.get(i);
                if (!setgllVo.getDsp().equals("DAD") && !setgllVo.getDsp().equals("HLD")) {
                    if (i == 0) {
                        act = setgllVo.getAct();
                    } else {
                        act += "\n" + setgllVo.getAct();
                    }
                }
            }
        }
        return act;
    }

    public boolean isRolSet(PtsptaVo ptsptaVo) {
        String flg = ptsptaVo.getRolsetflg();
        return "Y".equals(flg);
    }

    public ActnoBicAdrTagXXX swtPrtTag72(String tagValue) {
        ActnoBicAdrTagXXX actnoBicAdrTagXXX = new ActnoBicAdrTagXXX("72");
        actnoBicAdrTagXXX.setNarrative(StringUtils.convertBlock(tagValue, 6, 35));
        return actnoBicAdrTagXXX;
    }

    public String swtPrtTag44J(String countryCode, String countrySubDivision, String narrative) {
        if (StringUtils.isNotEmpty(narrative)) {
            return swtPrtTagApprul(countryCode, countrySubDivision) + "\n" + "/" + narrative;
        } else {
            return swtPrtTagApprul(countryCode, countrySubDivision);
        }
    }

    /**
     * GID, DCD请参考td传参
     *
     * @param tag
     * @param ptsptaVo
     * @param avbwth
     * @param avbby
     * @param avbwthtxt
     * @return
     */
    public ActnoBicAdrTagXXX swtPrtAvbWith(
            String tag, PtsptaVo ptsptaVo, String avbwth, String avbby, String avbwthtxt) {
        if (ptsptaVo == null) {
            return null;
        }
        ActnoBicAdrTagXXX actnoBicAdrTagXXX = new ActnoBicAdrTagXXX(tag);
        if (!MdaUtils.isEmpty(avbby)) {
            avbby = codetableService.getTblLabel(avbby, "AVBBY0");
        }
        if (!MdaUtils.isEmpty(avbwthtxt) || !MdaUtils.isEmpty(ptsptaVo.getRolsetflg())) {
            if ("O".equals(avbwth)) {
                if (MdaUtils.isEmpty(avbwthtxt)) {
                    avbwthtxt = codetableService.getTblLabel(avbby, "AVBWTH");
                }
                actnoBicAdrTagXXX.setAddress(StringUtils.convertBlock(avbwthtxt, 4, 35));
            } else {
                actnoBicAdrTagXXX = this.swtPrtAccAdrAD(tag, ptsptaVo);
                String adr = actnoBicAdrTagXXX.getAddress();
                if (!ptsptaVo.getPts().getExtkey().startsWith("9999") && !ptsptaVo.getPts().getExtkey().startsWith("Temp")) {
                    adr = adr + "\n" + avbby;
                }
                actnoBicAdrTagXXX.setAddress(adr);
            }
        }
        actnoBicAdrTagXXX.setCode(avbby);
        return actnoBicAdrTagXXX;
    }

    /**
     * 根据 transactionBo，找到相应的grp的field，
     * 例如 LetopnStoreBo对应的xxxgrp就是ledgrp
     *
     * @param transactionBo
     * @return
     */
    private String getXxxgrpName(Object transactionBo) {
        // 如果为null，直接返回null
        if (transactionBo == null) {
            return null;
        }

        String xxgrpName = null;
        Field[] fields = transactionBo.getClass().getDeclaredFields();
        for (Field field : fields) {
            // 长度为6，且已grp结尾，例如ledgrp，lidgrp等
            if (field.getName().length() == 6 && field.getName().endsWith("grp")) {
                xxgrpName = field.getName();
            }
        }
        return xxgrpName;
    }
}
