package com.xisc.pm.app.service.autoboard.core;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;

import org.apache.commons.lang3.StringUtils;
import org.hzero.core.base.BaseConstants;
import org.hzero.core.message.Message;
import org.hzero.core.message.MessageAccessor;

import com.xisc.pm.api.dto.PmCompositeSlabCalcDTO;
import com.xisc.pm.api.dto.PmCutPlaceDTO;
import com.xisc.pm.api.dto.PmProContYieldResposeDTO;
import com.xisc.pm.app.service.autoboard.config.CalcLog;
import com.xisc.pm.app.service.autoboard.dto.PmAutoBoardExecParam;
import com.xisc.pm.app.service.autoboard.dto.PmAutoBoardExecResult;
import com.xisc.pm.app.service.autoboard.dto.PmAutoBoardPolicyGroupDTO;
import com.xisc.pm.app.service.autoboard.dto.PmAutoPdLog;
import com.xisc.pm.app.service.autoboard.dto.PmContBoardParam;
import com.xisc.pm.domain.entity.PmAxisBrdTrimBt;
import com.xisc.pm.domain.entity.PmCutPlaceBt;
import com.xisc.pm.domain.entity.PmPdConstBt;
import com.xisc.pm.domain.entity.PmPlateCutLenBt;
import com.xisc.pm.domain.entity.PmPlateSpecBt;
import com.xisc.pm.domain.entity.PmPlateTrimBt;
import com.xisc.pm.domain.entity.PmSlabSpecBt;
import com.xisc.pm.domain.entity.PmSpeStAddvBt;
import com.xisc.pm.domain.entity.PmThickAddvBt;
import com.xisc.pm.infra.constant.Constants;
import com.xisc.pm.infra.constant.Constants.RollDirectCode;
import com.xisc.pm.infra.constant.PmPlateConstants;
import com.xisc.pm.infra.enums.FormPlateMode;
import com.xisc.pm.infra.enums.PdRuleItemType;
import com.xisc.pm.infra.util.Utils;

import io.choerodon.core.exception.CommonException;

/**
 * 组板程序
 * 
 * @author jun.zeng
 *
 */
public abstract class DefaultPmPdProgram implements Callable<Boolean> {

    public PmCutPlaceDTO queryCutPlace(FormPlateMode formPlateMode, PmContBoardParam axisPmProContProdTtr,
            PmAutoBoardExecParam current, PmCompositeSlabCalcDTO pmCompositeSlabCalcDTO) {
        // 读取粗切位置决定基准表
        List<PmCutPlaceBt> pmCutPlaceBts = current.getPmCutPlaceBts();
        if (pmCutPlaceBts == null || pmCutPlaceBts.isEmpty()) {
            throw new CommonException("pm.pm_pro_cont_018", current.getMscLineNo(), formPlateMode.getType(),
                    axisPmProContProdTtr.getOrderThick().toPlainString());
        }
        PmCutPlaceBt cutPlaceBt = null;
        for (PmCutPlaceBt pmCutPlaceBt : pmCutPlaceBts) {
            if (pmCutPlaceBt.getFormPlateModeFirst().equals(formPlateMode.getType())) {
                if (axisPmProContProdTtr.getOrderThick().compareTo(pmCutPlaceBt.getPlateThickFrom()) >= 0
                        && axisPmProContProdTtr.getOrderThick().compareTo(pmCutPlaceBt.getPlateThickTo()) <= 0) {
                    cutPlaceBt = pmCutPlaceBt;
                    break;
                }
            }
        }
        if (cutPlaceBt == null) {
            throw new CommonException("pm.pm_pro_cont_018", current.getMscLineNo(), formPlateMode.getType(),
                    axisPmProContProdTtr.getOrderThick().toPlainString());
        }
        PmCutPlaceDTO pmCutPlaceDTO = new PmCutPlaceDTO();
        if (StringUtils.isNotBlank(axisPmProContProdTtr.getBacklogQMark())
                && axisPmProContProdTtr.getBacklogQMark().charAt(0) == PmPlateConstants.BACKLOG_Q_MARK_FIRST_CHAR) {
            pmCutPlaceDTO.setType(PmPlateConstants.FUR_DEAL_TYPE_Q);
        } else if (StringUtils.isNotBlank(axisPmProContProdTtr.getBacklogTMark())
                && axisPmProContProdTtr.getBacklogTMark().charAt(0) == PmPlateConstants.BACKLOG_T_MARK_FIRST_CHAR) {
            pmCutPlaceDTO.setType(PmPlateConstants.FUR_DEAL_TYPE_Q);
        } else if (StringUtils.isNotBlank(axisPmProContProdTtr.getBacklogAMark())
                && axisPmProContProdTtr.getBacklogAMark().charAt(0) == PmPlateConstants.BACKLOG_A_MARK_FIRST_CHAR) {
            pmCutPlaceDTO.setType(PmPlateConstants.FUR_DEAL_TYPE_A);
        } else if (StringUtils.isNotBlank(axisPmProContProdTtr.getBacklogNMark())
                && axisPmProContProdTtr.getBacklogNMark().charAt(0) == PmPlateConstants.BACKLOG_N_MARK_FIRST_CHAR) {
            pmCutPlaceDTO.setType(PmPlateConstants.FUR_DEAL_TYPE_A);
        } else {
            pmCutPlaceDTO.setType(PmPlateConstants.FUR_DEAL_TYPE_G);
        }
        // 粗切长度上下限
        switch (pmCutPlaceDTO.getType()) {
        case PmPlateConstants.FUR_DEAL_TYPE_Q:
            pmCutPlaceDTO.setCutMax(cutPlaceBt.getQtCutLenTo());
            pmCutPlaceDTO.setCutMin(cutPlaceBt.getQtCutLenFrom());
            break;
        case PmPlateConstants.FUR_DEAL_TYPE_A:
            pmCutPlaceDTO.setCutMax(cutPlaceBt.getUnqtCutLenTo());
            pmCutPlaceDTO.setCutMin(cutPlaceBt.getUnqtCutLenFrom());
            break;
        default:
            pmCutPlaceDTO.setCutMax(cutPlaceBt.getNormalCutLenTo());
            pmCutPlaceDTO.setCutMin(cutPlaceBt.getNormalCutLenFrom());
            break;
        }
        return pmCutPlaceDTO;
    }

