package com.brilliance.isc.common.transaction.controller;

import cn.hutool.core.collection.CollectionUtil;
import com.brilliance.isc.bo.*;
import com.brilliance.isc.common.api.bch.service.BchService;
import com.brilliance.isc.common.authority.ITrnCodService;
import com.brilliance.isc.common.authority.TrnCodeAuthorityComplex;
import com.brilliance.isc.common.authority.TrnCodeAuthorityService;
import com.brilliance.isc.common.cache.atpbch.AtpBchCacheService;
import com.brilliance.isc.common.cache.pta.PtaCacheService;
import com.brilliance.isc.common.codetable.service.CodetableService;
import com.brilliance.isc.common.component.DyncDaoService;
import com.brilliance.isc.common.component.SptDataComponent;
import com.brilliance.isc.common.context.SettleContext;
import com.brilliance.isc.common.context.SpringEnvContext;
import com.brilliance.isc.common.doc.ITransactionDocSet;
import com.brilliance.isc.common.doc.TextResultVo;
import com.brilliance.isc.common.lock.BizLocker;
import com.brilliance.isc.common.lock.LockInfo;
import com.brilliance.isc.common.lock.common.BizCommonLocker;
import com.brilliance.isc.common.lock.common.BizRepeatComponent;
import com.brilliance.isc.common.ordmod.vo.OrdStaStatus;
import com.brilliance.isc.common.sysmod.SysmodService;
import com.brilliance.isc.common.transaction.TransactionService;
import com.brilliance.isc.common.transaction.TransactionServiceFactory;
import com.brilliance.isc.common.transaction.help.loadcontext.ITransactionLoadContext;
import com.brilliance.isc.common.transaction.vo.BaseTransactionVo;
import com.brilliance.isc.common.transaction.vo.TrnInfo;
import com.brilliance.isc.common.trndoc.vo.DoceotVo;
import com.brilliance.isc.common.util.StringUtils;
import com.brilliance.isc.constant.ErrorCode;
import com.brilliance.isc.exception.RestBizException;
import com.brilliance.isc.mda.dao.*;
import com.brilliance.isc.transfer.IStructMapper;
import com.brilliance.isc.vo.ResponseSet;
import com.brilliance.isc.vo.TextRequestVo;
import com.brilliance.isc.vo.TrnCodeQueryVo;
import com.brilliance.isc.vo.TrncodVo;
import com.brilliance.isc.warn.WarnService;
import com.brilliance.isc.warn.impl.WarnServiceImpl;
import com.brilliance.mda.runtime.mda.util.MdaUtils;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StopWatch;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import javax.annotation.Resource;
import javax.ws.rs.QueryParam;
import java.util.*;
import java.util.stream.Collectors;

public class AbstractTransactionController<V extends BaseTransactionVo> {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Resource
    private TransactionServiceFactory transactionServiceFactory;

    @Resource
    private SysmodService sysmodService;

    @Resource
    private PtaCacheService ptaCacheService;

    @Resource
    private TrnMapper trnMapper;

    @Resource
    private BchService bchService;

    @Resource
    private WarnService warnService;

    @Resource
    private SptMapper sptMapper;

    @Resource
    private OrdMapper ordMapper;

    @Resource
    private OreMapper oreMapper;

    @Resource
    private DiccodeMapper diccodeMapper;

    @Resource
    private SptDataComponent sptDataComponent;

    @Resource
    private BizRepeatComponent bizRepeatComponent;

    @Resource
    private BizCommonLocker bizCommonLocker;

    @Resource
    private BizLocker bizLocker;

    @Autowired
    @Qualifier("ceb")
    private ITransactionLoadContext transactionLoadContext;

    @Autowired(required = false)
    TrnCodeAuthorityService trnCodeAuthorityService;

    @Autowired(required = false)
    private ITrnCodService iTrnCodService;

    @Resource
    private TrnCodeAuthorityComplex trnCodeAuthorityComplex;

    @Autowired
    private AtpBchCacheService atpBchCacheService;

    @Autowired
    private DyncDaoService dyncDaoService;

    @Autowired
    private CodetableService codetableService;

