# AttributeSetupManagerImpl.java

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

    import com.mycim.framework.utils.lang.StringUtils;
    import com.mycim.framework.utils.lang.collections.MapUtils;
    import com.mycim.server.base.manager.NamedObjectManager;
    import com.mycim.server.ctx.exec.manager.ResequenceContextValueManager;
    import com.mycim.server.ctx.manager.ContextManager;
    import com.mycim.server.ctx.manager.ContextValueManager;
    import com.mycim.server.spec.manager.AttributeSetupManager;
    import com.mycim.valueobject.ObjectList;
    import com.mycim.valueobject.consts.ActionPointList;
    import com.mycim.valueobject.consts.ContextNames;
    import com.mycim.valueobject.prp.*;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;

    import java.lang.Override;
    import java.util.*;

    /**
     * @author Qiansheng.Wang
     * @since 2020-09-15
     */
    @Service
    @Transactional
    public class AttributeSetupManagerImpl implements AttributeSetupManager {

        @Autowired
        NamedObjectManager namedObjectManager;

        @Autowired
        ContextManager contextManager;

        @Autowired
        ContextValueManager contextValueManager;

        @Autowired
        ResequenceContextValueManager resequenceContextValueManager;

        @Override
        public void saveFlowSequenceToContextValue(Long facilityRrn, Ecn ecn, List<ProcessSpecItem> processSpecItems) {
            Map<String, Long> contextRrnMap = new HashMap<>();

            contextRrnMap.put(ContextNames.RESEQUENCE_CONTEXT, namedObjectManager
                    .getNamedObjectRrn(ContextNames.RESEQUENCE_CONTEXT, facilityRrn, ObjectList.CONTEXT_KEY));

            List<ContextValue> contextValues = new ArrayList<>();

            for (ProcessSpecItem processSpecItem : processSpecItems) {
                contextValues.add(buildProcessFlowSeq(contextRrnMap, processSpecItem));
            }

            ProcessSpecItem processSpecItem = processSpecItems.get(0);

            List<ContextValue> resequenceContextValues = resequenceContextValueManager
                    .getFlowSeqContextValueList(processSpecItem.getProcessRrn(), processSpecItem.getProcessVersion());

            List<ContextValue> deleteContextValues = new ArrayList<>();
            for (Iterator<ContextValue> iterator = contextValues.iterator(); iterator.hasNext(); ) {
                ContextValue contextValue = iterator.next();

                int index = resequenceContextValues.indexOf(contextValue);
                if (index >= 0) {
                    ContextValue oldContextValue = resequenceContextValues.get(index);

                    boolean needDelete = isNeedDelete(contextValue);
                    boolean isModified = isModified(contextValue, oldContextValue);

                    if (needDelete) {
                        // If the value is empty. The context value needs to be deleted.
                        deleteContextValues.add(contextValue);
                        iterator.remove();
                    } else if (!isModified) {
                        iterator.remove();
                    }
                }
            }

            saveContextValues(ecn, contextValues, deleteContextValues);
        }

        @Override
        public void saveProcessAttributeToContextValue(Long facilityRrn, Ecn ecn, List<ProcessSpecItem> processSpecItems) {
            Map<String, Long> contextRrnMap = contextManager.getContextRrns(facilityRrn);

            List<ContextValue> processContextValues = new ArrayList<>();

            for (ProcessSpecItem processSpecItem : processSpecItems) {
                processContextValues.add(buildProcessFlowSeq(contextRrnMap, processSpecItem));
                if (!ProductVariableEnum.isRecipeVariable(processSpecItem.getRecipeId())) {
                    processContextValues.add(buildProcessRecipe(contextRrnMap, processSpecItem));
                }
                if (!ProductVariableEnum.isEdcPlanVariable(processSpecItem.getParameterSetId())) {
                    processContextValues.add(buildProcessParameterSet(contextRrnMap, processSpecItem));
                }
                if (!ProductVariableEnum.isReticleGroupVariable(processSpecItem.getReticleFamilyId())) {
                    processContextValues.add(buildProcessReticle(contextRrnMap, processSpecItem));
                }
                processContextValues.add(buildProcessStage(contextRrnMap, processSpecItem));
                processContextValues.add(buildProcessLocation(contextRrnMap, processSpecItem));
                processContextValues.add(buildProcessPollutionLevel(contextRrnMap, processSpecItem));
                processContextValues.add(buildProcessOperationDesc(contextRrnMap, processSpecItem));
                processContextValues.add(buildBankFlag(contextRrnMap, processSpecItem));
            }

            List<ContextValue> deleteContextValues = new ArrayList<>();

            for (Iterator<ContextValue> iterator = processContextValues.iterator(); iterator.hasNext(); ) {
                ContextValue contextValue = iterator.next();

                boolean needDelete = isNeedDelete(contextValue);

                if (needDelete) {
                    // If the value is empty. The context value needs to be deleted.
                    deleteContextValues.add(contextValue);
                    iterator.remove();
                }
            }

            saveContextValues(ecn, processContextValues, deleteContextValues);
        }

        @Override
        public void saveProductAttributeToContextValue(Long facilityRrn, Ecn ecn,
                                                       List<ProductAttributeItem> productAttributeItems) {
            Map<String, Long> contextRrnMap = contextManager.getContextRrns(facilityRrn);

            List<ContextValue> productContextValues = new ArrayList<>();

            for (ProductAttributeItem productAttributeItem : productAttributeItems) {

                if (ProductVariableEnum.isRecipeVariable(productAttributeItem.getAttributeName())) {
                    productContextValues.add(buildProductRecipe(contextRrnMap, productAttributeItem));
                }
                if (ProductVariableEnum.isEdcPlanVariable(productAttributeItem.getAttributeName())) {
                    productContextValues.add(buildProductParameterSet(contextRrnMap, productAttributeItem));
                }
                if (ProductVariableEnum.isReticleGroupVariable(productAttributeItem.getAttributeName())) {
                    productContextValues.add(buildProductReticle(contextRrnMap, productAttributeItem));
                }
            }

            saveContextValues(ecn, productContextValues, new ArrayList<>());
        }

        private void saveContextValues(Ecn ecn, List<ContextValue> contextValues, List<ContextValue> deleteContextValues) {
            for (ContextValue newContextValue : contextValues) {
                newContextValue.setStatus(ecn.getEcnStatus());
                newContextValue.setEcnRrn(ecn.getInstanceRrn());
                newContextValue.setEffectiveDateFrom(ecn.getEffectiveDateFrom());
                newContextValue.setEffectiveDateTo(ecn.getEffectiveDateTo());
            }

            contextValueManager.saveContextValues(contextValues, ecn.getRequestBy());
            contextValueManager.deleteContextValues(deleteContextValues, ecn.getRequestBy());
        }

        /**
         * Check whether all the result values of the context value are empty.
         *
         * @param contextValue Inspection object
         * @return If all the result values are blank, return {@code true}.
         */
        private boolean isNeedDelete(ContextValue contextValue) {
            return StringUtils.isBlank(contextValue.getResultValue1()) &&
                    StringUtils.isBlank(contextValue.getResultValue2()) &&
                    StringUtils.isBlank(contextValue.getResultValue3()) &&
                    StringUtils.isBlank(contextValue.getResultValue4()) &&
                    StringUtils.isBlank(contextValue.getResultValue5()) &&
                    StringUtils.isBlank(contextValue.getResultValue6()) &&
                    StringUtils.isBlank(contextValue.getResultValue7()) &&
                    StringUtils.isBlank(contextValue.getResultValue8()) &&
                    StringUtils.isBlank(contextValue.getResultValue9()) &&
                    StringUtils.isBlank(contextValue.getResultValue10()) &&
                    StringUtils.isBlank(contextValue.getResultValue11()) &&
                    StringUtils.isBlank(contextValue.getResultValue12()) &&
                    StringUtils.isBlank(contextValue.getResultValue13()) &&
                    StringUtils.isBlank(contextValue.getResultValue14()) &&
                    StringUtils.isBlank(contextValue.getResultValue15());
        }

        /**
         * Check whether the result value of the context value has been modified.
         *
         * @param newContextValue Modified object
         * @param oldContextValue Source object
         * @return If one of the result values is modified, return {@code true}.
         */
        private boolean isModified(ContextValue newContextValue, ContextValue oldContextValue) {
            return isModified(newContextValue.getResultValue1(), oldContextValue.getResultValue1()) ||
                    isModified(newContextValue.getResultValue2(), oldContextValue.getResultValue2()) ||
                    isModified(newContextValue.getResultValue3(), oldContextValue.getResultValue3()) ||
                    isModified(newContextValue.getResultValue4(), oldContextValue.getResultValue4()) ||
                    isModified(newContextValue.getResultValue5(), oldContextValue.getResultValue5()) ||
                    isModified(newContextValue.getResultValue6(), oldContextValue.getResultValue6()) ||
                    isModified(newContextValue.getResultValue7(), oldContextValue.getResultValue7()) ||
                    isModified(newContextValue.getResultValue8(), oldContextValue.getResultValue8()) ||
                    isModified(newContextValue.getResultValue9(), oldContextValue.getResultValue9()) ||
                    isModified(newContextValue.getResultValue10(), oldContextValue.getResultValue10()) ||
                    isModified(newContextValue.getResultValue11(), oldContextValue.getResultValue11()) ||
                    isModified(newContextValue.getResultValue12(), oldContextValue.getResultValue12()) ||
                    isModified(newContextValue.getResultValue13(), oldContextValue.getResultValue13()) ||
                    isModified(newContextValue.getResultValue14(), oldContextValue.getResultValue14()) ||
                    isModified(newContextValue.getResultValue15(), oldContextValue.getResultValue15());
        }

        private boolean isModified(String newResultValue, String oldResultValue) {
            return !StringUtils.equals(StringUtils.trimToEmpty(newResultValue), StringUtils.trimToEmpty(oldResultValue));
        }

        private ReticleFamilyContextValue buildProductReticle(Map<String, Long> contexts,
                                                              ProductAttributeItem productAttributeItem) {
            ReticleFamilyContextValue contextValue = new ReticleFamilyContextValue();

            contextValue.setContextRrn(MapUtils.getLongValue(contexts, contextValue.getContextId()));

            contextValue.setProductRrn(productAttributeItem.getProductRrn());
            contextValue.setProductVersion(productAttributeItem.getProductVersion());
            contextValue.setProcessRrn(productAttributeItem.getProcessRrn());
            contextValue.setProcessVersion(productAttributeItem.getProcessVersion());
            contextValue.setRouteRrn(productAttributeItem.getRouteRrn());
            contextValue.setOperationRrn(productAttributeItem.getOperationRrn());

            contextValue.setReticleFamilyRrn(productAttributeItem.getAttributeValueRrn());
            contextValue.setAttributeNameRrn(productAttributeItem.getAttributeNameRrn());

            return contextValue;
        }

        private EdcLotContextValue buildProductParameterSet(Map<String, Long> contexts,
                                                            ProductAttributeItem productAttributeItem) {
            EdcLotContextValue contextValue = new EdcLotContextValue();

            contextValue.setContextRrn(MapUtils.getLongValue(contexts, contextValue.getContextId()));

            contextValue.setProductRrn(productAttributeItem.getProductRrn());
            contextValue.setProductVersion(productAttributeItem.getProductVersion());
            contextValue.setProcessRrn(productAttributeItem.getProcessRrn());
            contextValue.setProcessVersion(productAttributeItem.getProcessVersion());
            contextValue.setRouteRrn(productAttributeItem.getRouteRrn());
            contextValue.setOperationRrn(productAttributeItem.getOperationRrn());

            contextValue.setActionPoint(ActionPointList.MOVEOUT_KEY);

            contextValue.setParameterSetRrn(productAttributeItem.getAttributeValueRrn());
            contextValue.setAttributeNameRrn(productAttributeItem.getAttributeNameRrn());

            return contextValue;
        }

        private RecipeContextValue buildProductRecipe(Map<String, Long> contexts,
                                                      ProductAttributeItem productAttributeItem) {
            RecipeContextValue contextValue = new RecipeContextValue();

            contextValue.setContextRrn(MapUtils.getLongValue(contexts, contextValue.getContextId()));

            contextValue.setProductRrn(productAttributeItem.getProductRrn());
            contextValue.setProductVersion(productAttributeItem.getProductVersion());
            contextValue.setProcessRrn(productAttributeItem.getProcessRrn());
            contextValue.setProcessVersion(productAttributeItem.getProcessVersion());
            contextValue.setRouteRrn(productAttributeItem.getRouteRrn());
            contextValue.setOperationRrn(productAttributeItem.getOperationRrn());

            contextValue.setRecipeRrn(productAttributeItem.getAttributeValueRrn());
            contextValue.setAttributeNameRrn(productAttributeItem.getAttributeNameRrn());

            return contextValue;
        }

        private ProcessOperationDescContextValue buildProcessOperationDesc(Map<String, Long> contexts,
                                                                           ProcessSpecItem processSpecItem) {
            ProcessOperationDescContextValue contextValue = new ProcessOperationDescContextValue();

            contextValue.setContextRrn(MapUtils.getLongValue(contexts, contextValue.getContextId()));

            contextValue.setProcessRrn(processSpecItem.getProcessRrn());
            contextValue.setProcessVersion(processSpecItem.getProcessVersion());
            contextValue.setRouteRrn(processSpecItem.getRouteRrn());
            contextValue.setOperationRrn(processSpecItem.getOperationRrn());

            if (StringUtils.isNotBlank(processSpecItem.getOperationDesc())) {
                contextValue.setOperationDesc(processSpecItem.getOperationDesc());
            }

            return contextValue;
        }

        private BankFlagContextValue buildBankFlag(Map<String, Long> contexts, ProcessSpecItem processSpecItem) {
            BankFlagContextValue contextValue = new BankFlagContextValue();

            contextValue.setContextRrn(MapUtils.getLongValue(contexts, contextValue.getContextId()));

            contextValue.setProcessRrn(processSpecItem.getProcessRrn());
            contextValue.setProcessVersion(processSpecItem.getProcessVersion());
            contextValue.setRouteRrn(processSpecItem.getRouteRrn());
            contextValue.setOperationRrn(processSpecItem.getOperationRrn());

            if (StringUtils.isNotBlank(processSpecItem.getBankFlag())) {
                contextValue.setBankFlag(processSpecItem.getBankFlag());
            }

            return contextValue;
        }

        private OperationDESCContextValue buildProcessPollutionLevel(Map<String, Long> contexts,
                                                                     ProcessSpecItem processSpecItem) {
            OperationDESCContextValue contextValue = new OperationDESCContextValue();

            contextValue.setContextRrn(MapUtils.getLongValue(contexts, contextValue.getContextId()));

            contextValue.setProcessRrn(processSpecItem.getProcessRrn());
            contextValue.setProcessVersion(processSpecItem.getProcessVersion());
            contextValue.setRouteRrn(processSpecItem.getRouteRrn());
            contextValue.setOperationRrn(processSpecItem.getOperationRrn());

            if (StringUtils.isNotBlank(processSpecItem.getPollutionLevel())) {
                contextValue.setPollutionLevel(processSpecItem.getPollutionLevel());
            }
            if (StringUtils.isNotBlank(processSpecItem.getOperationType())) {
                contextValue.setOperationType(processSpecItem.getOperationType());
            }
            if (StringUtils.isNotBlank(processSpecItem.getWorkArea())) {
                contextValue.setWorkArea(processSpecItem.getWorkArea());
            }

            return contextValue;
        }

        private ProcessLocationContextValue buildProcessLocation(Map<String, Long> contexts,
                                                                 ProcessSpecItem processSpecItem) {
            ProcessLocationContextValue contextValue = new ProcessLocationContextValue();

            contextValue.setContextRrn(MapUtils.getLongValue(contexts, contextValue.getContextId()));

            contextValue.setProcessRrn(processSpecItem.getProcessRrn());
            contextValue.setProcessVersion(processSpecItem.getProcessVersion());
            contextValue.setRouteRrn(processSpecItem.getRouteRrn());
            contextValue.setOperationRrn(processSpecItem.getOperationRrn());

            if (StringUtils.isNotBlank(processSpecItem.getProcessLocation())) {
                contextValue.setProcessLocation(processSpecItem.getProcessLocation());
            }

            return contextValue;
        }

        private StageContextValue buildProcessStage(Map<String, Long> contexts, ProcessSpecItem processSpecItem) {
            StageContextValue contextValue = new StageContextValue();

            contextValue.setContextRrn(MapUtils.getLongValue(contexts, contextValue.getContextId()));

            contextValue.setProcessRrn(processSpecItem.getProcessRrn());
            contextValue.setProcessVersion(processSpecItem.getProcessVersion());
            contextValue.setRouteRrn(processSpecItem.getRouteRrn());
            contextValue.setOperationRrn(processSpecItem.getOperationRrn());

            if (StringUtils.isNotBlank(processSpecItem.getStageId())) {
                contextValue.setStageId(processSpecItem.getStageId());
            }

            return contextValue;
        }

        private ReticleFamilyContextValue buildProcessReticle(Map<String, Long> contexts, ProcessSpecItem processSpecItem) {
            ReticleFamilyContextValue contextValue = new ReticleFamilyContextValue();

            contextValue.setContextRrn(MapUtils.getLongValue(contexts, contextValue.getContextId()));

            contextValue.setProcessRrn(processSpecItem.getProcessRrn());
            contextValue.setProcessVersion(processSpecItem.getProcessVersion());
            contextValue.setRouteRrn(processSpecItem.getRouteRrn());
            contextValue.setOperationRrn(processSpecItem.getOperationRrn());

            if (processSpecItem.getReticleFamilyRrn() != null && processSpecItem.getReticleFamilyRrn() > 0) {
                contextValue.setReticleFamilyRrn(processSpecItem.getReticleFamilyRrn());
            }

            return contextValue;
        }

        private EdcLotContextValue buildProcessParameterSet(Map<String, Long> contexts, ProcessSpecItem processSpecItem) {
            EdcLotContextValue contextValue = new EdcLotContextValue();

            contextValue.setContextRrn(MapUtils.getLongValue(contexts, contextValue.getContextId()));

            contextValue.setProcessRrn(processSpecItem.getProcessRrn());
            contextValue.setProcessVersion(processSpecItem.getProcessVersion());
            contextValue.setRouteRrn(processSpecItem.getRouteRrn());
            contextValue.setOperationRrn(processSpecItem.getOperationRrn());
            contextValue.setActionPoint(ActionPointList.MOVEOUT_KEY);

            if (processSpecItem.getParameterSetRrn() != null && processSpecItem.getParameterSetRrn() > 0) {
                contextValue.setParameterSetRrn(processSpecItem.getParameterSetRrn());
            }

            return contextValue;
        }

        private RecipeContextValue buildProcessRecipe(Map<String, Long> contexts, ProcessSpecItem processSpecItem) {
            RecipeContextValue contextValue = new RecipeContextValue();

            contextValue.setContextRrn(MapUtils.getLongValue(contexts, contextValue.getContextId()));

            contextValue.setProcessRrn(processSpecItem.getProcessRrn());
            contextValue.setProcessVersion(processSpecItem.getProcessVersion());
            contextValue.setRouteRrn(processSpecItem.getRouteRrn());
            contextValue.setOperationRrn(processSpecItem.getOperationRrn());

            if (processSpecItem.getRecipeRrn() != null && processSpecItem.getRecipeRrn() > 0) {
                contextValue.setRecipeRrn(processSpecItem.getRecipeRrn());
            }

            return contextValue;
        }

        private ResequenceContextValue buildProcessFlowSeq(Map<String, Long> contexts, ProcessSpecItem processSpecItem) {
            ResequenceContextValue contextValue = new ResequenceContextValue();

            contextValue.setContextRrn(MapUtils.getLongValue(contexts, contextValue.getContextId()));

            contextValue.setProcessRrn(processSpecItem.getProcessRrn());
            contextValue.setProcessVersion(processSpecItem.getProcessVersion());
            contextValue.setRouteRrn(processSpecItem.getRouteRrn());
            contextValue.setOperationRrn(processSpecItem.getOperationRrn());

            if (StringUtils.isNotBlank(processSpecItem.getFlowSeq())) {
                contextValue.setResequence(StringUtils.trimToEmpty(processSpecItem.getFlowSeq()));
            }

            return contextValue;
        }

    }