    public PmCompositeSlabCalcDTO initParams(PmContBoardParam axisPmContBoardParam) {
        PmCompositeSlabCalcDTO pmCompositeSlabCalcDTO = new PmCompositeSlabCalcDTO();
        // 获取工序记号类型
        if (StringUtils.isNotBlank(axisPmContBoardParam.getBacklogQMark())
                && axisPmContBoardParam.getBacklogQMark().charAt(0) == PmPlateConstants.BACKLOG_Q_MARK_FIRST_CHAR) {
            pmCompositeSlabCalcDTO.setType(PmPlateConstants.FUR_DEAL_TYPE_Q);
        } else if (StringUtils.isNotBlank(axisPmContBoardParam.getBacklogTMark())
                && axisPmContBoardParam.getBacklogTMark().charAt(0) == PmPlateConstants.BACKLOG_T_MARK_FIRST_CHAR) {
            pmCompositeSlabCalcDTO.setType(PmPlateConstants.FUR_DEAL_TYPE_Q);
        } else if (StringUtils.isNotBlank(axisPmContBoardParam.getBacklogAMark())
                && axisPmContBoardParam.getBacklogAMark().charAt(0) == PmPlateConstants.BACKLOG_A_MARK_FIRST_CHAR) {
            pmCompositeSlabCalcDTO.setType(PmPlateConstants.FUR_DEAL_TYPE_A);
        } else if (StringUtils.isNotBlank(axisPmContBoardParam.getBacklogNMark())
                && axisPmContBoardParam.getBacklogNMark().charAt(0) == PmPlateConstants.BACKLOG_N_MARK_FIRST_CHAR) {
            pmCompositeSlabCalcDTO.setType(PmPlateConstants.FUR_DEAL_TYPE_A);
        } else {
            pmCompositeSlabCalcDTO.setType(PmPlateConstants.FUR_DEAL_TYPE_G);
        }
        return pmCompositeSlabCalcDTO;
    }

    public void plateCut(FormPlateMode formPlateMode, PmContBoardParam axisPmProContProdTtr,
            PmAutoBoardExecParam current, PmCompositeSlabCalcDTO pmCompositeSlabCalcDTO) {
        // 读取粗切位置决定基准表
        PmCutPlaceDTO pmCutPlaceDTO = queryCutPlace(formPlateMode, axisPmProContProdTtr, current,
                pmCompositeSlabCalcDTO);
        pmCompositeSlabCalcDTO.setCutMax(pmCutPlaceDTO.getCutMax());
        pmCompositeSlabCalcDTO.setCutMin(pmCutPlaceDTO.getCutMin());

        // 异宽粗切位置数组
        pmCompositeSlabCalcDTO.setDiffCut(pmCompositeSlabCalcDTO.getDiffLoc());
        // 定义每块小板终点位置
        BigDecimal endPos = BigDecimal.ZERO;
        BigDecimal commonCutSegment = BigDecimal.ZERO;
        if (pmCompositeSlabCalcDTO.getMLen() != null && !pmCompositeSlabCalcDTO.getMLen().isEmpty()) {
            for (int i = 0; i < pmCompositeSlabCalcDTO.getMLen().size(); i++) {
                BigDecimal mLen = pmCompositeSlabCalcDTO.getMLen().get(i);
                if (mLen.compareTo(pmCompositeSlabCalcDTO.getCutMax()) > 0) {
                    return;
                }
                endPos = endPos.add(mLen);
                // 添加分段累计和
                pmCompositeSlabCalcDTO.getSum().add(endPos);
                if (pmCompositeSlabCalcDTO.getDiffLoc().contains(i)) {
                    // 重新开始统计命令粗切汇总初始值
                    commonCutSegment = mLen;
                    continue;
                }
                commonCutSegment = commonCutSegment.add(mLen);
                if (commonCutSegment.compareTo(pmCompositeSlabCalcDTO.getCutMax()) > 0) {
                    // 如果小板长度累计大于cut_max 且不是异宽位置，当前下标切一刀
                    pmCompositeSlabCalcDTO.getCommandCut().add(i);
                    // 重新开始统计命令粗切汇总初始值
                    commonCutSegment = mLen;
                }
            }
        }
    }

    public void calcSampleLen(PmContBoardParam axisPmProContProdTtr, PmCompositeSlabCalcDTO pmCompositeSlabCalc) {
        BigDecimal ltpt = null;
        BigDecimal ltpm = null;
        BigDecimal sampleLenHead = axisPmProContProdTtr.getSampleLenHead();
        BigDecimal sampleLenTail = axisPmProContProdTtr.getSampleLenTail();

        if ("B".equals(axisPmProContProdTtr.getSampleModeCode())) {
            sampleLenHead = BigDecimal.ZERO;
            // 尾部试材长度
            ltpt = axisPmProContProdTtr.getSampleLenTail();
        } else if ("T".equals(axisPmProContProdTtr.getSampleModeCode())) {
            sampleLenTail = BigDecimal.ZERO;
            // 头部试样长度
            ltpt = axisPmProContProdTtr.getSampleLenHead();
        } else if ("A".equals(axisPmProContProdTtr.getSampleModeCode())) {
            // 头部+尾部
            ltpt = axisPmProContProdTtr.getSampleLenHead().add(axisPmProContProdTtr.getSampleLenTail());
        } else {
            ltpt = BigDecimal.ZERO;
            sampleLenTail = BigDecimal.ZERO;
            sampleLenHead = BigDecimal.ZERO;
        }
        if ("A".equals(axisPmProContProdTtr.getPickPatternCode())) {
            int planCutNum = pmCompositeSlabCalc.getDiffCut().size() + pmCompositeSlabCalc.getCommandCut().size();
            ltpm = ltpt.multiply(BigDecimal.valueOf(planCutNum));
        } else {
            ltpm = BigDecimal.ZERO;
        }
        pmCompositeSlabCalc.setSampleLenHead(sampleLenHead);
        pmCompositeSlabCalc.setSampleLenTail(sampleLenTail);
        pmCompositeSlabCalc.setSampleLenMid(ltpm);
        pmCompositeSlabCalc.setSampleLength(ltpt.add(ltpm));
    }

    /**
     * 匹配厚度余量
     * 
     * @param axisPmProContProdTtr
     * @param current
     * @param combinePlateWidth
     * @return
     */
    private PmThickAddvBt getPmThickAddvBt(PmContBoardParam axisPmProContProdTtr, PmAutoBoardExecParam current,
            BigDecimal combinePlateWidth) {
        String wholeHeatTreatmentType = axisPmProContProdTtr.getWholeHeatTreatmentTypeMap().get(current.getMscLineNo());
        for (PmThickAddvBt pmThickAddvBt : current.getPmThickAddvBts()) {
            if (pmThickAddvBt.getTolTypeCode().equals(PmPlateConstants.ALL)
                    || pmThickAddvBt.getTolTypeCode().equals(axisPmProContProdTtr.getThkTolType())) {
                if (pmThickAddvBt.getWholeHeatTreatmentType().equals(PmPlateConstants.ALL)
                        || ("Q".equals(pmThickAddvBt.getWholeHeatTreatmentType())
                                && wholeHeatTreatmentType != null && wholeHeatTreatmentType.contains("Q"))) {
                    if (axisPmProContProdTtr.getOrderThick().compareTo(pmThickAddvBt.getPlateThickFrom()) >= 0
                            && axisPmProContProdTtr.getOrderThick().compareTo(pmThickAddvBt.getPlateThickTo()) <= 0) {
                        if (combinePlateWidth.compareTo(pmThickAddvBt.getCombinePlateWidthFrom()) >= 0
                                && combinePlateWidth.compareTo(pmThickAddvBt.getCombinePlateWidthTo()) <= 0) {
                            return pmThickAddvBt;
                        }

                    }
                }
            }
        }
        throw new CommonException("pm.pm_pro_cont_021" , axisPmProContProdTtr.getThkTolType() , wholeHeatTreatmentType
                , axisPmProContProdTtr.getOrderThick().toPlainString() , combinePlateWidth.toPlainString() ,current.getMscLineNo());
    }

