/*
 * 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 git4idea.log;

import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.vcs.log.*;
import com.intellij.vcs.log.impl.VcsLogFilterCollectionImpl.VcsLogFilterCollectionBuilder;
import com.intellij.vcs.log.util.BekUtil;
import org.jetbrains.annotations.NotNull;

import java.util.Collections;
import java.util.List;
import java.util.Set;

class GitBekParentFixer {
  @NotNull private static final String MAGIC_TEXT = "Merge remote";
  @NotNull private static final VcsLogFilterCollection MAGIC_FILTER = createVcsLogFilterCollection();

  @NotNull private final Set<Hash> myWrongCommits;

  private GitBekParentFixer(@NotNull Set<Hash> wrongCommits) {
    myWrongCommits = wrongCommits;
  }

  @NotNull
  static GitBekParentFixer prepare(@NotNull VirtualFile root, @NotNull GitLogProvider provider) throws VcsException {
    if (!BekUtil.isBekEnabled()) {
      return new GitBekParentFixer(Collections.emptySet());
    }
    return new GitBekParentFixer(getWrongCommits(provider, root));
  }

  @NotNull
  TimedVcsCommit fixCommit(@NotNull TimedVcsCommit commit) {
    if (!myWrongCommits.contains(commit.getId())) {
      return commit;
    }
    return reverseParents(commit);
  }

  @NotNull
  private static Set<Hash> getWrongCommits(@NotNull GitLogProvider provider, @NotNull VirtualFile root) throws VcsException {
    List<TimedVcsCommit> commitsMatchingFilter = provider.getCommitsMatchingFilter(root, MAGIC_FILTER, -1);
    return ContainerUtil.map2Set(commitsMatchingFilter, timedVcsCommit -> timedVcsCommit.getId());
  }

  @NotNull
  private static TimedVcsCommit reverseParents(@NotNull final TimedVcsCommit commit) {
    return new TimedVcsCommit() {
      @Override
      public long getTimestamp() {
        return commit.getTimestamp();
      }

      @NotNull
      @Override
      public Hash getId() {
        return commit.getId();
      }

      @NotNull
      @Override
      public List<Hash> getParents() {
        return ContainerUtil.reverse(commit.getParents());
      }
    };
  }

  private static VcsLogFilterCollection createVcsLogFilterCollection() {
    VcsLogTextFilter textFilter = new VcsLogTextFilter() {
      @Override
      public boolean matchesCase() {
        return false;
      }

      @Override
      public boolean isRegex() {
        return false;
      }

      @NotNull
      @Override
      public String getText() {
        return MAGIC_TEXT;
      }

      @Override
      public boolean matches(@NotNull VcsCommitMetadata details) {
        return details.getFullMessage().contains(MAGIC_TEXT);
      }
    };

    return new VcsLogFilterCollectionBuilder().with(textFilter).build();
  }
}

@@ -1276,21 +1276,25 @@
 Hash%3E my
-Wrong
+Incorrect
 Commits;
@@ -1342,21 +1342,25 @@
 t%3CHash%3E 
-wrong
+incorrect
 Commits)
@@ -1368,21 +1368,25 @@
 %7B%0A    my
-Wrong
+Incorrect
 Commits 
@@ -1391,13 +1391,17 @@
 s = 
-wrong
+incorrect
 Comm
@@ -1676,21 +1676,25 @@
 ixer(get
-Wrong
+Incorrect
 Commits(
@@ -1799,21 +1799,25 @@
  if (!my
-Wrong
+Incorrect
 Commits.
@@ -1956,13 +1956,17 @@
  get
-Wrong
+Incorrect
 Comm
@@ -2331,22 +2331,16 @@
 NotNull 
-final 
 TimedVcs

rename wrong -> incorrect