# SorterExecInqManagerImpl.java

    package com.mycim.server.sorter.exec.manager.impl;

    import com.fa.sesa.i18n.I18nUtils;
    import com.fa.sesa.threadlocal.LocalContext;
    import com.fa.sesa.threadlocal.LocalContextNames;
    import com.mycim.framework.utils.lang.StringUtils;
    import com.mycim.framework.utils.lang.collections.CollectionUtils;
    import com.mycim.server.carrier.manager.CarrierManager;
    import com.mycim.server.ems.manager.EquipmentManager;
    import com.mycim.server.sorter.exec.manager.SorterExecInqManager;
    import com.mycim.server.sorter.manager.SorterManager;
    import com.mycim.server.spec.manager.ProcessSpecItemManager;
    import com.mycim.server.system.manager.ReferenceFileManager;
    import com.mycim.server.wip.manager.LotInqManager;
    import com.mycim.server.wip.manager.LotQueryManager;
    import com.mycim.server.wip.manager.RunCardQueryManager;
    import com.mycim.server.wip.manager.job.EquipmentCheckManager;
    import com.mycim.utils.SorterUtils;
    import com.mycim.utils.WipUtils;
    import com.mycim.valueobject.MessageIdList;
    import com.mycim.valueobject.consts.ReferenceDetailNames;
    import com.mycim.valueobject.consts.ReferenceFileConst;
    import com.mycim.valueobject.consts.SorterEnum;
    import com.mycim.valueobject.ems.Carrier;
    import com.mycim.valueobject.ems.Equipment;
    import com.mycim.valueobject.runcard.util.RunCardUtils;
    import com.mycim.valueobject.sorter.SorterModel;
    import com.mycim.valueobject.sys.ReferenceFileDetail;
    import com.mycim.valueobject.wip.Lot;
    import com.mycim.valueobject.wip.LotRunCardStore;
    import com.mycim.valueobject.wip.LotStatus;
    import com.mycim.valueobject.wip.SRCLotSpecialStep;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;

    import java.util.List;
    import java.util.regex.Matcher;
    import java.util.stream.Collectors;

    @Service
    @Transactional
    public class SorterExecInqManagerImpl implements SorterExecInqManager {
        @Autowired
        SorterManager sorterManager;

        @Autowired
        EquipmentManager equipmentManager;

        @Autowired
        EquipmentCheckManager equipmentCheckManager;

        @Autowired
        CarrierManager carrierManager;

        @Autowired
        LotInqManager lotInqManager;

        @Autowired
        LotQueryManager lotQueryManager;

        @Autowired
        ProcessSpecItemManager processSpecItemManager;

        @Autowired
        ReferenceFileManager referenceFileManager;

        @Autowired
        RunCardQueryManager runCardQueryManager;

        @Override
        public SorterModel checkSorterModelAndCreateInLineSorterJob(Lot lot, String equipmentId, String targetCarrierId) {
            SorterModel sorterModel = checkSorterModel(lot.getCarrierId(), equipmentId);
            if (sorterModel.getCanCreate()) {
                sorterManager.createSorterJobByInLine(sorterModel, lot, targetCarrierId);
            }
            return sorterModel;
        }

        @Override
        public SorterModel checkSorterModel(String carrierId, String equipmentId) {
            SorterModel sorterModel = new SorterModel(SorterEnum.Type.OFFLINE.getName());
            // 公用check
            //1.先check设备是否为Sorter 设备
            Equipment equipment = equipmentManager.getEquipment(equipmentId, LocalContext.getFacilityRrn());
            String msg = SorterUtils.checkEqptSorterFlag(equipment);
            if (StringUtils.isNotEmptyTrim(msg)) {
                sorterModel.setMsg(msg);
            }
            //2.check Carrier
            if (StringUtils.isEmpty(carrierId)) {
                return sorterModel;
            }
            Carrier carrier = carrierManager.getCarrier(LocalContext.getFacilityRrn(), carrierId);
            //3.check Lot 状态
            //3.1 新增前置check,避免一个CST下多个Lot
            List<Lot> lots = lotInqManager.getLotListByCarrierRrn(carrier.getInstanceRrn());
            if (CollectionUtils.isEmpty(lots) || lots.size() > 1) {
                return sorterModel;
            }
            //3.2 check Lot 状态
            Lot lot = lotQueryManager.getLotByCarrierId(carrierId, LocalContext.getFacilityRrn());
            // MAINRC 转换
            if (LotStatus.isRunCardHold(lot.getLotStatus())) {
                lot = lotInqManager.getLot(RunCardUtils.buildMainRcLotId(lot.getLotId()));
            }
            if (!StringUtils.equalsIgnoreCase(lot.getLotStatus(), LotStatus.WAITING)) {
                return sorterModel;
            }
            //4.check Lot 当站是否在该设备可用
            if (StringUtils.isNotEmptyTrim(
                    equipmentCheckManager.checkEqptJobByOperation(lot.getOperationRrn(), equipment.getInstanceRrn()))) {
                return sorterModel;
            }
            //5.check Eqpt 状态
            if (StringUtils.isNotEmptyTrim(equipmentCheckManager.checkEqptStatus(lot, equipment))) {
                return sorterModel;
            }
            //6. 预留不同的Job Type卡控
            //6.1.check Job Type
            if (isFlipSide(lot, sorterModel)) {
                return sorterModel;
            }

            if (isReadT7Code(lot, sorterModel)) {
                return sorterModel;
            }

            if (!StringUtils.isNotEmptyTrim(msg) && isExchange(lot, sorterModel)) {
                return sorterModel;
            }
            return sorterModel;
        }

        private boolean isExchange(Lot lot, SorterModel sorterModel) {
            String transModule = LocalContext.get(LocalContextNames.TRANS_MODULE_KEY);
            // manual 不做exchange
            if (WipUtils.MANUAL.equalsIgnoreCase(transModule)) {
                return false;
            }

            //如果是runcard lot 暂时跳过
            if (RunCardUtils.checkLotIdIsRunCardLot(lot.getLotId())) {
               return false;
            }
            String processLocation = StringUtils.EMPTY;
            processLocation = getProcessLocationByProcess(lot);
            String carrierType = referenceFileManager.getRefFileValue(ReferenceDetailNames.PROCESS_LOCARION_CARRIER_TYPE,
                                                               processLocation, ReferenceFileConst.DATA_1_VALUE);
            Matcher mathcher = WipUtils.PCDPATERN.matcher(carrierType);
            Boolean match = mathcher.matches();
            if (match) {
                sorterModel.setSorterType(SorterEnum.Type.INLINE.getName());
                sorterModel.setJobType(SorterEnum.Constant.EXCHANGE);
                return true;
            }else {
                return false;
            }
        }

        private boolean isFlipSide(Lot lot, SorterModel sorterModel) {
            //判断lot
            String flipType;
            if (RunCardUtils.checkLotIdIsRunCardLot(lot.getLotId())) {
                flipType = getFlipTypeByRunCard(lot);
            } else {
                flipType = getFlipTypeByProcess(lot);
            }

            // check 是否需要翻面
            if (StringUtils.contains(flipType, '-')) {
                // check Flip 合法性
                checkFlipType(lot, flipType, sorterModel);
                sorterModel.setSorterType(SorterEnum.Type.INLINE.getName());
                sorterModel.setJobType(SorterEnum.Constant.FLIP_SIDE);
                return true;
            } else {
                return false;
            }
        }

        private void checkFlipType(Lot lot, String flipType, SorterModel sorterModel) {
            // 拿到所有Flip Type
            List<String> flipTypes = referenceFileManager.getRefFileValues(ReferenceDetailNames.SORTER_FLIP_TYPE,
                                                                           LocalContext.getFacilityRrn()).stream()
                                                         .map(ReferenceFileDetail::getKey1Value)
                                                         .collect(Collectors.toList());
            List<String> strList = StringUtils.splitAsList(flipType, "-");
            // 验证数量是否正确
            if (strList.size() != 2) {
                sorterModel.appendMsg(I18nUtils.getMessage(MessageIdList.SORTER_REFERENCE_FILE_ERROR,
                                                           "ReferenceFile：{} have error data exist. --> {}",
                                                           ReferenceDetailNames.SORTER_FLIP_TYPE, flipType));
                return;
            }

            // 验证两边Flip Type是否存在
            for (String s : strList) {
                if (!flipTypes.contains(s)) {
                    sorterModel.appendMsg(
                            I18nUtils.getMessage(MessageIdList.SORTER_FLIP_TYPE_NOT_EXIST, "{} Flip Type not exist", s));
                    return;
                }
            }

            //验证当前Lot的Flip Type是否与翻面的类型一致
            if (!StringUtils.equalsIgnoreCase(strList.get(0), lot.getFlipType())) {
                sorterModel.appendMsg(I18nUtils.getMessage(MessageIdList.SORTER_FLIP_TYPE_NOT_MATCH,
                                                           "The current Flip Type {} is inconsistent with the" + " " +
                                                                   "expected Flip Type {} and cannot be done " + "Flip" +
                                                                   " Side", lot.getFlipType(), strList.get(0)));
            }
        }

        private String getFlipTypeByRunCard(Lot lot) {
            //获取SRC中当前flip type
            LotRunCardStore lotStore = runCardQueryManager.getSplitRunCardLotStore(lot.getLotRrn());
            Long lotSpecialStepRrn = lotStore.getLotSpecialStepRrn();
            SRCLotSpecialStep lotSpecialStep = runCardQueryManager
                    .getLotSplitRunCardSpecialStep(lotSpecialStepRrn, lotStore.getStepSequence());
            if (lotSpecialStep != null && lotSpecialStep.getLotSpecialStepRrn() > 0) {
                return StringUtils.isNotBlank(lotSpecialStep.getFlipType())? lotSpecialStep.getFlipType() : StringUtils.EMPTY;
            }
            return StringUtils.EMPTY;
        }

        private String getFlipTypeByProcess(Lot lot) {
            return processSpecItemManager.getFlipType(lot.getProcessRrn(), lot.getProcessVersion(), lot.getRouteRrn(),
                                                      lot.getOperationRrn());
        }

        private String getProcessLocationByProcess(Lot lot) {
            return processSpecItemManager.getProcessLocation(lot.getProcessRrn(), lot.getProcessVersion(),
                                                             lot.getRouteRrn(), lot.getRouteVersion(), lot.getOperationRrn());
        }

        private boolean isReadT7Code(Lot lot, SorterModel sorterModel) {
            //check step是否在类表$$INLINE_READ_T7CODE中存在
            List<String> stepIds = referenceFileManager.getRefFileValues(ReferenceDetailNames.READ_CUSTOMER_T7CODE_STEP,
                                                                         LocalContext.getFacilityRrn()).stream()
                                                       .map(ReferenceFileDetail::getKey1Value).collect(Collectors.toList());

            if (stepIds.contains(lot.getOperationId())) {
                sorterModel.setSorterType(SorterEnum.Type.INLINE.getName());
                sorterModel.setJobType(SorterEnum.Constant.READ_T7CODE);
                return true;
            } else {
                return false;
            }

        }

    }