    /**
     * 获取粗切位置
     * 
     * @param axisPmProContProdTtr
     * @param current
     * @param combinePlateWidth
     * @param pmCompositeSlabCalc
     * @return
     */
    public PmPlateCutLenBt getPmPlateCutLenBt(PmContBoardParam axisPmProContProdTtr, PmAutoBoardExecParam current,
            BigDecimal combinePlateWidth, PmCompositeSlabCalcDTO pmCompositeSlabCalc) {
        String getRollDirectCode = axisPmProContProdTtr.getRollDirectCodeMap().get(current.getMscLineNo());
        String getRollMode = axisPmProContProdTtr.getRollModeMap().get(current.getMscLineNo());
        for (PmPlateCutLenBt pmPlateCutLenBt : current.getPmPlateCutLenBts()) {
            if (pmPlateCutLenBt.getRollDirectCode().equals(getRollDirectCode)) {
                if (PmPlateConstants.ALL.equals(pmPlateCutLenBt.getRollMode())
                        || pmPlateCutLenBt.getRollMode().equals(getRollMode)) {
                    if (axisPmProContProdTtr.getOrderThick().compareTo(pmPlateCutLenBt.getPlateThickFrom()) >= 0
                            && axisPmProContProdTtr.getOrderThick().compareTo(pmPlateCutLenBt.getPlateThickTo()) <= 0) {
                        if (combinePlateWidth.compareTo(pmPlateCutLenBt.getCombinePlateWidthFrom()) >= 0
                                && combinePlateWidth.compareTo(pmPlateCutLenBt.getCombinePlateWidthTo()) <= 0) {
                            if (current.getMoldThick().compareTo(pmPlateCutLenBt.getSlabThickFrom()) >= 0
                                    && current.getMoldThick().compareTo(pmPlateCutLenBt.getSlabThickTo()) <= 0) {
                                if (pmCompositeSlabCalc.getBroadFlag().equals(pmPlateCutLenBt.getBrrNeed())) {
                                    return pmPlateCutLenBt;
                                }
                            }
                        }
                    }
                }
            }
        }
        return null;
    }

    public PmSpeStAddvBt getPmSpeStAddvBt(PmContBoardParam axisPmProContProdTtr, PmAutoBoardExecParam current,
            BigDecimal taim) {
        if(current.getPmSpeStAddvBts() == null) {
            return null ;
        }
        for (PmSpeStAddvBt pmSpeStAddvBt : current.getPmSpeStAddvBts()) {
            if (axisPmProContProdTtr.getStNo().equals(pmSpeStAddvBt.getStNo())) {
                if (PmPlateConstants.ALL.equals(pmSpeStAddvBt.getSgSign())
                        || axisPmProContProdTtr.getSgSign().equals(pmSpeStAddvBt.getSgSign())) {
                    if (current.getMoldThick().compareTo(pmSpeStAddvBt.getSlabThickFrom()) >= 0
                            && current.getMoldThick().compareTo(pmSpeStAddvBt.getSlabThickTo()) <= 0) {
                        if (taim.compareTo(pmSpeStAddvBt.getPlateThickFrom()) >= 0
                                && taim.compareTo(pmSpeStAddvBt.getPlateThickTo()) <= 0) {
                            return pmSpeStAddvBt;
                        }
                    }
                }
            }
        }
        return null;
    }