    public IStructMapper getStructMapper() {
        return null;
    }

    /**
     * 初始数据
     *
     * @param vo
     * @return ResponseSet<V>
     */
    @PostMapping("/init")
    @ApiOperation("初始数据")
    public ResponseSet<V> init(@RequestBody V vo) {
        SettleContext.setInitTransSta();
        StopWatch stopWatch = new StopWatch(vo.getTransName()+"交易数据初始化");
        String transName = vo.getTransName();
        logger.info("进入{}交易controller初始化", transName);
        TransactionService transactionService = transactionServiceFactory.getTransactionService(transName.toLowerCase());
        //转换成Bo
        stopWatch.start("Vo转换为Bo");
        BaseTransactionVo bo = (BaseTransactionVo) getStructMapper().voTransferToBo(vo);
        stopWatch.stop();
        //加载上下文信息
        transactionLoadContext.loadContext(bo);
        //进入初始化
        if(bo.getBusinessType()==null)
            bo.setBusinessType("");
        boolean showCheckVersion = false;
        switch(bo.getBusinessType()){
            case "SPT":
                stopWatch.start("Spt读取与锁定");
                Spt spt =sptMapper.getSptByInr(bo.getBusinessInr());
                if(spt==null){
                    throw new RestBizException(ErrorCode.BIZ_STATE_CHANGE,"当前经办数据(编号："+bo.getBusinessInr()+")无法找到，可能已被处理，请至其他队列查找。");
                }
                String isCheck = codetableService.getTblKey("check","CHKBTN");
                if(MdaUtils.equals(isCheck,"Y")) {
                    //校验数据是否合法可操作
//                trnCodeAuthorityComplex.validateTrnCode(spt.getObjinr(),spt.getObjtyp(),transName);
                    //待办夹进交易时判断交易是否可进入（走交易入口按钮亮灰显逻辑 ）,总行经办不走，来报objtyp和objinr可能为空 不走
                    Bch bchTemp = SettleContext.getUserSession().getOrgBch();
                    if (!MdaUtils.equals(bchTemp.getLev(), "0") && !MdaUtils.isEmpty(spt.getObjtyp()) && !MdaUtils.isEmpty(spt.getObjinr())) {
                        TrnCodeQueryVo trnCodeQueryVo = new TrnCodeQueryVo();
                        trnCodeQueryVo.setInr(spt.getObjinr());
                        trnCodeQueryVo.setType(spt.getObjtyp().substring(0, 2));
                        trnCodeQueryVo.setBranch(SettleContext.getUserSession().getBch().getBranch());
                        //起头交易退回时，主表为空，无法查询到数据，不走此逻辑
                        Map<String, Object> map = dyncDaoService.dyncReadByInr(spt.getObjtyp().length() == 3 ? spt.getObjtyp() : spt.getObjtyp().substring(0, 3), spt.getObjinr());
                        //iTrnCodService为null则该业务下未实现此接口，不走此逻辑
                        if (!MdaUtils.isEmpty(map) && !Objects.isNull(iTrnCodService)) {
                            List<TrncodVo> trnCodVos = iTrnCodService.dealWithByInr(trnCodeQueryVo);
                            if (!Objects.isNull(trnCodVos)) {
                                List<TrncodVo> trncodVosTemp = trnCodVos.stream().filter(trncodVo -> MdaUtils.equals(trncodVo.getInifrm().toUpperCase(), transName.toUpperCase())).collect(Collectors.toList());
                                if (trncodVosTemp.size() == 1) {
                                    if (MdaUtils.equals(trncodVosTemp.get(0).getIsAllowed(), "N")) {
                                        throw new RestBizException(ErrorCode.BIZ_STATE_CHANGE, "无法进入当前业务交易:" + trncodVosTemp.get(0).getDisResult());
                                    }
                                }
                            }
                        }
                    }
                }
                //先锁定spt
                if(!"view".equalsIgnoreCase(vo.getOperation())) {
                    bizCommonLocker.lockSpt(spt, bo);
                }
                stopWatch.stop();
                if(sptDataComponent.needMergeSptData(spt.getSta()) && !"X".equals(spt.getHldflg())){
                    logger.info("加载数据");
                    stopWatch.start("加载Spt文件数据");
                    bo = sysmodService.sptLoadData(bo.getClass(), vo.getBusinessInr());
                    logger.info("进入Spt报文交易Service初始化");
                    bo.setSpt(spt);
                    stopWatch.stop();
                    stopWatch.start(transName+"交易Service初始化");
                    bo = transactionService.init(bo);
                    stopWatch.stop();
                }else{
                    if (sptDataComponent.hasSptButNoSptFile(spt)) {
                        //来报数据但是没有来报文件，需要走交易初始化
                        logger.info("当前数据交易的init()初始化加载");
                        stopWatch.start("加载" + transName + "init()初始化方法");
                        bo.setSpt(spt);
                        bo = transactionService.init(bo);
                        logger.info("数据初始化完成");
                        stopWatch.stop();
                    } else {
                        logger.info("当前数据从SPT读取，vo.businessInr:{}", vo.getBusinessInr());
                        stopWatch.start("加载" + transName + "Spt文件数据");
                        bo = sysmodService.sptLoadData(bo.getClass(), vo.getBusinessInr());
                        bo.setSpt(spt);
                        logger.info("SPT数据加载完成");
                        showCheckVersion = true;
                        stopWatch.stop();
                    }
                }
                //总行上收的待办，交易码还是收单行的，需要更正
                bo.setTransName(vo.getTransName());
                //分行业务待经办默认需要初始化经办柜员（解决rerouting更换经办柜员）
                if(!"X".equals(spt.getHldflg())) {
                    bo = transactionService.initUsrcon(bo);
                }
                //设置一些交易相关的信息给前端
                updateTrnInfo(bo,spt);
                if(showCheckVersion){
                    //检查版本号，避免数据被覆盖
                    boolean changed = transactionService.checkReload(bo);
                    if(changed){
                        logger.info("当前SPT的业务模型发生变化，vo.businessInr:{}", vo.getBusinessInr());
                    }
                }
                break;
            case "TRN":
                //加载交易快照文件数据
                logger.info("当前数据从快照读取，trnInr:{}", vo.getBusinessInr());
                Trn trn = new Trn();
                trn.setInr(bo.getBusinessInr());
                //浏览模式不要加锁
                if(!"view".equalsIgnoreCase(vo.getOperation())) {
                    bizCommonLocker.lockTrn(trn, bo);
                }
                trn = trnMapper.selectByPrimaryKey(trn);
                bo = sysmodService.streamGetNameInSubDir(bo.getClass(), trn.getInr());
                updateTrnInfo(bo,trn);
                logger.info("快照加载完成，trnInr:{}", vo.getBusinessInr());
                break;
            default:
                //如果是由入口直接进入交易，尝试判断数据是否可操作
//                trnCodeAuthorityComplex.validateTrnCode(vo);
                logger.info("进入交易Service初始化");
                stopWatch.start(transName+"交易Service初始化");
                bo = transactionService.init(bo);
                stopWatch.stop();
        }
        //快照模式和预览模式不要锁业务
        if(!"TRN".equals(vo.getBusinessType()) && !"view".equalsIgnoreCase(vo.getOperation())){
            //非快照交易，初始化完成，进行锁定
            bizCommonLocker.lockTransBo(bo);
            logger.debug("锁定交易数据完成");
            //保函修改交易在前一笔修改和修改确认未完成复核时给出提示
//            if(vo.getTransName().toUpperCase().contains("AME") && !Objects.equals(
//                    SettleContext.getSessionUserVo().getWorkOrg(),"1000")) {
//                SimpleModuleVo simpleModuleVo = trnCodeAuthorityComplex.getSimpleVo(vo);
//               String errMsg = trnCodeAuthorityService.isTrnAmeAllowed(simpleModuleVo.getObjtyp(), simpleModuleVo.getObjinr(), vo.getTransName());
//                if(Strings.notEmpty(errMsg)){
//                    return new ResponseSet(ErrorCode.NSDH_NOTALLOWED,errMsg);
//                }
//            }
            }
        //更新当前交易唯一号
        updateTrnUniqueNo(bo);

        //转换成Vo
        stopWatch.start(transName+" Bo转换成Vo");
        V rtnVo = (V) getStructMapper().boTransferToVo(bo);
        if(ObjectUtils.isEmpty(rtnVo.getWarnList())){
            rtnVo.setWarnList(WarnServiceImpl.directGetAndClearTotalWarns());
        }else{
            rtnVo.getWarnList().addAll(WarnServiceImpl.directGetAndClearTotalWarns());
        }
        stopWatch.stop();
        logger.info(stopWatch.prettyPrint());
        return ResponseSet.simpleSuccess(rtnVo);
    }

