content: package com.aizuda.snailjob.server.job.task.support.cache;
  
  import cn.hutool.core.collection.CollUtil;
  import com.aizuda.snailjob.server.common.util.GraphUtils;
  import com.google.common.cache.Cache;
  import com.google.common.cache.CacheBuilder;
  import com.google.common.collect.Lists;
  import com.google.common.collect.Sets;
  import com.google.common.graph.MutableGraph;
  
  import java.util.HashSet;
  import java.util.List;
  import java.util.Optional;
  import java.util.Set;
  import java.util.concurrent.TimeUnit;
  
  /**
   * @author xiaowoniu
   * @date 2023-12-30 13:18:07
   * @since 2.6.0
   */
  public class MutableGraphCache {
  
      private static final Cache<Long/*工作流批次*/, MutableGraph<Long>> cache;
  
      static {
          cache = CacheBuilder.newBuilder()
                  .concurrencyLevel(8) // 并发级别
                  .expireAfterWrite(5, TimeUnit.MINUTES) // 写入后的过期时间
                  .build();
      }
  
      /**
       * 获取指定workflowBatchId的可变图对象，若图对象不存在则使用给定的jsonGraph反序列化生成新的图对象并返回
       *
       * @param workflowBatchId 工作流批次ID
       * @param jsonGraph       JSON格式的图对象字符串
       * @return {@link MutableGraph} 图对象
       */
      public static MutableGraph<Long> getOrDefault(Long workflowBatchId, String jsonGraph) {
          return Optional.ofNullable(cache.getIfPresent(workflowBatchId)).orElse(GraphUtils.deserializeJsonToGraph(jsonGraph));
      }
  
      /**
       * 根据给定的workflowBatchId获取图对象。
       *
       * @param workflowBatchId 工作流批次ID
       * @return {@link MutableGraph} 返回对应的图对象，如果不存在则返回空图
       */
      public static MutableGraph<Long> get(Long workflowBatchId) {
          return getOrDefault(workflowBatchId, "");
      }
  
      /**
       * 获取所有的叶子节点
       *
       * @param workflowBatchId 工作流批次ID
       * @param jsonGraph       JSON格式的图对象字符串
       * @return 叶子节点
       */
      public static List<Long> getLeaves(Long workflowBatchId, String jsonGraph) {
  
          MutableGraph<Long> graph = getOrDefault(workflowBatchId, jsonGraph);
          List<Long> leaves = Lists.newArrayList();
          for (Long node : graph.nodes()) {
              if (CollUtil.isEmpty(graph.successors(node))) {
                  leaves.add(node);
              }
          }
  
          return leaves;
      }
  
      public static Set<Long> getAllDescendants(MutableGraph<Long> graph, Long parentId) {
          Set<Long> descendants = new HashSet<>();
          getAllDescendantsHelper(graph, parentId, descendants);
          return descendants;
      }
  
      public static Set<Long> getBrotherNode(MutableGraph<Long> graph, Long nodeId) {
          Set<Long> predecessors = graph.predecessors(nodeId);
          if (CollUtil.isEmpty(predecessors)) {
              return Sets.newHashSet();
          }
          return graph.successors(predecessors.stream().findFirst().get());
      }
  
      private static void getAllDescendantsHelper(MutableGraph<Long> graph, Long parentId, Set<Long> descendants) {
          Set<Long> successors = graph.successors(parentId);
          descendants.addAll(successors);
  
          for (Long successor : successors) {
              getAllDescendantsHelper(graph, successor, descendants);
          }
      }
  
  }
  