    public PmProContYieldResposeDTO calcYield(List<PmContBoardParam> pmContBoardParamList,
            PmContBoardParam axisPmProContProdTtr, PmAutoBoardExecParam current, BigDecimal combinePlateWidth,
            BigDecimal combinePlateLen, PmCompositeSlabCalcDTO pmCompositeSlabCalc, BigDecimal allWt) {
        PmProContYieldResposeDTO yieldRespose = new PmProContYieldResposeDTO();
        yieldRespose.setCombinePlateWidth(combinePlateWidth);
        yieldRespose.setCombinePlateLen(combinePlateLen);
        yieldRespose.setBroadFlag(pmCompositeSlabCalc.getBroadFlag());
        yieldRespose.setRsCode(pmCompositeSlabCalc.getRsCode());

        PmThickAddvBt pmThickAddvBt = getPmThickAddvBt(axisPmProContProdTtr, current, combinePlateWidth);
        // 钢板切缝切头尾范围基准表数据
        PmPlateCutLenBt pmPlateCutLenBt = getPmPlateCutLenBt(axisPmProContProdTtr, current, combinePlateWidth,
                pmCompositeSlabCalc);
        // 轧制目标厚度taim
        BigDecimal maxTaim = null;
        BigDecimal minTaim = null;
        // 合同最大头部或者尾部切舍量
        BigDecimal maxOrderheadCut = null;
        BigDecimal maxOrderTailCut = null;
        // 合同厚度是否是否一致
        boolean thkEqualsFlag = true;
        // 公差交集下限是否一致
        boolean minTaimFlag = true;
        boolean trimCodeIsZeroFlag = false ;
        for (PmContBoardParam pmContBoardParam : pmContBoardParamList) {
            if("0".equals(pmContBoardParam.getTrimCode())) {
                trimCodeIsZeroFlag = true ;
            }
            BigDecimal getHeadCut = pmContBoardParam.getHeadCutMap().get(current.getMscLineNo());
            BigDecimal getTailCut = pmContBoardParam.getTailCutMap().get(current.getMscLineNo());
            if (thkEqualsFlag
                    && axisPmProContProdTtr.getOrderThick().compareTo(pmContBoardParam.getOrderThick()) != 0) {
                // 如果合同厚度不等于轴合同订货厚度需要取交集的中间值
                thkEqualsFlag = false;
            }
            if (minTaimFlag
                    && axisPmProContProdTtr.getThickTolMin().compareTo(pmContBoardParam.getThickTolMin()) != 0) {
                minTaimFlag = false;
            }
            // 合同订货区间
            BigDecimal thickMin = pmContBoardParam.getOrderThick().add(pmContBoardParam.getThickTolMin());
            BigDecimal thickMax = pmContBoardParam.getOrderThick().add(pmContBoardParam.getThickTolMax());
            // 记录交集
            if (maxTaim == null || maxTaim.compareTo(thickMax) > 0) {
                maxTaim = thickMax;
            }
            if (minTaim == null || minTaim.compareTo(thickMin) < 0) {
                minTaim = thickMin;
            }
            if (maxOrderheadCut == null || maxOrderheadCut.compareTo(getHeadCut) < 0) {
                maxOrderheadCut = getHeadCut;
            }
            if (maxOrderTailCut == null || maxOrderTailCut.compareTo(getTailCut) < 0) {
                maxOrderTailCut = getTailCut;
            }
        }
        if(trimCodeIsZeroFlag && pmCompositeSlabCalc.getPickModeLenDir() != 1 && pmCompositeSlabCalc.getPickModeWidDir() != 1) {
            // 如果切边标记为0，一块大板内只能组一块板
            throw new RuntimeException("如果切边标记为0，一块大板内只能组一块板");
        }

        if (pmContBoardParamList.size() == 1) {
            // 当为一个合同时，轧制目标厚度=订货厚度+厚度公差下限+厚度余量
            yieldRespose.setTaim(minTaim.add(pmThickAddvBt.getThickAddv()));
        } else if (pmContBoardParamList.size() > 1 && thkEqualsFlag && minTaimFlag) {
            // 当为多个合同且下公差相同时，轧制目标厚度=订货厚度+厚度公差下限+厚度余量
            yieldRespose.setTaim(minTaim.add(pmThickAddvBt.getThickAddv()));
        } else if (pmContBoardParamList.size() > 1 && thkEqualsFlag && !minTaimFlag) {
            // 当为多个合同且下公差不同时，计算每个合同的区间[订货厚度+厚度公差下限，订货厚度+合同厚度公差上限]，取各区间交集，轧制目标厚度=交集的下限+厚度余量，
            // 当轧制目标厚度＜交集的上限时允许通过，当轧制目标厚度≥交集的上限时不允许通过。
            yieldRespose.setTaim(minTaim.add(pmThickAddvBt.getThickAddv()));
            if (yieldRespose.getTaim().compareTo(maxTaim) >= 0) {
                throw new CommonException("pm.pm_pro_cont_022");
            }
        }

        yieldRespose.setRollThickTolMax(maxTaim.subtract(axisPmProContProdTtr.getOrderThick()));
        yieldRespose.setRollThickTolMin(minTaim.subtract(axisPmProContProdTtr.getOrderThick()));

        if (pmPlateCutLenBt == null || pmPlateCutLenBt.getPlateCutWidth() == null
                || pmPlateCutLenBt.getHeadCut() == null || pmPlateCutLenBt.getTailCut() == null) {
            throw new CommonException("pm.pm_pro_cont_023");
        }
        // 轧制目标宽度
        if (pmCompositeSlabCalc.getRsCode() == 3) {
            yieldRespose.setWaim(current.getMoldWidth());
        } else {
            // 轧制目标宽度=组合板宽度 + (轴合同)宽度余量 + 切边量 +（取板方式_宽度方向-1） × 钢板切缝宽度
            BigDecimal waim = yieldRespose.getCombinePlateWidth().add(
                    axisPmProContProdTtr.getWidthAddv() == null ? BigDecimal.ZERO : axisPmProContProdTtr.getWidthAddv())
                    .add(pmCompositeSlabCalc.getTrimWidth());
            BigDecimal pickModeWidDir = BigDecimal.valueOf(pmCompositeSlabCalc.getPickModeWidDir())
                    .subtract(BigDecimal.ONE);
            yieldRespose.setWaim(waim.add(pickModeWidDir.multiply(pmPlateCutLenBt.getPlateCutWidth())));
        }
        // 轧制目标长度laim
        // 组合板长度 + 试样长度 + 组板基表头部切舍量 + 组板基表尾部切舍量 +（取板方式_长度方向-1）* 长方向切缝量 +
        // MAX（大板上所有合同的头部切舍量）+ MAX（大板上所有合同的尾部切舍量）
        // 长方向切缝量 == 钢板切缝宽度
        BigDecimal headCut = pmPlateCutLenBt.getHeadCut().add(maxOrderheadCut);
        BigDecimal tailCut = pmPlateCutLenBt.getTailCut().add(maxOrderTailCut);
        BigDecimal pickModeLenDir = BigDecimal.valueOf(pmCompositeSlabCalc.getPickModeLenDir())
                .subtract(BigDecimal.ONE);
        BigDecimal laim = yieldRespose.getCombinePlateLen().add(pmCompositeSlabCalc.getSampleLength()).add(headCut)
                .add(tailCut).add(pickModeLenDir.multiply(pmPlateCutLenBt.getPlateCutWidth()));
        yieldRespose.setLaim(laim);
        yieldRespose.setHeadCut(headCut);
        yieldRespose.setTailCut(tailCut);
        // (2) 基准收得率norm_yield = （订货厚度*组合板宽度*组合板长度）*（1-氧化铁皮损失率）÷（轧制目标长度*轧制目标宽度*轧制目标厚度）
        yieldRespose.setNormYield(calcNormYield(axisPmProContProdTtr.getOrderThick(), yieldRespose));

        PmSpeStAddvBt PmSpeStAddvBt = getPmSpeStAddvBt(axisPmProContProdTtr, current, yieldRespose.getTaim());
        if (PmSpeStAddvBt != null) {
            yieldRespose.setSlabAddv(PmSpeStAddvBt.getSlabAddv());
        }

        calc(axisPmProContProdTtr, current, pmCompositeSlabCalc, allWt, yieldRespose);
        return yieldRespose;
    }

    public void calc(PmContBoardParam axisPmProContProdTtr, PmAutoBoardExecParam current,
            PmCompositeSlabCalcDTO pmCompositeSlabCalc, BigDecimal allWt, PmProContYieldResposeDTO yieldRespose) {
        // 板坯厚,板坯宽
        BigDecimal slabTaim = current.getMoldThick();
        BigDecimal slabWaim = current.getMoldWidth();
        // 密度（克/cm^3）
        BigDecimal prodDensity = axisPmProContProdTtr.getProdDensity();

        // 轧制有效重量(克) = 轴合同订货厚度 × 组合宽 × 组合长 × 密度
        BigDecimal effectWt = axisPmProContProdTtr.getOrderThick().multiply(yieldRespose.getCombinePlateLen())
                .multiply(yieldRespose.getCombinePlateWidth()).multiply(prodDensity)
                .divide(BigDecimal.valueOf(1000), PmPlateConstants.TEM_SCALE, RoundingMode.HALF_UP);

        // 必要板坯重量(克) = 轧制有效重量÷基准收得率 = (轧制目标厚 * 轧制目标宽 * 轧制目标长 * 密度) / (1-s1);
        BigDecimal needSlabWtGram = effectWt.divide(yieldRespose.getNormYield(), PmPlateConstants.TEM_SCALE,
                RoundingMode.HALF_UP);

        // 宽，厚转化为cm - 密度单位转化为 克/cm
        BigDecimal waimAndTaimAndDensity = slabTaim.multiply(slabWaim).multiply(prodDensity)
                .divide(BigDecimal.valueOf(100), PmPlateConstants.TEM_SCALE, RoundingMode.HALF_UP);

        // 必要板坯长度（cm) = 必要板坯重量(克) ÷（板坯厚度 × 板坯宽度 × 密度）;
        // 转化为毫米
        BigDecimal needSlabLen = needSlabWtGram.multiply(BigDecimal.TEN).divide(waimAndTaimAndDensity,
                PmPlateConstants.LEN_SCALE, RoundingMode.HALF_UP);

        // 单位克
        BigDecimal infurSlabWtGram = noFixSlabLenCalc(current, yieldRespose, axisPmProContProdTtr, effectWt,
                waimAndTaimAndDensity, needSlabLen, needSlabWtGram);

        // 厚板轧制重量roll_wt_hp = 轧制目标厚度(mm) * 轧制目标宽度(mm) * 轧制目标长度(mm) * 密度
        // 转化为吨
        yieldRespose.setRollWtHp(yieldRespose.getTaim().multiply(yieldRespose.getWaim())
                .multiply(yieldRespose.getLaim()).multiply(prodDensity)
                .divide(BigDecimal.valueOf(1000L * 1000L * 1000L), PmPlateConstants.WT_SCALE, RoundingMode.HALF_UP));

        if (yieldRespose.getNeedSlabLen().compareTo(yieldRespose.getPreCleanSlabLen()) > 0
                || yieldRespose.getNeedSlabLen().compareTo(yieldRespose.getInfurSlabLen()) > 0) {
            throw new CommonException("pm.pm_pro_cont_047", yieldRespose.getPreCleanSlabLen().toPlainString(),
                    yieldRespose.getInfurSlabLen().toPlainString(), yieldRespose.getNeedSlabLen().toBigInteger());
        }

        // 轧制收得率 ＝ 轧制有效重量 ÷ 进加热炉板坯重量
        yieldRespose.setRollYield(effectWt.divide(infurSlabWtGram, PmPlateConstants.YIELD_SCALE, RoundingMode.HALF_UP));
        // 命令收得率 ＝Σ合同单重 ÷ 进加热炉板坯重量
        yieldRespose.setSumPlateWt(allWt);
        yieldRespose.setCommandYield(
                allWt.divide(yieldRespose.getInfurSlabWt(), PmPlateConstants.YIELD_SCALE, RoundingMode.HALF_UP));
    }