    private void updateTrnUniqueNo(BaseTransactionVo bo){
        if(bo.getTrnInfo() == null){
            bo.setTrnInfo(new TrnInfo());
        }
        //设置一个唯一编号，用于提交时防重
        bo.getTrnInfo().setFormNo(UUID.randomUUID().toString());
    }

    private void updateTrnInfo(BaseTransactionVo bo,Spt spt){
        String ordInr = spt.getOrdinr();
        if(bo.getTrnInfo() == null){
            bo.setTrnInfo(new TrnInfo());
        }
        bo.getTrnInfo().setSptHldflg(spt.getHldflg());
        bo.getTrnInfo().setSptMsgtyp(spt.getMsgtyp());

        if(!MdaUtils.isEmpty(ordInr)){
            Ord ord = ordMapper.selectByOrdInr(ordInr);
            if(ord != null){
                bo.getTrnInfo().setSdhflg(ord.getSdhflg());
                List<Ore> oreList=new ArrayList<>();
                Ore ore=oreMapper.selectOneByOrdinrAndTyp(ord.getInr(),OrdStaStatus.MAN.getValue());
                if(ore!=null){
                    oreList.add(ore);
                }
                //追加手工录入备注数据
                List<Ore> addoreList=oreMapper.selectOneByOrdinrAndTypList(ord.getInr(),OrdStaStatus.ADD.getValue());
                if(addoreList!=null && addoreList.size()>0){
                    oreList.addAll(addoreList);
                }
                bo.getTrnInfo().setOreList(oreList);
            }
        }
    }

