package com.intellij.vcs.log.graphmodel.impl;

import com.intellij.openapi.util.Condition;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.vcs.log.Hash;
import com.intellij.vcs.log.graph.elements.Edge;
import com.intellij.vcs.log.graph.elements.Node;
import com.intellij.vcs.log.graph.mutable.MutableGraph;
import com.intellij.vcs.log.graph.mutable.elements.MutableNode;
import com.intellij.vcs.log.graph.mutable.elements.MutableNodeRow;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

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

/**
 * @author erokhins
 */
public class BranchVisibleNodes {

  @NotNull private final MutableGraph myGraph;
  @NotNull private Set<Node> myVisibleNodes = Collections.emptySet();

  public BranchVisibleNodes(@NotNull MutableGraph graph) {
    myGraph = graph;
  }

  @NotNull
  public Set<Node> generateVisibleBranchesNodes(@NotNull Function<Node, Boolean> isStartedNode) {
    Set<Node> visibleNodes = new HashSet<Node>();
    for (MutableNodeRow row : myGraph.getAllRows()) {
      for (MutableNode node : row.getInnerNodeList()) {
        if (isStartedNode.fun(node)) {
          visibleNodes.add(node);
        }
        if (isStartedNode.fun(node) || visibleNodes.contains(node)) {
          for (Edge edge : node.getInnerDownEdges()) {
            visibleNodes.add(edge.getDownNode());
          }
        }
      }
    }
    return visibleNodes;
  }

  public void setVisibleNodes(@NotNull Set<Node> visibleNodes) {
    myVisibleNodes = visibleNodes;
  }

  public Set<Node> getVisibleNodes() {
    return Collections.unmodifiableSet(myVisibleNodes);
  }

  public boolean isVisibleNode(@NotNull Node node) {
    return myVisibleNodes.contains(node);
  }

  @Nullable
  public Node getNodeIfVisible(@NotNull final Hash hash) {
    return ContainerUtil.find(myVisibleNodes, new Condition<Node>() {
      @Override
      public boolean value(Node node) {
        return node.getCommitHash().equals(hash);
      }
    });
  }

}

@@ -44,52 +44,8 @@
 l;%0A%0A
-import com.intellij.openapi.util.Condition;%0A
 impo
@@ -75,16 +75,16 @@
 nction;%0A
+
 import c
@@ -587,16 +587,38 @@
 ashSet;%0A
+import java.util.Map;%0A
 import j
@@ -811,16 +811,93 @@
 tySet();
+%0A  @NotNull private Map%3CHash, Node%3E myVisibleHashes = Collections.emptyMap();
 %0A%0A  publ
@@ -1660,32 +1660,182 @@
 = visibleNodes;%0A
+    myVisibleHashes = ContainerUtil.newHashMap();%0A    for (Node node : myVisibleNodes) %7B%0A      myVisibleHashes.put(node.getCommitHash(), node);%0A    %7D%0A
   %7D%0A%0A  public Se
@@ -2109,186 +2109,32 @@
 urn 
-ContainerUtil.find(myVisibleNodes, new Condition%3CNode%3E() %7B%0A      @Override%0A      public boolean value(Node node) %7B%0A        return node.getCommitHash().equals(hash);%0A      %7D%0A    %7D
+myVisibleHashes.get(hash
 );%0A 

optimize check if hash corresponds to a visible node