    public BigDecimal noFixSlabLenCalc(PmAutoBoardExecParam current, PmProContYieldResposeDTO yieldRespose,
            PmContBoardParam axisPmProContProdTtr, BigDecimal effectWt, BigDecimal waimAndTaimAndDensity,
            BigDecimal needSlabLen, BigDecimal needSlabWtGram) {
        BigDecimal newInfurSlabWtGram = null;
        // 查询质量接口，根据产品品种获取是否能展宽，如果不是
        if (StringUtils.isNotBlank(axisPmProContProdTtr.getAxialRollMark()) && BaseConstants.Flag.NO.toString().equals(axisPmProContProdTtr.getAxialRollMark())) {
            // 当组合大板宽度/必要板坯长度*1.02 <1.6,且 组合大板宽度 > 结晶器宽度，则重新计算轧制目标宽度waim
            BigDecimal raito = yieldRespose.getCombinePlateWidth()
                    .divide(needSlabLen, PmPlateConstants.TEM_SCALE, RoundingMode.HALF_UP)
                    .multiply(BigDecimal.valueOf(1.02f));
            if (raito.compareTo(BigDecimal.valueOf(1.6f)) < 0
                    && yieldRespose.getCombinePlateWidth().compareTo(current.getMoldWidth()) > 0) {
                // 重算目标宽
                BigDecimal waim = yieldRespose.getWaim()
                        .subtract(axisPmProContProdTtr.getWidthAddv() == null ? BigDecimal.ZERO
                                : axisPmProContProdTtr.getWidthAddv());
                PmAxisBrdTrimBt pmAxisBrdTrimBt = getPmAxisBrdTrimBt(current, yieldRespose, axisPmProContProdTtr);
                if (pmAxisBrdTrimBt != null) {
                    waim = waim.add(pmAxisBrdTrimBt.getWidthAddv());
                    yieldRespose.setWaim(waim);
                    // 重算基准收得率
                    calcNormYield(axisPmProContProdTtr.getOrderThick(), yieldRespose);
                    needSlabWtGram = effectWt.divide(yieldRespose.getNormYield(), PmPlateConstants.TEM_SCALE,
                            RoundingMode.HALF_UP);
                    needSlabLen = needSlabWtGram.multiply(BigDecimal.TEN).divide(waimAndTaimAndDensity,
                            PmPlateConstants.LEN_SCALE, RoundingMode.HALF_UP);
                }
            }
        }

        BigDecimal saleWtRate = BigDecimal.ONE;
        if (yieldRespose.getSlabAddv() != null) {
            saleWtRate = saleWtRate.add(yieldRespose.getSlabAddv());
        }
        // 必要板坯重量 = 必要板坯重量 * （1 + 板坯加料），
        // 必要板坯长度 = 必要板坯长度 * （1 + 板坯加料），
        needSlabWtGram = needSlabWtGram.multiply(saleWtRate);
        needSlabLen = needSlabLen.multiply(saleWtRate);

        yieldRespose.setNeedSlabLen(needSlabLen);
        yieldRespose.setNeedSlabWt(
                needSlabWtGram.divide(PmPlateConstants.GRAM_TO_TON, PmPlateConstants.WT_SCALE, RoundingMode.HALF_UP));

//        // 中间坯 TODO
//        BigDecimal lenWidthDiff = pmMidSlabAddvBtRepository.queryLenWidthDiff(yieldRespose.getTaim(),
//                axisPmProContProdTtr.getOrderNo(), pmProContYield.getPmContFilterRequest().getMscLineNo(),
//                pmProContYield.getPmContFilterRequest().getStNo(), pmProContYield.getPmContFilterRequest().getSgSign(),
//                pmProContYield.getTenantId());
//        
//        if (lenWidthDiff != null) {
//            // 中间坯长度 = 板坯厚度 * 板坯宽度 * 必要板坯长度 / (中间坯厚度目标 * 轧制目标宽度waim)
//            BigDecimal midSLabThkAim = qdToPoOrderMapper.queryMidSLabThkAim(axisPmProContProdTtr.getOrderNo(),
//                    pmProContYield.getPmContFilterRequest().getMscLineNo(), pmProContYield.getTenantId());
//            
//            if (midSLabThkAim != null) {
//                BigDecimal midLen = current.getMoldThick()
//                        .multiply(current.getMoldWidth()).multiply(needSlabLen);
//                midLen = midLen.divide(midSLabThkAim.multiply(yieldRespose.getWaim()), PmPlateConstants.LEN_SCALE,
//                        RoundingMode.HALF_UP);
//                if (midLen.subtract(yieldRespose.getWaim()).abs().compareTo(lenWidthDiff) < 0) {
//                    // 若 |中间坯长度-轧制目标宽度| < len_width_diff，则要将中间坯长度补长，使中间坯长度 = 轧制目标宽度 + len_width_diff
//                    midLen = yieldRespose.getWaim().add(lenWidthDiff);
//                }
//                // 更新必要板坯长度 = 中间坯厚度目标 * 轧制目标宽度 * 中间坯长度 / （板坯厚度 * 板坯宽度）
//                needSlabLen = midSLabThkAim.multiply(yieldRespose.getWaim()).multiply(midLen)
//                        .divide(current.getMoldThick()
//                                .multiply(current.getMoldWidth()),
//                                PmPlateConstants.LEN_SCALE, RoundingMode.HALF_UP);
//            }
//        }
        needSlabLen = needSlabLen.setScale(PmPlateConstants.LEN_SCALE, RoundingMode.HALF_UP);
        needSlabWtGram = needSlabLen.multiply(waimAndTaimAndDensity).divide(BigDecimal.TEN, PmPlateConstants.TEM_SCALE,
                RoundingMode.HALF_UP);

        yieldRespose.setNeedSlabLen(needSlabLen);
        yieldRespose.setNeedSlabWt(
                needSlabWtGram.divide(PmPlateConstants.GRAM_TO_TON, PmPlateConstants.WT_SCALE, RoundingMode.HALF_UP));

        // 单位克
        newInfurSlabWtGram = needSlabWtGram;
        yieldRespose.setInfurSlabWt(newInfurSlabWtGram.divide(PmPlateConstants.GRAM_TO_TON, PmPlateConstants.WT_SCALE,
                RoundingMode.HALF_UP));
        // 进加热炉板坯长度 = 进加热炉板坯重量 ÷（板坯厚度×板坯宽度×密度）
        yieldRespose.setInfurSlabLen(newInfurSlabWtGram.multiply(PmPlateConstants.CM_TO_MM)
                .divide(waimAndTaimAndDensity, PmPlateConstants.LEN_SCALE, RoundingMode.HALF_UP));
        // 清理前板坯重量 ＝ 进加热炉板坯重量
        yieldRespose.setPreCleanSlabWt(yieldRespose.getInfurSlabWt());
        // 清理前板坯长度 ＝ 清理前板坯重量 ÷（板坯厚度×板坯宽度×密度）
        yieldRespose.setPreCleanSlabLen(newInfurSlabWtGram.multiply(PmPlateConstants.CM_TO_MM)
                .divide(waimAndTaimAndDensity, PmPlateConstants.LEN_SCALE, RoundingMode.HALF_UP));
        return newInfurSlabWtGram;
    }

