/*
 * Copyright 2000-2014 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.intellij.vcs.log.graph.impl.facade;

import com.intellij.util.Consumer;
import com.intellij.vcs.log.graph.api.LiteLinearGraph;
import com.intellij.vcs.log.graph.impl.permanent.PermanentLinearGraphImpl;
import com.intellij.vcs.log.graph.utils.DfsUtil;
import com.intellij.vcs.log.graph.utils.Flags;
import com.intellij.vcs.log.graph.utils.LinearGraphUtils;
import com.intellij.vcs.log.graph.utils.UnsignedBitSet;
import com.intellij.vcs.log.graph.utils.impl.BitSetFlags;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

public class ReachableNodes {
  @NotNull private final LiteLinearGraph myGraph;
  @NotNull private final DfsUtil myDfsUtil = new DfsUtil();
  @NotNull private final Flags myTempFlags;

  public ReachableNodes(@NotNull LiteLinearGraph graph) {
    myGraph = graph;
    myTempFlags = new BitSetFlags(graph.nodesCount());
  }

  @NotNull
  public static UnsignedBitSet getReachableNodes(@NotNull PermanentLinearGraphImpl permanentGraph, @Nullable Set<Integer> headNodeIndexes) {
    if (headNodeIndexes == null) {
      UnsignedBitSet nodesVisibility = new UnsignedBitSet();
      nodesVisibility.set(0, permanentGraph.nodesCount() - 1, true);
      return nodesVisibility;
    }

    assert !headNodeIndexes.isEmpty();

    final UnsignedBitSet result = new UnsignedBitSet();
    ReachableNodes getter = new ReachableNodes(LinearGraphUtils.asLiteLinearGraph(permanentGraph));
    getter.walk(headNodeIndexes, new Consumer<Integer>() {
      @Override
      public void consume(Integer node) {
        result.set(node, true);
      }
    });

    return result;
  }

  public Set<Integer> getContainingBranches(int nodeIndex, @NotNull final Collection<Integer> branchNodeIndexes) {
    final Set<Integer> result = new HashSet<Integer>();

    walk(Collections.singletonList(nodeIndex), false, new Consumer<Integer>() {
      @Override
      public void consume(Integer integer) {
        if (branchNodeIndexes.contains(integer)) result.add(integer);
      }
    });

    return result;
  }

  public void walk(@NotNull Collection<Integer> headIds, @NotNull final Consumer<Integer> consumer) {
    walk(headIds, true, consumer);
  }

  public void walk(@NotNull Collection<Integer> startNodes, final boolean goDown, @NotNull final Consumer<Integer> consumer) {
    synchronized (myTempFlags) {

      myTempFlags.setAll(false);
      for (int start : startNodes) {
        if (myTempFlags.get(start)) continue;
        myTempFlags.set(start, true);
        consumer.consume(start);

        myDfsUtil.nodeDfsIterator(start, new DfsUtil.NextNode() {
          @Override
          public int fun(int currentNode) {
            for (int downNode : myGraph.getNodes(currentNode, goDown ? LiteLinearGraph.NodeFilter.DOWN : LiteLinearGraph.NodeFilter.UP)) {
              if (!myTempFlags.get(downNode)) {
                myTempFlags.set(downNode, true);
                consumer.consume(downNode);
                return downNode;
              }
            }

            return NODE_NOT_FOUND;
          }
        });
      }

    }
  }
}

@@ -2896,37 +2896,38 @@
 sumer);%0A  %7D%0A%0A  p
-ublic
+rivate
  void walk(@NotN

make method private