# SpecManagerImpl.java

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

    import com.fa.sesa.threadlocal.LocalContext;
    import com.mycim.framework.jdbc.Page;
    import com.mycim.framework.utils.lang.BooleanUtils;
    import com.mycim.framework.utils.lang.ObjectUtils;
    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.base.manager.TransactionLogManager;
    import com.mycim.server.ctx.exec.manager.WflLinkContextValueManager;
    import com.mycim.server.ctx.manager.ContextValueManager;
    import com.mycim.server.prp.manager.ProcessManager;
    import com.mycim.server.prp.manager.ProductProcessManager;
    import com.mycim.server.prp.manager.ProductVersionManager;
    import com.mycim.server.prp.manager.WorkflowManager;
    import com.mycim.server.spec.manager.*;
    import com.mycim.utils.WflLinkContextSetupAttributeUtil;
    import com.mycim.valueobject.ObjectList;
    import com.mycim.valueobject.bas.TransactionLog;
    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.*;
    import java.util.function.Function;
    import java.util.stream.Collectors;

    /**
     * @author Qiansheng.Wang
     * @version 1.0
     * @since 2021-07-07
     **/
    @Service
    @Transactional
    public class SpecManagerImpl implements SpecManager {

        @Autowired
        TransactionLogManager transactionLogManager;

        @Autowired
        ProductSpecInfoManager productSpecInfoManager;

        @Autowired
        ProcessSpecInfoManager processSpecInfoManager;

        @Autowired
        ProcessSpecItemManager processSpecItemManager;

        @Autowired
        ProductAttributeInfoManager productAttributeInfoManager;

        @Autowired
        ProductAttributeItemManager productAttributeItemManager;

        @Autowired
        ProductVersionManager productVersionManager;

        @Autowired
        ProductProcessManager productProcessManager;

        @Autowired
        ActivationAttributeManager activationAttributeManager;

        @Autowired
        ProcessManager processManager;

        @Autowired
        NamedObjectManager namedObjectManager;

        @Autowired
        ContextValueManager contextValueManager;

        @Autowired
        WorkflowManager workflowManager;

        @Autowired
        WflLinkContextValueManager wflLinkContextValueManager;

        @Override
        public List<Integer> getProcessVersionsInSpec(Long processRrn) {
            List<Integer> result = new ArrayList<>();
            for (ProcessSpecInfo processSpecInfo : processSpecInfoManager.getProcessSpecItemInfos(processRrn)) {
                result.add(processSpecInfo.getProcessVersion());
            }
            return result;
        }

        @Override
        public Integer getLatestAvailableVersion(Long processRrn) {
            List<Integer> activeVersion = processSpecInfoManager.getAllActivatedProcessVersions(processRrn);
            for (Integer verion : activeVersion) {
                if (CollectionUtils.isEmpty(processSpecItemManager.getProcessSpecItemsWithVariables(processRrn, verion))) {
                    return verion;
                }
            }
            return 0;
        }

        @Override
        public ProductSpecInfo getLatestActivatedProductSpecInfo(Long productRrn, Long processRrn) {
            return productSpecInfoManager.getLatestActivatedProductSpecInfo(productRrn, processRrn);
        }

        @Override
        public int getLatestActivatedProcessVersion(Long productRrn, Long processRrn) {
            // 获取流程或流程产品最新可用的流程版本
            ProductSpecInfo productSpecInfo = getLatestActivatedProductSpecInfo(productRrn, processRrn);

            int processVer = 0;
            if (productSpecInfo != null && productSpecInfo.getProcessVersion() > 0) {
                // 如果有数据，表示曾经激活过对应版本的属性信息，返回对应的流程版本
                processVer = productSpecInfo.getProcessVersion();
            } else {
                // 如果没有数据，则获取流程最新的可用版本
                processVer = getLatestAvailableVersion(processRrn);
            }
            return processVer;
        }

        @Override
        public void addProductAttributeWhenAddProductProcess(TransactionLog transactionLog,
                                                             ProductProcessDto productProcess) {
            List<ProcessSpecInfo> specInfos = getProcessSpecInfosThatNeedsToSaveProductAttributes(
                    productProcess.getProcessRrn());
            if (CollectionUtils.isEmpty(specInfos)) {
                return;
            }

            List<ProductVersion> productVersions = getProductVersionsThatNeedsToSaveProductAttributes(
                    productProcess.getProductRrn());
            if (CollectionUtils.isEmpty(productVersions)) {
                return;
            }

            for (ProcessSpecInfo processSpecInfo : specInfos) {
                List<ProcessSpecItem> willSaveProcessSpecItems = processSpecItemManager
                        .getProcessSpecItemsWithVariables(processSpecInfo.getProcessRrn(),
                                                          processSpecInfo.getProcessVersion());

                if (CollectionUtils.isEmpty(willSaveProcessSpecItems)) {
                    if (BooleanUtils.toBoolean(processSpecInfo.getActiveFlag())) {
                        activateProduct(transactionLog, productVersions, processSpecInfo);
                    }
                    continue;
                }

                productAttributeItemManager
                        .saveProductAttribute(transactionLog, processSpecInfo, willSaveProcessSpecItems, productVersions);
            }
        }

        @Override
        public void deleteProductAttributeWhenDeleteProductProcess(TransactionLog transactionLog,
                                                                   ProductProcessDto productProcess) {
            deleteProductAttributeWhenProductDoDelete(transactionLog, productAttributeInfoManager
                    .getProductAttributeInfos(productProcess.getProductRrn(), productProcess.getProcessRrn()));
        }

        @Override
        public void deleteProductAttributeWhenDeleteProduct(TransactionLog transactionLog, Long productRrn) {
            deleteProductAttributeWhenProductDoDelete(transactionLog, productAttributeInfoManager
                    .getProductAttributeInfosByProduct(productRrn));
        }

        private void deleteProductAttributeWhenProductDoDelete(TransactionLog transactionLog,
                                                               List<ProductAttributeInfo> productAttributeInfosByProduct) {
            List<ProductAttributeInfo> willDeleteAttributeInfos = new ArrayList<>();
            List<ProductAttributeItem> willDeleteAttributeItems = new ArrayList<>();

            for (ProductAttributeInfo attributeInfo : productAttributeInfosByProduct) {
                //  if (!BooleanUtils.toBoolean(attributeInfo.getActiveFlag())) {
                // 在product 解绑和删除时，需要删除对应product的所有数据 包括active的数据
                willDeleteAttributeInfos.add(attributeInfo);
                willDeleteAttributeItems.addAll(productAttributeItemManager
                                                        .getProductAttributeItems(attributeInfo.getProcessRrn(),
                                                                                  attributeInfo.getProcessVersion(),
                                                                                  attributeInfo.getProductRrn(),
                                                                                  attributeInfo.getProductVersion()));
                //  }
            }

            productAttributeInfoManager.deleteProductAttributeInfos(willDeleteAttributeInfos);
            productAttributeItemManager.deleteProductAttributeItems(transactionLog, willDeleteAttributeItems);
        }

        private void activateProduct(TransactionLog transactionLog, List<ProductVersion> productVersions,
                                     ProcessSpecInfo processSpecInfo) {
            productSpecInfoManager.activateProductSpecInfos(transactionLog, processSpecInfo, productVersions);

            activateProduct(transactionLog, processSpecInfo.getProcessRrn(), processSpecInfo.getProcessVersion());
        }

        @Override
        public void activateProduct(TransactionLog transactionLog, Long processRrn, Integer processVersion) {
            Integer highestAvailableProcessVersion = processSpecInfoManager.getHighestActivatedProcessVersion(processRrn);
            if (highestAvailableProcessVersion == null || highestAvailableProcessVersion <= processVersion) {
                // 更新产品可用的流程版本
                productProcessManager.updateAvailableProcessVersionOfAllProduct(transactionLog, processRrn, processVersion);
            }

            activationAttributeManager.saveActivationAttributes(processRrn, processVersion);
        }

        @Override
        public Boolean checkMultipath(String processId, Long processRrn, Integer processVersion, List<String> productIds) {
            Boolean multipathSetFlag = Boolean.FALSE;
            List<Item> usedByProducts = new ArrayList<>();
            if (CollectionUtils.isNotEmpty(productIds)) {
                //若productIds不为空则表示536active，只check当前的product
                for (String productId : productIds) {
                    Item item = new Item();
                    item.setInstanceId(productId);
                    item.setInstanceRrn(namedObjectManager.getNamedObjectRrn(productId, LocalContext.getFacilityRrn(),
                                                                             ObjectList.PRODUCT_KEY));
                    usedByProducts.add(item);
                }
            } else {
                // 若productIds为空 则表示535active，查询当前process上挂的所有product
                usedByProducts = processManager.getUsedByProducts(processRrn);
            }
            if (CollectionUtils.isEmpty(usedByProducts)) {
                return Boolean.FALSE;
            }

            List<Map<String, Object>> multipathOperation = getMultipath(processRrn, processVersion,
                                                                        WflLinkContextSetupAttributeUtil.OPERATION_FLAG);

            List<Map<String, Object>> multipathRoute = getMultipath(processRrn, processVersion,
                                                                    WflLinkContextSetupAttributeUtil.ROUTE_FLAG);

            for (Map<String, Object> map : multipathOperation) {
                Long operationRrn = MapUtils.getLong(map, "operationRrn");
                Long routeRrn = MapUtils.getLong(map, "routeRrn");
                if (operationRrn.longValue() < 0 || routeRrn.longValue() < 0) {
                    continue;
                }

                for (Item product : usedByProducts) {
                    multipathSetFlag = Boolean.TRUE;
                    // 查询对应product上的Multipath设置
                    WflLinkContextValue wflLinkContextValue = new WflLinkContextValue();
                    wflLinkContextValue.setProductRrn(product.getInstanceRrn());
                    wflLinkContextValue.setProcessRrn(processRrn);
                    wflLinkContextValue.setProcessVersion(processVersion);
                    wflLinkContextValue.setStatus("ACTIVE");
                    List<WflLinkContextValue> contextValues = wflLinkContextValueManager
                            .getContextValues(wflLinkContextValue);

                    for (WflLinkContextValue ct : contextValues) {
                        if (operationRrn.equals(ct.getOperationRrn()) && routeRrn.equals(ct.getRouteRrn()) &&
                                WflLinkContextSetupAttributeUtil.isByOperationMultipath(ct)) {
                            multipathSetFlag = Boolean.FALSE;
                            break;
                        }
                    }
                    if (multipathSetFlag) {
                        return multipathSetFlag;
                    }
                }

            }
            for (Map<String, Object> map : multipathRoute) {
                String routeId = MapUtils.getString(map, "routeId");
                Long routeRrn = namedObjectManager
                        .getNamedObjectRrn(routeId, LocalContext.getFacilityRrn(), ObjectList.WFL_KEY);

                if (routeRrn.longValue() > 0) {
                    for (Item product : usedByProducts) {
                        // 查询对应product上的Multipath设置
                        multipathSetFlag = Boolean.TRUE;
                        WflLinkContextValue wflLinkContextValue = new WflLinkContextValue();
                        wflLinkContextValue.setProductRrn(product.getInstanceRrn());
                        wflLinkContextValue.setProcessRrn(processRrn);
                        wflLinkContextValue.setProcessVersion(processVersion);
                        wflLinkContextValue.setStatus("ACTIVE");
                        List<WflLinkContextValue> contextValues = wflLinkContextValueManager
                                .getContextValues(wflLinkContextValue);

                        for (WflLinkContextValue ct : contextValues) {
                            if (WflLinkContextSetupAttributeUtil.isByRouteMultipath(ct) &&
                                    routeRrn.equals(ct.getRouteRrn())) {
                                multipathSetFlag = Boolean.FALSE;
                                break;
                            }
                        }
                        if (multipathSetFlag) {
                            return multipathSetFlag;
                        }
                    }

                }
            }

            return Boolean.FALSE;
        }

        private List<ProductVersion> getProductVersionsThatNeedsToSaveProductAttributes(Long productVersion) {
            List<ProductVersion> productVersions = new ArrayList<>();

            List<ProductVersion> allProductVersion = productVersionManager.getAllVersions(productVersion);

            allProductVersion.sort((o1, o2) -> o2.getInstanceVersion() - o1.getInstanceVersion());

            productVersions.add(allProductVersion.iterator().next());

            return productVersions;
        }

        private List<ProcessSpecInfo> getProcessSpecInfosThatNeedsToSaveProductAttributes(Long processRrn) {
            List<ProcessSpecInfo> processSpecInfos = processSpecInfoManager.getProcessSpecItemInfos(processRrn);

            processSpecInfos.sort((o1, o2) -> o2.getProcessVersion() - o1.getProcessVersion());

            List<ProcessSpecInfo> specInfos = new ArrayList<>();
            for (ProcessSpecInfo processSpecInfo : processSpecInfos) {
                specInfos.add(processSpecInfo);
                if (BooleanUtils.toBoolean(processSpecInfo.getActiveFlag())) {
                    break;
                }
            }
            return specInfos;
        }

        private List<Map<String, Object>> getMultipath(Long processRrn, Integer processVersion, String type) {
            List<Map<String, Object>> workFlowByProcess = new ArrayList<>();
            Boolean ruleFlag = Boolean.FALSE;
            if (StringUtils.equalsIgnoreCase(WflLinkContextSetupAttributeUtil.OPERATION_FLAG, type)) {
                workFlowByProcess = workflowManager.getWflOperationByProcess(processRrn, processVersion);
                ruleFlag = Boolean.TRUE;
            } else if (StringUtils.equalsIgnoreCase(WflLinkContextSetupAttributeUtil.ROUTE_FLAG, type)) {
                workFlowByProcess = workflowManager.getWflRouteByProcess(processRrn, processVersion);
                ruleFlag = Boolean.FALSE;
            } else {
                return null;
            }
            List<Map<String, Object>> buildWorkFlow = new ArrayList<>();
            Map<String, Integer> map = new HashMap<>();
            for (Map<String, Object> flowByProcess : workFlowByProcess) {
                String rule = StringUtils.EMPTY;
                if (ruleFlag) {
                    rule = MapUtils.getString(flowByProcess, "routeRrn") + StringUtils.COMMA_SIGN +
                            MapUtils.getString(flowByProcess, "routeVersion") + StringUtils.COMMA_SIGN +
                            MapUtils.getString(flowByProcess, "operationId") + StringUtils.COMMA_SIGN;
                } else {
                    rule = MapUtils.getString(flowByProcess, "processRrn") + StringUtils.COMMA_SIGN +
                            MapUtils.getString(flowByProcess, "processVersion") + StringUtils.COMMA_SIGN +
                            MapUtils.getString(flowByProcess, "routeId") + StringUtils.COMMA_SIGN;
                }

                //1 检测key是否重复
                if (map.containsKey(rule)) {
                    Integer num = map.get(rule);
                    if (NumberUtils.INTEGER_ONE.equals(num)) {
                        String operationId = MapUtils.getString(flowByProcess, "operationId");
                        Long instanceRrn = namedObjectManager
                                .getNamedObjectRrn(operationId, LocalContext.getFacilityRrn(), ObjectList.OPERATION_KEY);
                        flowByProcess.put("operationRrn", instanceRrn);
                        buildWorkFlow.add(flowByProcess);//获取重复元素
                    }
                    map.put(rule, num + 1);
                } else {
                    map.put(rule, 1);
                }
            }

            return buildWorkFlow;

        }

        @Override
        public Boolean checkMultiPathHasManualForContextValue(WflLinkContextValue contextValue) {

            Long routeRrn = contextValue.getRouteRrn();
            Long operationRrn = contextValue.getOperationRrn();
            Long processRrn = contextValue.getProcessRrn();
            Integer processVersion = contextValue.getProcessVersion();
            if (WflLinkContextSetupAttributeUtil.isByManualOperationMultipath(contextValue)) {
                Integer routeVersion = workflowManager.getWFLVersionByProcess(processRrn, processVersion, routeRrn);
                Collection operationPath = workflowManager
                        .getWflPath(routeRrn, routeVersion, namedObjectManager.getInstanceId(operationRrn));
                if (operationPath.size() < 2) {
                    return Boolean.FALSE;
                }
            } else if (WflLinkContextSetupAttributeUtil.isByManualRouteMultipath(contextValue)) {
                Collection routePath = workflowManager
                        .getWflPath(processRrn, processVersion, namedObjectManager.getInstanceId(routeRrn));
                if (routePath.size() < 2) {
                    return Boolean.FALSE;
                }
            }

            return Boolean.TRUE;

        }

        @Override
        public List<Map<String,Object>> getMultipathAndDefaultSteps(Long processRrn, Integer processVersion,String type) {
            //根据processRrn processVersion取到对应的所有operation节点信息
            List<Map<String, Object>> allWflList = workflowManager.getallWflByProcess(processRrn,processVersion);
            //operation multipath
            if (StringUtils.equalsIgnoreCase(WflLinkContextSetupAttributeUtil.OPERATION_FLAG, type)) {
                Set<Long> wflStepRrns = new HashSet<>();
                List<Map<String,Object>> wflList = new ArrayList<>();
                for(Map<String, Object> operation : allWflList){
                    if(StringUtils.isNotBlank(MapUtils.getString(operation,"operationLinkId"))){
                        wflStepRrns.add(MapUtils.getLong(operation, "operationStepRrn"));
                    }
                }
                //若operation存在multipath的节点(可能存在多个)
                if(CollectionUtils.isNotEmpty(wflStepRrns)){
                    for(Long wflStepRrn : wflStepRrns){
                        List<Long> multiParentAndChildrenNodesList = new ArrayList<>();
                        List<Long> multiParentAndChildrenNodesListNoEnd = new ArrayList<>();
                        //拿到multipath节点的默认子节点和multipath子节点(可能存在多个)
                        Set<Long> multiStepRrns = new LinkedHashSet<>();
                        for(Map<String, Object> operation : allWflList){
                            if(wflStepRrn.equals(MapUtils.getLong(operation, "operationStepRrn"))){
                                multiStepRrns.add(MapUtils.getLong(operation, "wflNextStepRrn"));
                            }
                        }

                        if(CollectionUtils.isNotEmpty(multiStepRrns)){
                            //递归查询multipath节点作为父节点对应路径下的所有节点
                            for(Long wflNode : multiStepRrns){
                                List<Map<String, Object>> childrenNodes = getChildrenNodes(allWflList,wflNode,"wflNextStepRrn","operationStepRrn",new ArrayList<>());
                                for(Map<String, Object> childNode : childrenNodes){
                                    multiParentAndChildrenNodesList.add(MapUtils.getLong(childNode, "operationStepRrn"));
                                }
                            }
                            if(CollectionUtils.isNotEmpty(multiParentAndChildrenNodesList)) {
                                //拿到对应的multipath和default路径节点(即个数不等于分支长度的节点)
                                multiParentAndChildrenNodesListNoEnd = multiParentAndChildrenNodesList.stream().collect(
                                                           Collectors.toMap(Function.identity(), s -> 1, Integer::sum)).entrySet().stream()
                                                           .filter(entry -> !entry.getValue().equals(multiStepRrns.size()))
                                                           .map(Map.Entry::getKey).collect(Collectors.toList());
                            }
                        }

                        //取multipath和default路径节点的operationRrn
                        if(CollectionUtils.isNotEmpty(multiParentAndChildrenNodesListNoEnd)){
                            for(Map<String,Object> wflInfo : allWflList){
                                for(Long operationStepRrn : multiParentAndChildrenNodesListNoEnd){
                                    if(MapUtils.getLong(wflInfo,"operationStepRrn").equals(operationStepRrn)){
                                        wflList.add(wflInfo);
                                    }
                                }
                            }
                        }
                    }
                }
                return wflList;
            }

            //route multipath
            else if (StringUtils.equalsIgnoreCase(WflLinkContextSetupAttributeUtil.ROUTE_FLAG, type)) {
                List<Map<String,Object>> routeWflList = new ArrayList<>();
                List<Long> routeStepRrnList = new ArrayList<>();
                //获取到对应的所有route节点信息
                for(Map<String, Object> wflInfo : allWflList){
                    if(!routeStepRrnList.contains(MapUtils.getLong(wflInfo,"routeStepRrn"))){
                        routeStepRrnList.add(MapUtils.getLong(wflInfo,"routeStepRrn"));
                        routeWflList.add(wflInfo);
                    }
                }
                List<Map<String,Object>> wflList = new ArrayList<>();
                Set<Long> wflStepRrns = new HashSet<>();
                for(Map<String, Object> route : routeWflList){
                    if(StringUtils.isNotBlank(MapUtils.getString(route,"routeLinkId"))){
                        wflStepRrns.add(MapUtils.getLong(route, "routeStepRrn"));
                    }
                }
                //若route存在multipath的节点(可能存在多个)
                if(CollectionUtils.isNotEmpty(wflStepRrns)){
                    for(Long wflStepRrn : wflStepRrns){
                        List<Long> multiParentAndChildrenNodesList = new ArrayList<>();
                        List<Long> multiParentAndChildrenNodesListNoEnd = new ArrayList<>();
                        //拿到multipath节点的默认子节点和multipath子节点(可能存在多个)
                        Set<Long> multiStepRrns = new LinkedHashSet<>();
                        for(Map<String, Object> operation : allWflList){
                            if(wflStepRrn.equals(MapUtils.getLong(operation, "routeStepRrn"))){
                                multiStepRrns.add(MapUtils.getLong(operation, "routeWflNextStepRrn"));
                            }
                        }

                        if(CollectionUtils.isNotEmpty(multiStepRrns)){
                            //递归查询multipath节点作为父节点对应路径下的所有节点
                            for(Long wflNode : multiStepRrns){
                                List<Map<String, Object>> childrenNodes = getChildrenNodes(routeWflList,wflNode,"routeWflNextStepRrn","routeStepRrn",new ArrayList<>());
                                for(Map<String, Object> childNode : childrenNodes){
                                    multiParentAndChildrenNodesList.add(MapUtils.getLong(childNode, "routeStepRrn"));
                                }
                            }

                            if(CollectionUtils.isNotEmpty(multiParentAndChildrenNodesList)) {
                                //拿到对应的end节点(个数和multipath节点个数相同的第一个节点即为end节点)
                                multiParentAndChildrenNodesListNoEnd = multiParentAndChildrenNodesList.stream().collect(
                                                                                                         Collectors.toMap(Function.identity(), s -> 1, Integer::sum)).entrySet().stream()
                                                                                                 .filter(entry -> !entry.getValue().equals(multiStepRrns.size()))
                                                                                                 .map(Map.Entry::getKey).collect(Collectors.toList());
                            }
                        }

                        //取multipath和default路径节点的operationRrn
                        if(CollectionUtils.isNotEmpty(multiParentAndChildrenNodesListNoEnd)){
                            for(Map<String,Object> wflInfo : allWflList){
                                for(Long routeStepRrn : multiParentAndChildrenNodesListNoEnd){
                                    if(MapUtils.getLong(wflInfo,"routeStepRrn").equals(routeStepRrn)){
                                        wflList.add(wflInfo);
                                    }
                                }
                            }
                        }
                    }
                }
                return wflList;
            } else {
                return null;
            }
        }

        //递归查找父节点的所有子节点
        public List<Map<String,Object>> getChildrenNodes(List<Map<String,Object>> nodesList, Long nodeRrn, String wflNextStepRrnString,String stepRrnString,List<Map<String,Object>> childNodes) {
            for (Map<String,Object> node : nodesList) {
                //遍历出wflNextStepRrn等于operationStepRrn，add进子节点集合
                if (nodeRrn.equals(MapUtils.getLong(node,stepRrnString))) {
                    //递归遍历下一级
                    childNodes.add(node);
                    getChildrenNodes(nodesList,MapUtils.getLong(node,wflNextStepRrnString),wflNextStepRrnString,stepRrnString,childNodes);
                }
            }
            return childNodes;
        }
    }