    public PmAxisBrdTrimBt getPmAxisBrdTrimBt(PmAutoBoardExecParam current, PmProContYieldResposeDTO yieldRespose,
            PmContBoardParam axisPmProContProdTtr) {
        for (PmAxisBrdTrimBt pmAxisBrdTrimBt : current.getPmAxisBrdTrimBts()) {
            if (pmAxisBrdTrimBt.getWithSideFlag().equals(axisPmProContProdTtr.getTrimCode())
                    && pmAxisBrdTrimBt.getValidFlag().equals(BaseConstants.Flag.YES.longValue())) {
                return pmAxisBrdTrimBt;
            }
        }
        return null;
    }

    /**
     * 计算基准收得率 基准收得率norm_yield =
     * （订货厚度*组合板宽度*组合板长度）*（1-氧化铁皮损失率）÷（轧制目标长度*轧制目标宽度*轧制目标厚度）
     * 
     * @param orderThick
     * @param yieldRespose
     * @return
     */
    private BigDecimal calcNormYield(BigDecimal orderThick, PmProContYieldResposeDTO yieldRespose) {
        BigDecimal compositeSlabArea = orderThick.multiply(yieldRespose.getCombinePlateLen())
                .multiply(yieldRespose.getCombinePlateWidth()).multiply(PmPlateConstants.IRON_OXIDE_EFFECT_RATE);
        BigDecimal targetSlabArea = yieldRespose.getLaim().multiply(yieldRespose.getWaim())
                .multiply(yieldRespose.getTaim());
        return compositeSlabArea.divide(targetSlabArea, PmPlateConstants.YIELD_SCALE, RoundingMode.HALF_UP);
    }