    private void updateTrnInfo(BaseTransactionVo bo,Trn trn){
        if(bo.getTrnInfo() == null){
            bo.setTrnInfo(new TrnInfo());
        }
        List<Ore> oreList=new ArrayList<>();
            Ore ore=oreMapper.selectOneByOrdinrAndTyp(trn.getOrdinr(),OrdStaStatus.MAN.getValue());
            if(ore!=null){
                oreList.add(ore);
        }
        //追加手工录入备注数据
        List<Ore> addoreList=oreMapper.selectOneByOrdinrAndTypList(trn.getOrdinr(),OrdStaStatus.ADD.getValue());
        if(addoreList!=null && addoreList.size()>0){
            oreList.addAll(addoreList);
        }
        bo.getTrnInfo().setOreList(oreList);
        bo.getTrnInfo().setTrninr(trn.getInr());
    }


    /**
     * 数据校验
     *
     * @param vo
     * @return ResponseSet<V>
     */
    @PostMapping("/checkAll")
    @ApiOperation("数据校验")
    public ResponseSet<V> checkAll(@RequestBody V vo) {
        SettleContext.setCheckTransSta();
        String transName = vo.getTransName();
        StopWatch stopWatch = new StopWatch(transName+"交易校验");
        logger.info("进入{}交易校验", transName);
        TransactionService transactionService = transactionServiceFactory.getTransactionService(transName.toLowerCase());
        //转换得到Bo
        BaseTransactionVo bo = voUpdateNewBo(vo,stopWatch);
        warnService.putWarnList(MdaUtils.deepClone(bo.getWarnList()));
        //开始校验
        try {
            return ResponseSet.simpleSuccess(transactionService.checkAll(bo));
        }finally {
            logger.info(stopWatch.prettyPrint());
        }
    }

