# EdcInqServiceImpl.java

    package com.mycim.server.wip.service;

    import com.fa.sesa.exception.Assert;
    import com.fa.sesa.exception.Errors;
    import com.mycim.framework.utils.lang.StringUtils;
    import com.mycim.framework.utils.lang.collections.CollectionUtils;
    import com.mycim.framework.utils.lang.collections.MapUtils;
    import com.mycim.framework.utils.lang.math.NumberUtils;
    import com.mycim.server.automonitor.manager.AutoMonitorItemInqManager;
    import com.mycim.server.automonitor.manager.LotAutoMonitorInqManager;
    import com.mycim.server.edc.manager.ParameterSetManager;
    import com.mycim.server.edcchart.manager.EdcSpcManager;
    import com.mycim.server.wip.manager.*;
    import com.mycim.valueobject.MessageIdList;
    import com.mycim.valueobject.automonitor.entity.AutoMonitorItemStepEdcInfo;
    import com.mycim.valueobject.automonitor.entity.LotAutoMonitorInfo;
    import com.mycim.valueobject.automonitor.util.AutoMonitorOperationConstants;
    import com.mycim.valueobject.consts.ActionPointList;
    import com.mycim.valueobject.consts.EDCConst;
    import com.mycim.valueobject.edcspc.Parameter;
    import com.mycim.valueobject.edcspc.ParameterSetVersion;
    import com.mycim.valueobject.edcspc.rule.CollectionRule;
    import com.mycim.valueobject.ems.Equipment;
    import com.mycim.valueobject.runcard.util.RunCardUtils;
    import com.mycim.valueobject.wip.*;
    import com.mycim.valueobject.wip.dto.ParameterDto;
    import com.mycim.valueobject.wip.dto.ParameterSetDto;
    import com.mycim.valueobject.wip.dto.ReadingDto;
    import com.mycim.valueobject.wip.dto.SampleDto;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;

    import java.util.*;
    import java.util.stream.Collectors;

    /**
     * @author finatice.yang
     * @date 2022/1/17
     **/
    @Service
    public class EdcInqServiceImpl implements EdcInqService {

        @Autowired
        LotInqManager lotInqManager;

        @Autowired
        LotStepHistoryInqManager lotStepHistoryInqManager;

        @Autowired
        DiffBatchQueryManager diffBatchQueryManager;

        @Autowired
        RunCardQueryManager runCardQueryManager;

        @Autowired
        LotAutoMonitorInqManager lotAutoMonitorInqManager;

        @Autowired
        AutoMonitorItemInqManager autoMonitorItemInqManager;

        @Autowired
        UnitQueryManager unitQueryManager;

        @Autowired
        ParameterSetManager parameterSetManager;

        @Autowired
        EdcQueryManager edcQueryManager;

        @Autowired
        EdcSpcManager edcSpcManager;

        @Override
        public ParameterSetDto getParameterSetDto(Lot lot, Equipment equipment) {
            ParameterSetDto parameterSetDto = null;

            if (diffBatchQueryManager.checkLotIsBatchMonitorLot(lot.getLotRrn(), equipment)) {
                List<Lot> batchLotList = diffBatchQueryManager.getBatchLotList(lot.getLotRrn());
                parameterSetDto = buildParameterSetInfoByBatch(batchLotList, equipment, lot);
            } else if (RunCardUtils.checkLotIdIsRunCardLot(lot.getLotId())) {
                parameterSetDto = buildParameterSetInfoByRunCard(lot, equipment);
            } else if (lotAutoMonitorInqManager.checkLotIsAutoMonitorLot(lot.getLotRrn())) {
                parameterSetDto = buildParameterSetInfoByAutoMonitor(lot);
            } else {
                parameterSetDto = buildParameterSetInfoByNormal(lot, equipment);
            }
            return parameterSetDto;
        }

        @Override
        public CollectionRule getAvailableDataCollectionRule(Lot lot, List<Unit> unitList, Long parameterRrn) {
            Map<String, Object> matchMap = MapUtils.newHashMap();
            matchMap.put(EDCConst.CollectionRuleMatchKey.FACILITY_RRN.getMatchKey(), lot.getFacilityRrn());
            matchMap.put(EDCConst.CollectionRuleMatchKey.EQPT_RRN.getMatchKey(), lot.getEqptRrn());
            matchMap.put(EDCConst.CollectionRuleMatchKey.PRODUCT_RRN.getMatchKey(), lot.getProductRrn());

            Long matcRecipeRrn = lot.getRecipeRrn();
            if (matcRecipeRrn == null || matcRecipeRrn.longValue() <= 0) {
                matcRecipeRrn = lot.getRecipeLogicalRrn();
            }
            matchMap.put(EDCConst.CollectionRuleMatchKey.RECIPE_RRN.getMatchKey(), matcRecipeRrn);

            return edcQueryManager.getAvailableDataCollectionRule(lot.getFacilityRrn(), lot.getLotRrn(), matchMap, unitList,
                                                                  parameterRrn);
        }

        @Override
        public String getChartOwnerHoldCode(List<ParameterDto> parameters) {
            return edcQueryManager.getChartOwnerHoldCode(parameters);
        }

        private ParameterSetDto buildParameterSetInfoByBatch(List<Lot> batchLotList, Equipment equipment, Lot lot) {

            List<ParameterDto> allParameterList = new ArrayList<>();

            for (Lot batchLot : batchLotList) {
                ParameterSetDto parameterSetInfoDto = null;

                if (RunCardUtils.checkLotIdIsRunCardLot(batchLot.getLotId())) {
                    parameterSetInfoDto = buildParameterSetInfoByRunCard(batchLot, equipment);
                } else if (lotAutoMonitorInqManager.checkLotIsAutoMonitorLot(batchLot.getLotRrn())) {
                    LotAutoMonitorInfo monitorInfo = lotAutoMonitorInqManager
                            .getLotActiveAutoMonitorInfo(batchLot.getLotRrn());
                    parameterSetInfoDto = buildAutoMonitorParameterInfo(batchLot, monitorInfo);
                } else {
                    parameterSetInfoDto = buildParameterSetInfoByNormal(batchLot, equipment);
                }

                if (Objects.nonNull(parameterSetInfoDto) &&
                        CollectionUtils.isNotEmpty(parameterSetInfoDto.getParameters())) {
                    selectParameterList(allParameterList, parameterSetInfoDto.getParameters());
                }
            }

            if (CollectionUtils.isEmpty(allParameterList)) {
                return null;
            }

            // 3. 替换量测片
            List<Unit> unitList = unitQueryManager.getUnitList(lot.getLotRrn());
            List<ParameterDto> parameterInfoDtoList = new ArrayList<>();
            for (int i = 0; i < allParameterList.size(); i++) {
                ParameterDto baseParameterInfoDto = allParameterList.get(i);
                int size = baseParameterInfoDto.getSamplePrompts().iterator().next().getReadingPrompts().size();

                String parameterId = baseParameterInfoDto.getParameterId();
                Long paramrterRrn = baseParameterInfoDto.getParameterRrn();

                ParameterDto parameterInfo = buildAllUnitParameterDto(parameterId, size, unitList);
                parameterInfo.setParameterRrn(paramrterRrn);
                parameterInfo.setParameterSequence(i + 1);
                parameterInfoDtoList.add(parameterInfo);
            }

            ParameterSetDto parameterSetDto = new ParameterSetDto();
            parameterSetDto.setParameters(parameterInfoDtoList);

            return parameterSetDto;
        }

        private void selectParameterList(List<ParameterDto> allList, List<ParameterDto> selectList) {
            for (ParameterDto select : selectList) {
                Boolean needAdd = true;
                for (ParameterDto parameterInfoDto : allList) {
                    if (StringUtils.equals(parameterInfoDto.getParameterId(), select.getParameterId())) {
                        needAdd = false;
                        break;
                    }
                }
                if (needAdd) {
                    allList.add(select);
                }
            }
        }

        private ParameterSetDto buildParameterSetInfoByAutoMonitor(Lot lot) {
            if (lotAutoMonitorInqManager.checkAutomonitorLotNeedSkipEdc(lot.getLotRrn(), lot.getStepSequence())) {
                return null;
            }

            LotAutoMonitorInfo monitorInfo = lotAutoMonitorInqManager.getLotActiveAutoMonitorInfo(lot.getLotRrn());
            ParameterSetDto parameterSetInfoDto = buildAutoMonitorParameterInfo(lot, monitorInfo);
            return parameterSetInfoDto;
        }

        private ParameterSetDto buildParameterSetInfoByRunCard(Lot lot, Equipment equipment) {
            List<ParameterSetVersion> allParameterSetVersionList = getRunCardParameterSetVersionList(lot);
            if (CollectionUtils.isEmpty(allParameterSetVersionList)) {
                return null;
            }

            List<Unit> unitList = unitQueryManager.getUnitList(lot.getLotRrn());
            unitList.stream().forEach(unit -> {
                unit.setUnitId(RunCardUtils.getShowUnitId(unit.getUnitId()));
            });

            ParameterSetDto parameterSetDto = buildParameterSetBaseInfo(allParameterSetVersionList.iterator().next());
            for (int i = 0; i < allParameterSetVersionList.size(); i++) {
                ParameterSetVersion parameterSetVersion = allParameterSetVersionList.get(i);
                Parameter parameter = (Parameter) parameterSetVersion.getParameters().iterator().next();
                if (lot.getEqptRrn() == null || lot.getEqptRrn().longValue() <= 0) {
                    lot.setEqptRrn(equipment.getInstanceRrn());
                }

                List<Unit> edcUnitList = selectEdcUnit(unitList, parameter.getSelectedUnitIds());

                ParameterDto parameterDto = buildParameterInfo(parameterSetVersion, edcUnitList, i + 1);
                parameterSetDto.getParameters().add(parameterDto);
            }
            return parameterSetDto;
        }

        private ParameterSetDto buildParameterSetInfoByNormal(Lot lot, Equipment equipment) {
            String actionPoint = ActionPointList.MOVEOUT_KEY;
            List<ParameterSetVersion> parameterSetVersionList = getParameterSetVersionList(lot, equipment, actionPoint);
            if (CollectionUtils.isEmpty(parameterSetVersionList)) {
                return null;
            }

            List<Unit> unitList = unitQueryManager.getUnitList(lot.getLotRrn());

            ParameterSetDto parameterSetInfoDto = buildParameterSetBaseInfo(parameterSetVersionList.iterator().next());
            for (int i = 0; i < parameterSetVersionList.size(); i++) {
                ParameterSetVersion parameterSetVersion = parameterSetVersionList.get(i);
                Parameter parameter = (Parameter) parameterSetVersion.getParameters().iterator().next();
                if (lot.getEqptRrn() == null || lot.getEqptRrn().longValue() <= 0) {
                    lot.setEqptRrn(equipment.getInstanceRrn());
                }

                CollectionRule collectionRule = getAvailableDataCollectionRule(lot, unitList, parameter.getInstanceRrn());
                Assert.state(Objects.nonNull(collectionRule),
                             Errors.create().content("The parameter :{} not set collection rule.")
                                   .args(parameter.getInstanceId()).build());
                List<Unit> edcUnitList = selectEdcUnit(unitList, collectionRule.getSelectedUnitIds());

                ParameterDto parameterDto = buildParameterInfo(parameterSetVersion, edcUnitList, i + 1);
                parameterSetInfoDto.getParameters().add(parameterDto);
            }
            return parameterSetInfoDto;
        }

        private List<ParameterSetVersion> getParameterSetVersionList(Lot lot, Equipment equipment, String actionPoint) {
            return parameterSetManager.buildParameterSetInfo(lot, equipment, actionPoint);
        }

        private List<ParameterSetVersion> getRunCardParameterSetVersionList(Lot lot) {
            List<ParameterSetVersion> allParameterSetVersionList = new ArrayList<>();

            LotRunCardStep lotRunCardStep = runCardQueryManager.getLotRunCardStep(lot.getLotRrn());

            if (Objects.nonNull(lotRunCardStep)) {
                Long parameterSetRrn = lotRunCardStep.getOutParameterSetRrn();
                List<ParameterSetVersion> parameterSetVersionList = parameterSetManager
                        .getActiveParameterSetVersion(parameterSetRrn);
                List<LotRunCardStepParameter> stepParameterList = runCardQueryManager
                        .getLotRunCardStepParameterList(lotRunCardStep.getRunCardRrn(), lotRunCardStep.getStepSerialNo(),
                                                        parameterSetRrn);

                String[] unitRrns = StringUtils.split(lotRunCardStep.getMeasurementUnitRrns(), StringUtils.COMMA_SIGN);
                List<String> unitIdList = new ArrayList<>();
                if (unitRrns != null) {
                    for (String unitRrn : unitRrns) {
                        unitIdList.add(unitQueryManager.getUnitIdByRrn(NumberUtils.toLong(unitRrn)));
                    }
                }

                for (LotRunCardStepParameter stepParameter : stepParameterList) {
                    String parameterId = stepParameter.getParameterId();
                    for (ParameterSetVersion parameterSetVersion : parameterSetVersionList) {
                        if (StringUtils.equals(parameterId, parameterSetVersion.getParameterId())) {
                            Parameter parameter = (Parameter) parameterSetVersion.getParameters().iterator().next();
                            parameter.setSelectedUnitIds(unitIdList.toArray(new String[unitIdList.size()]));
                            allParameterSetVersionList.add(parameterSetVersion);
                        }
                    }
                }
            }
            return allParameterSetVersionList;
        }

        private ParameterSetDto buildAutoMonitorParameterInfo(Lot lot, LotAutoMonitorInfo monitorInfo) {
            List<Map> nonRTJobList = edcSpcManager.getMainEqpNonRTJobList(monitorInfo.getMainEqptRrn());
            if (CollectionUtils.isEmpty(nonRTJobList)) {
                return null;
            }
            ParameterSetDto parameterSetInfoDto = new ParameterSetDto();
            parameterSetInfoDto.setParameters(new ArrayList<>());

            List<Unit> unitList = unitQueryManager.getUnitList(lot.getLotRrn());
            unitList.sort(new Comparator<Unit>() {
                @Override
                public int compare(Unit o1, Unit o2) {
                    return o1.getPositionInCarrier().intValue() - o2.getPositionInCarrier().intValue();
                }
            });

            List<AutoMonitorItemStepEdcInfo> edcInfoList = autoMonitorItemInqManager
                    .getEdcInfoList(monitorInfo.getWorkflowRrn(), monitorInfo.getWorkflowVersion(),
                                    monitorInfo.getWorkflowStepSequence());
            if (CollectionUtils.isEmpty(edcInfoList)) {
                return null;
            }

            String nonRTSlotType = monitorInfo.getNonRTSlotType();

            checkNonRtJobInSpc(edcInfoList, nonRTJobList, nonRTSlotType);

            if (StringUtils.equals(nonRTSlotType, AutoMonitorOperationConstants.STEP_SLOT_TYPE_WAFER)) {
                Map<String, List<Unit>> jobUnitMapping = MapUtils.newHashMap();

                for (AutoMonitorItemStepEdcInfo edcInfo : edcInfoList) {
                    String[] jobNames = StringUtils.split(edcInfo.getNonRTJobNames(), StringUtils.COMMA_SIGN);
                    for (String jobName : jobNames) {
                        if (Objects.isNull(MapUtils.getObject(jobUnitMapping, jobName))) {
                            jobUnitMapping.put(jobName, new ArrayList<>());
                        }
                        jobUnitMapping.get(jobName).add(unitList.get(edcInfo.getWaferSlot().intValue() - 1));
                    }
                }

                Integer sequence = NumberUtils.INTEGER_ONE;
                for (String jobName : jobUnitMapping.keySet()) {
                    List<Unit> jobUnits = jobUnitMapping.get(jobName);
                    Integer subGroupSize = getSubGroupSize(nonRTJobList, jobName);
                    ParameterDto parameterInfoDto = buildAllUnitParameterDto(jobName, subGroupSize, jobUnits);
                    parameterInfoDto.setParameterSequence(sequence++);
                    parameterSetInfoDto.getParameters().add(parameterInfoDto);
                }
            } else {
                AutoMonitorItemStepEdcInfo edcInfo = edcInfoList.iterator().next();
                String[] jobNames = StringUtils.split(edcInfo.getNonRTJobNames(), StringUtils.COMMA_SIGN);
                Integer sequence = NumberUtils.INTEGER_ONE;
                for (String jobName : jobNames) {
                    Integer subGroupSize = getSubGroupSize(nonRTJobList, jobName);
                    ParameterDto parameterInfoDto = buildAllUnitParameterDto(jobName, subGroupSize, unitList);
                    parameterInfoDto.setParameterSequence(sequence++);
                    parameterSetInfoDto.getParameters().add(parameterInfoDto);
                }
            }
            return parameterSetInfoDto;
        }

        private Integer getSubGroupSize(List<Map> nonRTJobList, String jobName) {
            Integer subGroupSize = NumberUtils.INTEGER_ZERO;
            for (Map map : nonRTJobList) {
                if (StringUtils.equals(MapUtils.getString(map, "JobName"), jobName)) {
                    subGroupSize = MapUtils.getInteger(map, "SubgroupSize");
                    break;
                }
            }
            return subGroupSize;
        }

        private void rebuildParameterSelectUnitId(SRCLotSpecialStep lotSpecialStep,
                                                  ParameterSetVersion parameterSetVersion) {
            Parameter parameter = (Parameter) parameterSetVersion.getParameters().iterator().next();
            parameter.setSelectedUnitIds(StringUtils.split(lotSpecialStep.getMeasSlotId(), StringUtils.COMMA_SIGN));
        }

        private List<Unit> selectEdcUnit(List<Unit> unitList, String[] selectUnitId) {
            List<Unit> edcUnitList = unitList.stream().filter(unit -> {
                for (String unitId : selectUnitId) {
                    if (StringUtils.equals(unit.getUnitId(), unitId)) {
                        return true;
                    }
                }
                return false;
            }).collect(Collectors.toList());
            return edcUnitList;
        }

        private ParameterSetDto buildParameterSetBaseInfo(ParameterSetVersion parameterSetVersion) {
            ParameterSetDto parameterSetDto = new ParameterSetDto();

            parameterSetDto.setParameterSetRrn(parameterSetVersion.getInstanceRrn());
            parameterSetDto.setParameterSetVersion(parameterSetVersion.getInstanceVersion());
            parameterSetDto.setParameterSetSpecRrn(parameterSetVersion.getParameterSetSpecRrn());
            parameterSetDto.setParameterSetDesc(parameterSetVersion.getInstanceDesc());

            parameterSetDto.setParameters(new ArrayList<>());
            return parameterSetDto;
        }

        private ParameterDto buildParameterInfo(ParameterSetVersion parameterSetVersion, List<Unit> unitList,
                                                int parameterSequence) {
            Parameter parameter = (Parameter) parameterSetVersion.getParameters().iterator().next();

            ParameterDto parameterDto = buildAllUnitParameterDto(parameter.getInstanceId(),
                                                                 parameter.getReadingPrompts().size(), unitList);
            parameterDto.setParameterRrn(parameter.getInstanceRrn());
            parameterDto.setParameterId(parameter.getInstanceId());
            parameterDto.setParameterDesc(parameter.getInstanceDesc());
            parameterDto.setParameterSequence(parameterSequence);
            parameterDto.setcollectionLevel(parameterSetVersion.getCollectionLevel());
            parameterDto.setDataType(parameterSetVersion.getDataType());
            parameterDto.setMeasureType(parameterSetVersion.getMeasureType());
            return parameterDto;
        }

        private ParameterDto buildAllUnitParameterDto(String jobName, Integer subGroupSize, List<Unit> unitList) {
            ParameterDto parameterInfoDto = new ParameterDto();
            parameterInfoDto.setParameterId(jobName);
            parameterInfoDto.setSamplePrompts(new ArrayList<SampleDto>());
            for (int j = 0; j < unitList.size(); j++) {
                Unit unit = unitList.get(j);
                SampleDto sampleInfoDto = new SampleDto();
                sampleInfoDto.setUnitId(unit.getUnitId());
                sampleInfoDto.setUnitRrn(unit.getUnitRrn());
                sampleInfoDto.setPosition(unit.getPositionInCarrier() + "");
                sampleInfoDto.setReadingPrompts(new ArrayList<ReadingDto>());
                sampleInfoDto.setSampleSequence(j + 1);

                for (int k = 0; k < subGroupSize; k++) {
                    ReadingDto readingInfoDto = new ReadingDto();
                    String readingId = EDCConst.READING_ID_PREFIX + (k + 1);
                    readingInfoDto.setReadingId(readingId);
                    readingInfoDto.setReadingSequence(k + 1);
                    sampleInfoDto.getReadingPrompts().add(readingInfoDto);
                }
                parameterInfoDto.getSamplePrompts().add(sampleInfoDto);
            }
            return parameterInfoDto;
        }

        private void checkNonRtJobInSpc(List<AutoMonitorItemStepEdcInfo> edcInfoList, List<Map> nonRTJobList,
                                        String slotType) {

            List<String> notInSpcJobNameList = new ArrayList<>();
            if (StringUtils.equals(slotType, AutoMonitorOperationConstants.STEP_SLOT_TYPE_WAFER)) {
                for (AutoMonitorItemStepEdcInfo edcInfo : edcInfoList) {
                    String[] jobNames = StringUtils.split(edcInfo.getNonRTJobNames(), StringUtils.COMMA_SIGN);

                    for (String jobName : jobNames) {
                        boolean notInSpc = true;
                        for (Map map : nonRTJobList) {
                            if (StringUtils.equals(MapUtils.getString(map, "JobName"), jobName)) {
                                notInSpc = false;
                                break;
                            }
                        }
                        if (notInSpc && !notInSpcJobNameList.contains(jobName)) {
                            notInSpcJobNameList.add(jobName);
                        }
                    }
                }
            } else {
                AutoMonitorItemStepEdcInfo edcInfo = edcInfoList.iterator().next();
                String[] jobNames = StringUtils.split(edcInfo.getNonRTJobNames(), StringUtils.COMMA_SIGN);
                for (String jobName : jobNames) {
                    boolean notInSpc = true;
                    for (Map map : nonRTJobList) {
                        if (StringUtils.equals(MapUtils.getString(map, "JobName"), jobName)) {
                            notInSpc = false;
                            break;
                        }
                    }
                    if (notInSpc && !notInSpcJobNameList.contains(jobName)) {
                        notInSpcJobNameList.add(jobName);
                    }
                }
            }

            Assert.state(CollectionUtils.isEmpty(notInSpcJobNameList),
                         Errors.create().key(MessageIdList.AUTOMONITOR_NONRT_NOT_IN_SPC)
                               .args(notInSpcJobNameList.toString()).build());
        }

    }