    protected PmProContYieldResposeDTO checkResult(FormPlateMode formPlateMode,
            List<PmContBoardParam> pmContBoardParams, PmAutoBoardPolicyGroupDTO policyGroup,
            PmAutoBoardExecParam current,PmAutoBoardExecResult execResult, BigDecimal combinePlateWidth, BigDecimal combinePlateLen,
            PmContBoardParam axisPmContBoardParam, List<BigDecimal> lens, BigDecimal allWt , List<String> block1 , List<String> block2) {

        PmCompositeSlabCalcDTO pmCompositeSlabCalcDTO = initParams(axisPmContBoardParam);
        if (FormPlateMode.S.getType().equals(formPlateMode.getType())) {
            pmCompositeSlabCalcDTO.setPickModeWidDir(2);
        } else {
            pmCompositeSlabCalcDTO.setPickModeWidDir(1);
        }
        pmCompositeSlabCalcDTO.setPickModeLenDir(lens.size());
        pmCompositeSlabCalcDTO.setMotherableNum(lens.size());
        pmCompositeSlabCalcDTO.getMLen().addAll(lens);
        pmCompositeSlabCalcDTO.setDiffCut(new ArrayList<Integer>());
        if(FormPlateMode.A2.equals(formPlateMode)) {
            Map<String , PmContBoardParam> orderMap = new HashMap<String, PmContBoardParam>(pmContBoardParams.size());
            for (PmContBoardParam pmContBoardParam : pmContBoardParams) {
                orderMap.put(pmContBoardParam.getOrderNo(), pmContBoardParam);
            }
            int i = 0 ;
            PmContBoardParam pmContBoardParamLast = null;
            for (String val : block1) {
                PmContBoardParam pmContBoardParam = orderMap.get(val);
                if(pmContBoardParamLast != null) {
                    if(pmContBoardParamLast.getOrderWid().compareTo(pmContBoardParam.getOrderWid()) != 0) {
                        pmCompositeSlabCalcDTO.getDiffLoc().add(i);
                    }
                }
                i++;
                pmContBoardParamLast = pmContBoardParam;
            }
        }
        // 计算命令粗切
        try {
            plateCut(formPlateMode, axisPmContBoardParam, current, pmCompositeSlabCalcDTO);
        } catch (CommonException e) {
            Message message = MessageAccessor.getMessage(e.getCode(), e.getParameters());
            CalcLog.log(message.getDesc());
            return null;
        } catch (Exception e) {
            e.printStackTrace();
            CalcLog.log(e.getMessage());
            return null;
        }
        // 计算试样长
        calcSampleLen(axisPmContBoardParam, pmCompositeSlabCalcDTO);

        BigDecimal trimWidth = null;
        // 取小板宽度切边量的最大值
        BigDecimal ratio = combinePlateWidth.divide(current.getMoldWidth(), BaseConstants.Digital.TWO,
                RoundingMode.HALF_UP);
        for (PmPlateTrimBt pmPlateTrimBt : current.getPmPlateTrimBts()) {
            if (combinePlateWidth.compareTo(pmPlateTrimBt.getCombinePlateWidthFrom()) < 0
                    || combinePlateWidth.compareTo(pmPlateTrimBt.getCombinePlateWidthTo()) > 0) {
                continue;
            }
            if (!pmPlateTrimBt.getWithSideFlag().equals(axisPmContBoardParam.getProdSideMark())) {
                continue;
            }
            if (pmPlateTrimBt.getWidenFrom().compareTo(ratio) > 0 || pmPlateTrimBt.getWidenTo().compareTo(ratio) < 0) {
                continue;
            }
            if (axisPmContBoardParam.getOrderThick().compareTo(pmPlateTrimBt.getPlateThickFrom()) < 0
                    || axisPmContBoardParam.getOrderThick().compareTo(pmPlateTrimBt.getPlateThickTo()) > 0) {
                continue;
            }
            for (BigDecimal len : lens) {
                if (len.compareTo(pmPlateTrimBt.getSmallPlateLenFrom()) >= 0
                        && len.compareTo(pmPlateTrimBt.getSmallPlateLenTo()) <= 0) {
                    if (trimWidth == null || pmPlateTrimBt.getTrimWidth().compareTo(trimWidth) > 0) {
                        trimWidth = pmPlateTrimBt.getTrimWidth();
                    }
                }
            }
        }
        if (trimWidth == null) {
            trimWidth = BigDecimal.ZERO;
            CalcLog.log(block1 , block2 ,"获取切边量配置失败：组板失败！");
            CalcLog.log(new PmAutoPdLog(current.getRequestId() , execResult.getVersion() , current.getMoldId()).setAxisOrderNo(axisPmContBoardParam.getOrderNo()).setBlock1(block1).setBlock2(block2)
                    .setFormPlateMode(formPlateMode.getCode()).setLens(lens).setMessage("获取切边量配置失败：组板失败！"));
            return null;
        }
        pmCompositeSlabCalcDTO.setTrimWidth(trimWidth);
        pmCompositeSlabCalcDTO.setRsCode(0);
        pmCompositeSlabCalcDTO.setBroadFlag("1");
        if (combinePlateWidth.add(trimWidth).compareTo(current.getMoldWidth()) <= 0) {
            pmCompositeSlabCalcDTO.setRsCode(3);
            pmCompositeSlabCalcDTO.setBroadFlag("0");
        }
        String rollDirectCode = pmCompositeSlabCalcDTO.getRsCode() == 3 ? RollDirectCode.L : RollDirectCode.C;
        try {
            PmProContYieldResposeDTO yieldRespose = calcYield(pmContBoardParams, axisPmContBoardParam, current,
                    combinePlateWidth, combinePlateLen, pmCompositeSlabCalcDTO, allWt);
            yieldRespose.setPmCompositeSlabCalc(pmCompositeSlabCalcDTO);
            BigDecimal commandYield = yieldRespose.getCommandYield().multiply(BigDecimal.valueOf(100L));
            if (policyGroup.getYieldLower() != null && policyGroup.getYieldLower().compareTo(commandYield) >= 0) {
                CalcLog.log(block1 , block2,"命令收得率不满足下限要求：" + commandYield.toPlainString() + " 下限： "
                        + policyGroup.getYieldLower().toPlainString());
                CalcLog.log(new PmAutoPdLog(current.getRequestId() , execResult.getVersion() , current.getMoldId()).setRequestId(current.getRequestId()).setAxisOrderNo(axisPmContBoardParam.getOrderNo()).setBlock1(block1).setBlock2(block2)
                        .setFormPlateMode(formPlateMode.getCode()).setLens(lens).setMessage("命令收得率不满足下限要求：" + commandYield.toPlainString() + " 下限： "
                                + policyGroup.getYieldLower().toPlainString()).setYield(commandYield));
                return null;
            }
            if (checkRuleSet05(current, combinePlateWidth,combinePlateLen, rollDirectCode, axisPmContBoardParam, yieldRespose , formPlateMode)) {
                return yieldRespose;
            }
            ;
        } catch (CommonException e) {
            Message message = MessageAccessor.getMessage(e.getCode(), e.getParameters());
            CalcLog.log(block1 , block2 ,message.getDesc());
            CalcLog.log(new PmAutoPdLog(current.getRequestId() , execResult.getVersion() , current.getMoldId()).setRequestId(current.getRequestId()).setAxisOrderNo(axisPmContBoardParam.getOrderNo()).setBlock1(block1).setBlock2(block2)
                    .setFormPlateMode(formPlateMode.getCode()).setLens(lens).setMessage(message.getDesc()));
            return null;
        } catch (Exception e) {
            e.printStackTrace();
            CalcLog.log(block1 , block2 ,e.getMessage());
            CalcLog.log(new PmAutoPdLog(current.getRequestId() , execResult.getVersion() , current.getMoldId()).setAxisOrderNo(axisPmContBoardParam.getOrderNo()).setBlock1(block1).setBlock2(block2)
                    .setFormPlateMode(formPlateMode.getCode()).setLens(lens).setMessage(e.getMessage()));
            return null;
        }
        return null;

    }