    /**
     * 数据暂存
     *
     * @param vo
     * @return ResponseSet<V>
     */
    @PostMapping("/txnHold")
    @ApiOperation("数据暂存")
    public ResponseSet<V> txnHold(@RequestBody V vo) {
        SettleContext.setHoldTransSta();
        String transName = vo.getTransName();
        logger.info("进入{}交易暂存", transName);
        StopWatch stopWatch = new StopWatch(transName+"交易暂存");
        //加入锁定，防止重复提交
        bizRepeatComponent.checkAndSetRepeatLock(vo);
        try {
            TransactionService transactionService = transactionServiceFactory.getTransactionService(transName.toLowerCase());
            //转换得到Bo
            BaseTransactionVo bo = voUpdateNewBo(vo,stopWatch);
            return ResponseSet.simpleSuccess(transactionService.txnHold(bo));
        }catch (Exception e){
            //发生异常需要释放锁定
            bizRepeatComponent.releaseRepeatLock(vo);
            throw e;
        }finally {
            logger.info(stopWatch.prettyPrint());
        }
    }


    /**
     * 动态获取码表值
     *
     * @param params
     * @return ResponseSet<V>
     */
    @PostMapping("/getDiffCodeTable")
    @ApiOperation("动态获取码表值")
    public ResponseSet<Map<String, List<DicCode>>> getDiffCodeTable(@RequestBody Map<String, Object> params) {
        // 获取传递的交易码
        String transName = params.get("transName").toString();
        // 获取传递的dbcode值
        String dbCode = params.get("dbCode").toString();
        if (StringUtils.isEmpty(dbCode)) {
            return ResponseSet.simpleSuccess(new HashMap<String, List<DicCode>>());
        }
        // 从数据库中获取码表值
        List<DicCode> list = diccodeMapper.listAllByType(dbCode);
        if (CollectionUtil.isEmpty(list)) {
            return ResponseSet.simpleSuccess(new HashMap<String, List<DicCode>>());
        }
        /*TransactionService transactionService = transactionServiceFactory.getTransactionService(transName.toLowerCase());
        return ResponseSet.simpleSuccess(transactionService.getDiffCodeTable(params,list));*/
        return null;
    }

    /**
     * save存盘
     *
     * @param vo
     * @return ResponseSet<V>
     */
    @PostMapping("/save")
    @ApiOperation("save存盘")
    public ResponseSet<V> save(@RequestBody V vo) {
        String transName = vo.getTransName();
        StopWatch stopWatch = new StopWatch(transName+"交易保存");

        //检查锁定，防止重复提交
        bizRepeatComponent.checkAndSetRepeatLock(vo);
        //检查完毕
        try {
            SettleContext.setSavTransSta();
            logger.info("进入{}交易保存", transName);
            TransactionService transactionService = transactionServiceFactory.getTransactionService(transName.toLowerCase());
            //转换得到Bo
            BaseTransactionVo bo = voUpdateNewBo(vo,stopWatch);
            stopWatch.start("锁定Spt");
            stopWatch.stop();
            warnService.putWarnList(bo.getWarnList());
            stopWatch.start(transName+"交易Service保存");
            return ResponseSet.simpleSuccess(transactionService.saveTransaction(bo));
        }
        catch (Exception e){
            //发生异常需要释放锁定
            bizRepeatComponent.releaseRepeatLock(vo);
            throw e;
        }
        finally {
            stopWatch.stop();
            logger.info(stopWatch.prettyPrint());
        }
    }

    /**
     * 获取编号
     *
     * @param params
     * @return ResponseSet<String>
     */
    @PostMapping("/getOwnRef")
    @ApiOperation("获取编号")
    public ResponseSet<String> getOwnRef(@RequestBody Map<String, String> params) {
        String ownref = "";
        String ptainr = params.get("ptainr");
        String businessType = params.get("businessType");
        String tbl = params.get("tbl");
        Pta pta = ptaCacheService.getPtaByInr(ptainr);
        Bch wrkbch = null;
        if (pta != null) {
            //调用bchservice，可从缓存中获取避免重复读取数据库
            wrkbch = bchService.getByBchInr(pta.getBranchinr());
            if (wrkbch != null) {
                ownref = sysmodService.getOwnRef(wrkbch, businessType, tbl);
            }
        }
        return ResponseSet.simpleSuccess(ownref);
    }

