package zielu.gittoolbox.blame;

import com.intellij.openapi.vcs.annotate.FileAnnotation;
import com.intellij.openapi.vcs.history.VcsRevisionNumber;
import com.intellij.openapi.vfs.VirtualFile;
import gnu.trove.THashMap;
import gnu.trove.TIntObjectHashMap;
import java.util.Map;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import zielu.gittoolbox.revision.RevisionInfo;
import zielu.gittoolbox.revision.RevisionService;

class BlameAnnotationImpl implements BlameAnnotation {
  private final FileAnnotation annotation;
  private final RevisionService revisionService;
  private final Map<VcsRevisionNumber, RevisionInfo> revisions;
  private final TIntObjectHashMap<VcsRevisionNumber> lineRevisions;

  BlameAnnotationImpl(@NotNull FileAnnotation annotation, @NotNull RevisionService revisionService) {
    this.annotation = annotation;
    this.revisionService = revisionService;
    lineRevisions =  new TIntObjectHashMap<>(this.annotation.getLineCount() + 1);
    revisions = new THashMap<>(this.annotation.getLineCount() + 1);
  }

  @NotNull
  @Override
  public RevisionInfo getBlame(int lineNumber) {
    VcsRevisionNumber revisionNumber = getLineRevisionNumber(lineNumber);
    if (revisionNumber != VcsRevisionNumber.NULL) {
      RevisionInfo revisionInfo = revisions.get(revisionNumber);
      if (revisionInfo == null) {
        revisionInfo = loadRevision(lineNumber);
      }
      return revisionInfo;
    }
    return RevisionInfo.EMPTY;
  }

  @NotNull
  private VcsRevisionNumber getLineRevisionNumber(int lineNumber) {
    VcsRevisionNumber revisionNumber = lineRevisions.get(lineNumber);
    if (revisionNumber == null) {
      VcsRevisionNumber lineRevisionNumber = annotation.getLineRevisionNumber(lineNumber);
      if (lineRevisionNumber == null) {
        lineRevisionNumber = VcsRevisionNumber.NULL;
      }
      lineRevisions.put(lineNumber, lineRevisionNumber);
      revisionNumber = lineRevisionNumber;
    }
    return revisionNumber;
  }

  @NotNull
  private RevisionInfo loadRevision(int lineNumber) {
    RevisionInfo revisionInfo = revisionService.getForLine(annotation, lineNumber);
    revisions.put(revisionInfo.getRevisionNumber(), revisionInfo);
    return revisionInfo;
  }

  @Override
  public boolean isChanged(@NotNull VcsRevisionNumber revision) {
    return annotation.isBaseRevisionChanged(revision);
  }

  @Nullable
  @Override
  public VirtualFile getVirtualFile() {
    return annotation.getFile();
  }

  @Override
  public boolean updateRevision(@NotNull RevisionInfo revisionInfo) {
    if (revisions.containsKey(revisionInfo.getRevisionNumber())) {
      revisions.put(revisionInfo.getRevisionNumber(), revisionInfo);
      return true;
    }
    return false;
  }

  @Override
  public String toString() {
    return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
        .append("file", getVirtualFile())
        .append("currentRevision", annotation.getCurrentRevision())
        .toString();
  }
}

@@ -218,44 +218,8 @@
 ap;%0A
-import gnu.trove.TIntObjectHashMap;%0A
 impo
@@ -232,24 +232,24 @@
 a.util.Map;%0A
+
 import org.a
@@ -758,34 +758,16 @@
 e final 
-TIntObjectHashMap%3C
 VcsRevis
@@ -775,17 +775,18 @@
 onNumber
-%3E
+%5B%5D
  lineRev
@@ -997,34 +997,31 @@
 ns =
- 
  new 
-TIntObjectHashMap%3C%3E(
+VcsRevisionNumber%5B
 this
@@ -1046,25 +1046,25 @@
 eCount() + 1
-)
+%5D
 ;%0A    revisi
@@ -1680,21 +1680,17 @@
 evisions
-.get(
+%5B
 lineNumb
@@ -1683,33 +1683,33 @@
 sions%5BlineNumber
-)
+%5D
 ;%0A    if (revisi
@@ -1939,21 +1939,17 @@
 evisions
-.put(
+%5B
 lineNumb
@@ -1950,17 +1950,19 @@
 neNumber
-,
+%5D =
  lineRev
@@ -1964,33 +1964,32 @@
 neRevisionNumber
-)
 ;%0A      revision

Use plain array to store line revisions