    /**
     * 
     */
    protected boolean checkRuleSet05(PmAutoBoardExecParam current, BigDecimal combinePlateWidth, BigDecimal combinePlateLen, String rollDirectCode,
            PmContBoardParam axisPmContBoardParam, PmProContYieldResposeDTO yieldRespose , FormPlateMode formPlateMode) {
        
        
        // 结晶器厚度
        BigDecimal moldThick = current.getMoldThick();
        BigDecimal moldWidth = current.getMoldWidth();
        PmPdConstBt record = current.getPmPdConstBt();
        
        if (yieldRespose.getLaim().compareTo(record.getHpmMinPLen()) < 0 || yieldRespose.getLaim().compareTo(record.getHpmMaxPLen()) > 0) {
            // 47
            // 组合长度为【combine_plate_len】，组合板长度上下限分别为【COMBINE_PLATE_LEN_MAX】、【COMBINE_PLATE_LEN_MIN】。
            throw new CommonException("pm.pm_pd_rule_set_017", yieldRespose.getLaim().toPlainString(),
                    record.getHpmMaxPLen().toPlainString(), record.getHpmMinPLen().toPlainString());
        }

        List<PmSlabSpecBt> pmSlabSpecBts = current.getPmSlabSpecBts();

        if (null == pmSlabSpecBts || pmSlabSpecBts.isEmpty()) {
            return false;
        }
        BigDecimal minRollThick = null;
        BigDecimal canRollWidthMin = null;
        boolean checkFlag = false ;
        for (PmSlabSpecBt pmSlabSpecBt : pmSlabSpecBts) {
            if (!pmSlabSpecBt.getRollDirectCode().equals(rollDirectCode)) {
                continue;
            }
            if (!Constants.CcType.TYPE_1.equals(pmSlabSpecBt.getCcType())) {
                continue;
            }
            if (current.getMoldThick().compareTo(pmSlabSpecBt.getSlabThickFrom()) >= 0
                    && current.getMoldThick().compareTo(pmSlabSpecBt.getSlabThickTo()) <= 0) {
                if (current.getMoldWidth().compareTo(pmSlabSpecBt.getSlabWidthFrom()) >= 0
                        && current.getMoldWidth().compareTo(pmSlabSpecBt.getSlabWidthTo()) <= 0) {
                    if (minRollThick == null || minRollThick.compareTo(pmSlabSpecBt.getMinRollThick()) > 0) {
                        minRollThick = pmSlabSpecBt.getMinRollThick();
                        canRollWidthMin = pmSlabSpecBt.getCanRollWidthMin();
                    }
                    if (yieldRespose.getInfurSlabLen().compareTo(pmSlabSpecBt.getSlabMinLen()) >= 0
                            && yieldRespose.getInfurSlabLen().compareTo(pmSlabSpecBt.getSlabMaxLen()) <= 0) {
                        // 52
                        checkFlag = true ;
                    }
                }
            }
        }
        if(!checkFlag) {
            if(current.isTransflag() && current.getMoldWidth().compareTo(BigDecimal.valueOf(2200)) >= 0 
                    && yieldRespose.getInfurSlabLen().compareTo(BigDecimal.valueOf(2200)) < 0) {
                // 开启转置，增加一次转置校验
                for (PmSlabSpecBt pmSlabSpecBt : pmSlabSpecBts) {
                    if (!pmSlabSpecBt.getRollDirectCode().equals(rollDirectCode)) {
                        continue;
                    }
                    if (!Constants.CcType.TYPE_1.equals(pmSlabSpecBt.getCcType())) {
                        continue;
                    }
                    if (current.getMoldThick().compareTo(pmSlabSpecBt.getSlabThickFrom()) >= 0
                            && current.getMoldThick().compareTo(pmSlabSpecBt.getSlabThickTo()) <= 0) {
                        if (current.getMoldWidth().compareTo(pmSlabSpecBt.getSlabMinLen()) >= 0
                                && current.getMoldWidth().compareTo(pmSlabSpecBt.getSlabMaxLen()) <= 0) {
                            if (yieldRespose.getInfurSlabLen().compareTo(pmSlabSpecBt.getSlabWidthFrom()) >= 0
                                    && yieldRespose.getInfurSlabLen().compareTo(pmSlabSpecBt.getSlabWidthTo()) <= 0) {
                                // 52
                                checkFlag = true ;
                                yieldRespose.setTransFlag(1L);
                                break;
                            }
                        }
                    }
                }
            }
        }
        if(!checkFlag) {
            throw new CommonException("pm.pm_pd_rule_set_019", current.getMscLineNo(), rollDirectCode,
                    moldThick.toPlainString(), moldWidth.toPlainString(), Constants.CcType.TYPE_1,
                    yieldRespose.getInfurSlabLen().toPlainString(),
                    yieldRespose.getNeedSlabLen().toPlainString());
        }
        
        if (null == minRollThick || canRollWidthMin == null) {
            throw new CommonException("pm.pm_pd_rule_set_004", Constants.CcType.TYPE_1, moldThick.toPlainString(),
                    moldWidth, current.getMscLineNo(), rollDirectCode, PdRuleItemType.SLAB_ROLL_WIDTH_MATCH.getCode());
        }

        // mold_thick / (ORDER_THICK + MIN_ROLL_THICK) * mold_width
        BigDecimal ratioRollWidth = moldThick.divide(axisPmContBoardParam.getOrderThick().add(minRollThick),
                PmPlateConstants.TEM_SCALE, RoundingMode.HALF_UP).multiply(moldWidth);
        BigDecimal widthLimit = Utils.minValue(record.getHpmMaxPWidth(), ratioRollWidth);
        // 5
        if (canRollWidthMin.compareTo(combinePlateWidth) > 0) {
            throw new CommonException("pm.pm_pd_rule_set_041", combinePlateWidth.toPlainString(),
                    canRollWidthMin.toPlainString());
        }
        if (widthLimit.compareTo(combinePlateWidth) < 0) {
            throw new CommonException("pm.pm_pd_rule_set_041", combinePlateWidth.toPlainString(),
                    canRollWidthMin.toPlainString());
        }
        String wholeHeatTreatmentType = axisPmContBoardParam.getWholeHeatTreatmentTypeMap().get(current.getMscLineNo());
        String getAdTypeCode = axisPmContBoardParam.getAdTypeCodeMap().get(current.getMscLineNo());
        String getRollMode = axisPmContBoardParam.getRollModeMap().get(current.getMscLineNo());
        PmPlateSpecBt currentPmPlateSpecBt = null;
        for (PmPlateSpecBt pmPlateSpecBt : current.getPmPlateSpecBts()) {
            if(PmPlateConstants.ALL.equals(pmPlateSpecBt.getStCode()) || pmPlateSpecBt.getStCode().equals(axisPmContBoardParam.getStCode())) {
                if(PmPlateConstants.ALL.equals(pmPlateSpecBt.getFormPlateMode()) || formPlateMode.getType().equals(pmPlateSpecBt.getFormPlateMode())) {
                    if(PmPlateConstants.ALL.equals(pmPlateSpecBt.getAdTypeMode()) || pmPlateSpecBt.getAdTypeMode().equals(getAdTypeCode)) {
                        if(PmPlateConstants.ALL.equals(pmPlateSpecBt.getRollMode()) || pmPlateSpecBt.getRollMode().equals(getRollMode)) {
                            if(pmPlateSpecBt.getWholeHeatTreatmentType().equals(PmPlateConstants.ALL)
                                    || ("Q".equals(pmPlateSpecBt.getWholeHeatTreatmentType())
                                            && wholeHeatTreatmentType != null 
                                            && wholeHeatTreatmentType.contains("Q"))) {
                                if (combinePlateWidth.compareTo(pmPlateSpecBt.getCombinePlateWidthFrom()) >= 0
                                        && combinePlateWidth.compareTo(pmPlateSpecBt.getCombinePlateWidthTo()) <= 0) {
                                    if (axisPmContBoardParam.getOrderThick().compareTo(pmPlateSpecBt.getPlateThickFrom()) >= 0
                                            && axisPmContBoardParam.getOrderThick().compareTo(pmPlateSpecBt.getPlateThickTo()) <= 0) {
                                        currentPmPlateSpecBt = pmPlateSpecBt;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    
                }
            }
        }
        if(currentPmPlateSpecBt == null) {
            throw new CommonException("pm.pm_plate_spec_bt_001" , axisPmContBoardParam.getStCode() , formPlateMode , getAdTypeCode
                    , getRollMode , axisPmContBoardParam.getOrderThick().toPlainString() ,combinePlateWidth.toPlainString() 
                    , wholeHeatTreatmentType);
        }
        if (combinePlateLen.compareTo(currentPmPlateSpecBt.getCombinePlateLenMax()) > 0) {
            // 组合长度为【combine_plate_len】，组合板长度上限为【COMBINE_PLATE_LEN_MAX】。
            throw new CommonException("pm.pm_pd_rule_set_016", axisPmContBoardParam.getStCode() , formPlateMode , getAdTypeCode
                    , getRollMode , axisPmContBoardParam.getOrderThick().toPlainString() ,combinePlateWidth.toPlainString() 
                    , wholeHeatTreatmentType, combinePlateLen.toPlainString(),
                    currentPmPlateSpecBt.getCombinePlateLenMax());
        }
        return true;
    }

}