    /**
     * 将Vo组合给Bo，尤其后手交易需要用，这样安全性、可靠性统一起来
     * 如果有特殊情况，可以重写，不要拘泥！！！
     *
     * @param vo 前端给的Vo
     * @return 更新组合好Vo的Bo
     */
    public BaseTransactionVo voUpdateNewBo(V vo,StopWatch stopWatch) {
        String transName = vo.getTransName();
        logger.info("{}交易开始转换vo至bo", transName);
        TransactionService transactionService = transactionServiceFactory.getTransactionService(transName.toLowerCase());
        //转换成Bo
        BaseTransactionVo bo = (BaseTransactionVo) getStructMapper().voTransferToBo(vo);
        logger.info("{}交易完成转换vo至bo", transName);
        //加载上下文
        transactionLoadContext.loadContext(bo);
        if(vo.getSpt() != null && !MdaUtils.isEmpty(vo.getSpt().getInr())) {
            stopWatch.start("加载SPT记录");
            Spt spt = sptMapper.getSptByInr(vo.getSpt().getInr());
            if (spt == null) {
                throw new RestBizException(ErrorCode.BIZ_STATE_CHANGE,"当前经办数据(编号："+vo.getSpt().getInr()+")无法找到，可能已被处理，请至其他队列查找。");
            }
            //校验数据是否合法可操作
            //先不打开
//            trnCodeAuthorityComplex.validateTrnCode(spt.getObjinr(),spt.getObjtyp(),transName);
            stopWatch.stop();
            logger.info("当前数据从SPT读取，vo.businessInr:{}", spt.getInr());
            if(sptDataComponent.needMergeSptData(spt.getSta())){
                logger.info("进入报文交易Service初始化");
                stopWatch.start("加载" + transName + " Spt文件数据");
                bo = sysmodService.sptLoadData(bo.getClass(), spt.getInr());
                bo.setSpt(spt);
                stopWatch.stop();
                stopWatch.start(transName+" service 来报加载初始化");
                bo.setTransName(transName);
                bo = transactionService.init(bo);
                stopWatch.stop();
            }else{
                if(!sptDataComponent.hasSptButNoSptFile(spt)) {
                    stopWatch.start("加载" + transName + " Spt文件数据");
                    bo = sysmodService.sptLoadData(bo.getClass(), spt.getInr());
                    logger.info("SPT数据加载完成");
                    stopWatch.stop();
                    //检查版本号，避免数据被覆盖
                    boolean changed = transactionService.checkReload(bo);
                    if(changed){
                      logger.info("当前SPT的业务模型发生变化，vo.businessInr:{}", vo.getBusinessInr());
                    }
                }
                getStructMapper().voUpdateToBo(vo, bo);
                bo.setSpt(spt);
                logger.info("从VO更新数据至SPT BO数据更新完成");
            }
            getStructMapper().voUpdateToBo(vo, bo);
            logger.info("BO数据更新完成");
            return bo;
        }

        //如果是由入口直接进入交易，尝试判断数据是否可操作
        //先不打开
        //trnCodeAuthorityComplex.validateTrnCode(vo);
        //从数据库加载出Bo
        logger.info("从交易Service的初始化里加载数据");
        stopWatch.start(transName+" service 一般加载初始化");
        bo = transactionService.init(bo);
        stopWatch.stop();
        logger.info("从交易Service的初始化里加载数据完成");

        //Vo拷贝到Bo
        getStructMapper().voUpdateToBo(vo, bo);
        logger.info("BO数据更新完成");
        //返回更新好的Bo
        return bo;
    }

