# EdcQueryManagerImpl.java

    package com.mycim.server.wip.manager.impl;

    import com.fa.sesa.exception.Assert;
    import com.fa.sesa.exception.Errors;
    import com.fa.sesa.exception.SystemIllegalArgumentException;
    import com.fa.sesa.threadlocal.LocalContext;
    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.base.manager.NamedObjectManager;
    import com.mycim.server.ctx.exec.manager.EdcLotContextManager;
    import com.mycim.server.edc.manager.DataCollectionRuleManager;
    import com.mycim.server.edc.manager.ParameterRuleManager;
    import com.mycim.server.edc.manager.ParameterSetManager;
    import com.mycim.server.system.manager.ReferenceFileManager;
    import com.mycim.server.wip.dao.EdcQueryDAO;
    import com.mycim.server.wip.manager.*;
    import com.mycim.utils.ChartNamingRule;
    import com.mycim.valueobject.MessageIdList;
    import com.mycim.valueobject.ObjectList;
    import com.mycim.valueobject.bas.NamedObject;
    import com.mycim.valueobject.consts.ActionPointList;
    import com.mycim.valueobject.consts.EDCConst;
    import com.mycim.valueobject.consts.HoldCodeNames;
    import com.mycim.valueobject.consts.ReferenceDetailNames;
    import com.mycim.valueobject.edcspc.*;
    import com.mycim.valueobject.edcspc.responseModel.ParameterRuleDetailResponse;
    import com.mycim.valueobject.edcspc.rule.CollectionRule;
    import com.mycim.valueobject.edcspc.rule.CollectionRuleFactory;
    import com.mycim.valueobject.edcspc.rule.SpecialRule;
    import com.mycim.valueobject.ems.Equipment;
    import com.mycim.valueobject.prp.EdcLotContextValue;
    import com.mycim.valueobject.sys.ReferenceFileDetail;
    import com.mycim.valueobject.wip.BatchLotStore;
    import com.mycim.valueobject.wip.Lot;
    import com.mycim.valueobject.wip.Unit;
    import com.mycim.valueobject.wip.dto.ParameterDto;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;

    import java.util.*;

    /**
     * @author Johnson.Wang
     * @version 6.0.0
     * @date 2019/9/27
     **/
    @Service
    @Transactional
    public class EdcQueryManagerImpl implements EdcQueryManager {

        @Autowired
        private NamedObjectManager namedObjectManager;

        @Autowired
        private EdcQueryDAO edcQueryDAO;

        @Autowired
        private UnitQueryManager unitQueryManager;

        @Autowired
        private LotQueryManager lotQueryManager;

        @Autowired
        private EdcLotContextManager edcLotContextManager;

        @Autowired
        private ParameterSetManager parameterSetManager;

        @Autowired
        private DataCollectionRuleManager dataCollectionRuleManager;

        @Autowired
        private ParameterRuleManager parameterRuleManager;

        @Autowired
        private OcapQueryManager ocapQueryManager;

        @Autowired
        private DiffBatchQueryManager diffBatchQueryManager;

        @Autowired
        private ReferenceFileManager referenceFileManager;

        @Override
        public double getParamValByCondition(long lotRrn, long operationRrn, long productRrn, long processRrn,
                                             long parameterRrn, String puType) {
            return edcQueryDAO.getParamValByCondition(lotRrn, operationRrn, productRrn, processRrn, parameterRrn, puType);
        }

        @Override
        public List<ParameterSetVersion> getParameterSetWithMonitorLot(Lot lot, Equipment equipment) {
            Long parameterSetRrn = null;
            List parameterSetVersions = null;
            List<BatchLotStore> list = diffBatchQueryManager.getBatchStoreListByLot(lot.getLotRrn());
            if (CollectionUtils.isNotEmpty(list)) {
                for (BatchLotStore bonding : list) {
                    Long toLotRrn = bonding.getLotRrn();
                    Lot toLot = lotQueryManager.getLot(toLotRrn);
                    EdcLotContextValue edcLotContextValue = edcLotContextManager
                            .getEdcLotContextValue(toLot, equipment, ActionPointList.MOVEOUT_KEY);
                    if (edcLotContextValue != null && edcLotContextValue.getParameterSetRrn() != null) {
                        if (parameterSetRrn == null) {
                            parameterSetRrn = edcLotContextValue.getParameterSetRrn();
                            parameterSetVersions = parameterSetManager
                                    .buildParameterSetInfo(toLot, equipment, ActionPointList.MOVEOUT_KEY);
                        } else if (parameterSetRrn.longValue() != edcLotContextValue.getParameterSetRrn().longValue()) {
                            throw new SystemIllegalArgumentException(
                                    Errors.create().content("Batch lots not the same edcplan.").build());
                        }
                    }
                }
            }
            return parameterSetVersions;
        }

        /**
         * 获取可用的规则
         *
         * @param unitList
         * @param parameterRrn
         * @return
         */
        @Override
        public CollectionRule getAvailableDataCollectionRule(List<Unit> unitList, Long parameterRrn) {
            List<DataCollectionRule> collectionRules = dataCollectionRuleManager.getDataCollectionRules(parameterRrn);
            Assert.isFalse(collectionRules.size() == 0,
                           Errors.create().key(MessageIdList.RULE_MISSING).content("规则不存在！").build());

            CollectionRule collectionRule = null;
            for (DataCollectionRule dataCollectionRule : collectionRules) {
                collectionRule = new CollectionRuleFactory(dataCollectionRule, unitList).getAndCheckAvailableRule();
                if (collectionRule != null) {
                    return collectionRule;
                }
            }

            return null;
        }

        /**
         * 获取可用的规则
         *
         * @param unitList
         * @param parameterRrn
         * @return
         */
        @Override
        public CollectionRule getAvailableDataCollectionRule(Long facilityRrn, Long lotRrn, Map<String, Object> matchMap,
                                                             List<Unit> unitList, Long parameterRrn) {

            List<DataCollectionRule> collectionRules = getDataCollectionRules(matchMap, parameterRrn);

            Long eqptRrn = MapUtils.getLongValue(matchMap, EDCConst.CollectionRuleMatchKey.EQPT_RRN.getMatchKey());
            Long productRrn = MapUtils.getLongValue(matchMap, EDCConst.CollectionRuleMatchKey.PRODUCT_RRN.getMatchKey());

            String remeasureUnitIds = ocapQueryManager.getRemeasureUnitIds(facilityRrn, lotRrn, parameterRrn);

            CollectionRule collectionRule = null;
            boolean newRuleFlag = false;
            String ruleId = "";
            for (DataCollectionRule dataCollectionRule : collectionRules) {
                if (StringUtils.isNotEmpty(remeasureUnitIds)) {
                    dataCollectionRule.setRuleId(EDCConst.CollectionRuleEnum.OCAP.toString());
                    dataCollectionRule.setCollectionRule(EDCConst.CollectionRuleEnum.OCAP.toString());
                    dataCollectionRule.setWaferSample(remeasureUnitIds);
                    newRuleFlag = true;
                } else if (StringUtils.equals(EDCConst.CollectionRuleEnum.SEARCHSTEP.toString(),
                                              dataCollectionRule.getCollectionRule())) {
                    newRuleFlag = true;
                } else {
                    ruleId = dataCollectionRule.getRuleId();
                    // 只能是1-25的正整数
                    if (NumberUtils.isParsable(ruleId) && !StringUtils.contains(ruleId, ".")) {
                        // ruleId 是数字，使用新规则处理(新规则的处理，实际上是将规则重新构建成special模式的数据结构)
                        int units = NumberUtils.toInt(ruleId);
                        if (units > 0 && units < 26) {
                            newRuleFlag = buildDataCollectionRuleToSpecial(eqptRrn, productRrn, parameterRrn,
                                                                           unitList.size(), units, dataCollectionRule);
                        }
                    }
                }

                if (newRuleFlag) {
                    collectionRule = new CollectionRuleFactory(dataCollectionRule, unitList).getAndCheckAvailableRule();
                    if (collectionRule != null) {
                        return collectionRule;
                    }
                }
            }
            return null;
        }

        /**
         * 获取规则
         *
         * @param unitList
         * @param parameterSetRrn
         * @param parameterSetVersion
         * @param parameterRrn
         * @return
         */
        @Override
        public CollectionRule getDataCollectionRule(List<Unit> unitList, Long parameterSetRrn, Integer parameterSetVersion,
                                                    Long parameterRrn) {
            List<DataCollectionRule> collectionRules = dataCollectionRuleManager
                    .getDataCollectionRules(parameterSetRrn, parameterSetVersion, parameterRrn);

            CollectionRule collectionRule = null;
            for (DataCollectionRule dataCollectionRule : collectionRules) {
                collectionRule = new CollectionRuleFactory(dataCollectionRule, unitList).getDataCollectionRule();
                if (collectionRule != null) {
                    return collectionRule;
                }
            }

            return null;
        }

        /**
         * 获取当前参数集当前版本当前参数的数据采集规则
         *
         * @param matchMap
         * @param parameterRrn
         * @return
         */
        @Override
        public List<DataCollectionRule> getDataCollectionRules(Map<String, Object> matchMap, Long parameterRrn) {
            List<DataCollectionRule> dataCollectionRules = dataCollectionRuleManager.getDataCollectionRules(parameterRrn);
            if (dataCollectionRules == null) {
                dataCollectionRules = new ArrayList<>();
            }

            buildId4MatchMap(matchMap);
            for (DataCollectionRule dataCollectionRule : dataCollectionRules) {
                String collectionRule = dataCollectionRule.getCollectionRule();
                if (ParameterRule.ParameterRuleType.SPECIAL.getValue().equals(collectionRule)) {
                    WaferSelectionMain mainCondition = new WaferSelectionMain();
                    mainCondition.setEqptId(
                            MapUtils.getStringCheckNull(matchMap, EDCConst.CollectionRuleMatchKey.EQPT_ID.getMatchKey()));

                    List<ParameterRuleDetailResponse> details = dataCollectionRuleManager
                            .getSpecialRuleDetailByRule(dataCollectionRule.getRuleRrn());
                    dataCollectionRule.setRuleDetail(details);
                }
                dataCollectionRule.setCollectionRule(ParameterRule.ParameterRuleType.parseCollectionRule(collectionRule));
            }

            return dataCollectionRules;
        }

        @Override
        public List<Map<String, Object>> getAllDataCollectionPointInfoByDcolRrn(Long dcolRrn) {
            List<Map<String, Object>> result = edcQueryDAO.getAllDataCollectionPointInfoByDcolRrn(dcolRrn);
            if (CollectionUtils.isEmpty(result)) {
                result = Collections.emptyList();
            }
            return result;
        }

        @Override
        public List<Parameter> getLotEdcInfoList(Lot lot, Equipment equipment) {
            List<Parameter> paramList = new ArrayList<Parameter>();

            EdcLotContextValue edcLotContextValue = edcLotContextManager
                    .getEdcLotContextValue(lot, equipment, ActionPointList.MOVEOUT_KEY);

            Long parameterSetRrn = edcLotContextValue.getParameterSetRrn();

            if (parameterSetRrn == null || parameterSetRrn.longValue() <= 0) {
                return null;
            }

            //1.获取parameter
            List<ParameterSetVersion> parameterSetVersions = parameterSetManager
                    .getActiveParameterSetVersion(parameterSetRrn);

            for (ParameterSetVersion parameterSetVersion : parameterSetVersions) {
                List<Parameter> parameters = (List<Parameter>) parameterSetVersion.getParameters();
                for (Parameter parameter : parameters) {
                    Map<String, Object> matchMap = new HashMap<String, Object>();
                    matchMap.put(EDCConst.CollectionRuleMatchKey.FACILITY_RRN.getMatchKey(), lot.getFacilityRrn());
                    matchMap.put(EDCConst.CollectionRuleMatchKey.EQPT_RRN.getMatchKey(), equipment.getInstanceRrn());
                    matchMap.put(EDCConst.CollectionRuleMatchKey.PRODUCT_RRN.getMatchKey(), lot.getProductRrn());
                    matchMap.put(EDCConst.CollectionRuleMatchKey.RECIPE_RRN.getMatchKey(), lot.getRecipeLogicalRrn());

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

                    CollectionRule collectionRule = getAvailableDataCollectionRule(lot.getFacilityRrn(), lot.getLotRrn(),
                                                                                   matchMap, unitsList,
                                                                                   parameter.getInstanceRrn());

                    if (collectionRule != null) {
                        parameter.setSelectedUnitIds(collectionRule.getSelectedUnitIds());
                        parameter.setSelectedUnitPositions(collectionRule.getSelectedUnitPositions());
                    }
                    paramList.add(parameter);
                }
            }
            return paramList;
        }

        @Override
        public String getChartOwnerHoldCode(List<ParameterDto> parameters) {
            String holdCode = HoldCodeNames.PIE_PIE_ENG;
            if (CollectionUtils.isEmpty(parameters)) {
                return holdCode;
            }
            String parameterId = parameters.get(0).getParameterId();
            String code = ChartNamingRule.getCodeRepresentedAsModule(parameterId);
            String owner = referenceFileManager.getRefValue(ReferenceDetailNames.SPC_CHART_OWNER, code);
            if (StringUtils.isBlank(owner)) {
                return holdCode;
            }

            NamedObject holdCodeNmdObj = namedObjectManager.getNamedObject("$HOLD_CODE", namedObjectManager.getNamedSpace(
                    LocalContext.getFacilityRrn(), ObjectList.SUB_TECHNOLOGY), ObjectList.REFERENCE_FILE_KEY);
            if (holdCodeNmdObj == null) { //数据库数据安全校验
                return holdCode;
            }
            long holdCodeRrn = holdCodeNmdObj.getInstanceRrn();
            if (holdCodeRrn <= 0) {//rrn 合法校验
                return holdCode;
            }
            //通过rrn 找到明细
            List<ReferenceFileDetail> referenceFileDetails = referenceFileManager.getRefFileValues(holdCodeRrn);
            if (CollectionUtils.isEmpty(referenceFileDetails)) { //detail 合法校验
                return holdCode;
            }
            //按照需求规则拼接
            String chartOwnerHoldCode = String.format("%s_%s_ENG", owner, owner);

            //找出按照规则设置的 hold code 信息
            ReferenceFileDetail referenceFileDetail = referenceFileDetails.stream()
                                                                          .filter((e) -> StringUtils.equalsIgnoreCase(
                                                                                  e.getKey1Value(),
                                                                                  chartOwnerHoldCode))
                                                                          .findFirst().orElse(null);
            if (referenceFileDetail == null) {//没有设置 hold code
                return holdCode;
            }

            holdCode = chartOwnerHoldCode;

            return holdCode;
        }

        /**
         * 匹配新规则，返回抽片位置数组
         */
        public String[] getNewRuleSelectedWafer(Long eqptRrn, Long productRrn, Long parameterRrn, int units, int waferQty) {
            String eqptId = namedObjectManager.getInstanceId(eqptRrn);
            String prodId = namedObjectManager.getInstanceId(productRrn);
            String paramId = namedObjectManager.getInstanceId(parameterRrn);

            // param的匹配有点特殊，因为chart的导入创建的parameter id中会在第二位自动添加一个M，
            // 手动在MES中添加的不会有M
            // 所以匹配的时候两种情况都考虑
            String relation = ChartNamingRule.getChartRuleRelationByParameterId(paramId);

            List<NewParameterRule> ruleList = parameterRuleManager.getNewRulesByMatch(eqptId, prodId, relation, units);
            NewParameterRule rule = new NewParameterRule();
            if (CollectionUtils.isNotEmpty(ruleList)) {
                if (ruleList.size() > 0) {
                    // 产品是否已优先匹配
                    boolean productMatchFlag = false;

                    // 设备是否已优先匹配
                    boolean eqptMatchFlag = false;
                    int prodMaxLen = 0;
                    for (NewParameterRule r : ruleList) {
                        if (r.getProductId().length() > prodMaxLen && StringUtils.equals(eqptId, r.getEqptId()) &&
                                !StringUtils.equals("*", r.getProductId())) {
                            rule = r;
                            break;
                        }
                        if (r.getProductId().length() > prodMaxLen && !StringUtils.equals("*", r.getProductId())) {
                            prodMaxLen = r.getProductId().length();
                            rule = r;
                            productMatchFlag = true;
                        }
                        if (StringUtils.equals(eqptId, r.getEqptId())) {
                            if (!productMatchFlag) {
                                rule = r;
                                eqptMatchFlag = true;
                            }
                        }
                        if (!productMatchFlag && !eqptMatchFlag) {
                            rule = r;
                        }
                    }

                    String selectedWafers = rule.getActuallyChooseWafers(waferQty);
                    if (StringUtils.isNotBlank(selectedWafers)) {
                        return StringUtils.split(selectedWafers, ",");
                    }
                }
            }
            return new String[0];
        }

        private void buildId4MatchMap(Map<String, Object> matchMap) {
            Long eqptRrn = MapUtils.getLongValue(matchMap, EDCConst.CollectionRuleMatchKey.EQPT_RRN.getMatchKey());
            Long productRrn = MapUtils.getLongValue(matchMap, EDCConst.CollectionRuleMatchKey.PRODUCT_RRN.getMatchKey());
            Long recipeRrn = MapUtils.getLongValue(matchMap, EDCConst.CollectionRuleMatchKey.RECIPE_RRN.getMatchKey());

            matchMap.put(EDCConst.CollectionRuleMatchKey.EQPT_ID.getMatchKey(), namedObjectManager.getInstanceId(eqptRrn));
            matchMap.put(EDCConst.CollectionRuleMatchKey.PRODUCT_ID.getMatchKey(),
                         namedObjectManager.getInstanceId(productRrn));
            matchMap.put(EDCConst.CollectionRuleMatchKey.RECIPE_ID.getMatchKey(),
                         namedObjectManager.getInstanceId(recipeRrn));
        }

        /**
         * 匹配新规则，将新规则数据结构重构为SPECIAL模式
         *
         * @param eqptRrn            机台
         * @param productRrn         批次product
         * @param parameterRrn       chart
         * @param waferQty           批次上的晶圆数
         * @param units              要采集的片数
         * @param dataCollectionRule 参数，参数规则集合 信息
         * @return true 匹配上新规则，false 没有匹配上新规则
         */
        private boolean buildDataCollectionRuleToSpecial(long eqptRrn, long productRrn, long parameterRrn, int waferQty,
                                                         int units, DataCollectionRule dataCollectionRule) {
            String[] selectedWafers = getNewRuleSelectedWafer(eqptRrn, productRrn, parameterRrn, units, waferQty);
            if (selectedWafers != null && selectedWafers.length > 0) {
                List<ParameterRuleDetailResponse> ruleDetailList = buildNewRuleToSpecialRuleDetail(
                        dataCollectionRule.getRuleRrn(), waferQty, selectedWafers, units);
                dataCollectionRule.setRuleDetail(ruleDetailList);
                // 不论之前是什么模式，匹配上后，都重置为SPECIAL模式
                dataCollectionRule.setCollectionRule(ParameterRule.ParameterRuleType.SPECIAL.toString());
                dataCollectionRule.setCollectionRuleSequence(1);

                String waferSample = StringUtils.EMPTY;
                for (int i = 0; i < selectedWafers.length; i++) {
                    int waferIndex = Integer.parseInt(selectedWafers[i]);
                    waferSample += waferIndex + ",";
                }
                waferSample = StringUtils.removeLastChar(waferSample, ",");
                dataCollectionRule.setWaferSampleByNewParamRule(waferSample);
                return true;
            }
            return false;
        }

        private List<ParameterRuleDetailResponse> buildNewRuleToSpecialRuleDetail(long ruleRrn, int rangeEnd,
                                                                                  String[] selectedWafer, int units) {
            ParameterRuleDetailResponse detail = new ParameterRuleDetailResponse();
            detail.setDetailSeq(1);
            detail.setQtyRangeEnd(rangeEnd);
            detail.setQtyRangeStart(1);
            detail.setRuleRrn(ruleRrn);

            String specialSelectedWafer = StringUtils.EMPTY;
            for (int i = 0; i < selectedWafer.length; i++) {
                int waferIndex = Integer.parseInt(selectedWafer[i]);
                if (waferIndex == 1) {
                    specialSelectedWafer += SpecialRule.TOP_KEY + ",";
                } else {
                    specialSelectedWafer += SpecialRule.TOP_KEY + "+" + (waferIndex - 1) + ",";
                }
            }
            specialSelectedWafer = StringUtils.removeLastChar(specialSelectedWafer, ",");

            detail.setSelectedWafer(specialSelectedWafer);
            detail.setWaferNum(units);

            List<ParameterRuleDetailResponse> list = new ArrayList<ParameterRuleDetailResponse>();
            list.add(detail);
            return list;
        }

    }