    /**
     * 面函预览。要求每个交易实现一个TransactionDocSet
     * 用【交易码.docset】命名
     *
     * @param vo  交易Vo，提供数据
     * @param idx 当前要预览那个条目的面函
     * @return ResponseSet<TextResultVo>
     */
    @PostMapping("/showDocs")
    public ResponseSet<TextResultVo> showDocs(@RequestBody V vo, @QueryParam("idx") int idx) {
        SettleContext.setViewDocTransSta();
        String transName = vo.getTransName();
        StopWatch stopWatch = new StopWatch(transName+"报文/面函预览"+idx);
        logger.info("预览{}面函报文数据，索引:{}", transName, idx);
        //转换得到Bo
        BaseTransactionVo bo = voUpdateNewBo(vo,stopWatch);
        ITransactionDocSet transactionDocSet = SpringEnvContext.getBean(atpBchCacheService.getSdTransNameForRegister().toLowerCase() + ".docset");
        DoceotVo doceotVo = bo.getDoceot().get(idx);
        logger.info("面函信息role:{},docNam:{},corTyp:{}", doceotVo.getRole(), doceotVo.getDocnam(), doceotVo.getCortyp());
        stopWatch.start("生成报文/面函");
        TextResultVo textResultVo = transactionDocSet.outputMessage(bo, doceotVo);
        stopWatch.stop();
        logger.info("格式Format:{}", textResultVo.getFormat());
        logger.info(stopWatch.prettyPrint());
        return ResponseSet.simpleSuccess(textResultVo);
    }

    /**
     * 显示文本请求。要求每个交易实现一个显示文本的函数
     *
     * @param textRequestVo  交易Vo，模板、变量与路径映射的合体，提供数据
     * @return ResponseSet<Text>
     */
    @PostMapping("/showText")
    public ResponseSet<String> showText(@RequestBody TextRequestVo<V> textRequestVo) {
        SettleContext.setViewTextTransSta();
        String transName = textRequestVo.getVo().getTransName();
        StopWatch stopWatch = new StopWatch(transName+"文本预览");

        logger.info("预览{}文本数据", transName);
        //转换得到Bo
        BaseTransactionVo bo = voUpdateNewBo(textRequestVo.getVo(),stopWatch);
        TransactionService transactionService = transactionServiceFactory.getTransactionService(transName.toLowerCase());
        String text= transactionService.convertText(textRequestVo.getTemplate(),textRequestVo.getFieldMap(),bo);
//        if("nitopn".equalsIgnoreCase(bo.getTransName()) || "nitpop".equalsIgnoreCase(bo.getTransName())){
//            text = transactionService.convertTextExceType(textRequestVo.getTemplate(),textRequestVo.getFieldMap(),bo);
//        }else{
//            text = transactionService.convertText(textRequestVo.getTemplate(),textRequestVo.getFieldMap(),bo);
//        }
        logger.info("转换完毕:{}", text);
        logger.info(stopWatch.prettyPrint());
        return ResponseSet.simpleSuccess(text);
    }




    /**
     * save存盘
     *
     * @param vo
     * @return ResponseSet<V>
     */
    @PostMapping("/exit")
    @ApiOperation("交易退出")
    public ResponseSet<Boolean> exit(@RequestBody V vo) {
        if(SettleContext.getSessionUserVo() == null){
            logger.info("用户已退出，将会通过退出请求解锁");
            return ResponseSet.simpleSuccess(false);
        }
        String transName = vo.getTransName();
        StopWatch stopWatch = new StopWatch(transName+"退出");
        logger.info("进入{}交易退出", transName);
        //解锁当前交易下的所有锁定
        stopWatch.start("解锁");
        if("TRN".equals(vo.getBusinessType()) && !MdaUtils.isEmpty(vo.getBusinessInr()) && !"view".equalsIgnoreCase(vo.getOperation())) {
            LockInfo lockInfoTrn = LockInfo.builder().objInr(vo.getBusinessInr()).objType("TRN")
                    .trnName("TRNREL")
                    .usrId(SettleContext.getSessionUserVo().getLogName()).reentrant(true).build();
            bizLocker.unlock(lockInfoTrn);
        }else if(!"view".equalsIgnoreCase(vo.getOperation())){
            bizCommonLocker.unlockAllOfTrans(transName,SettleContext.getSessionUserVo().getLogName());
        }
        stopWatch.stop();
        try {
            //业务交易解锁
            return ResponseSet.simpleSuccess(true);
        }finally {
            logger.info(stopWatch.prettyPrint());
        }
    }

}
