/*
 * 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 org.jetbrains.plugins.github.test;

import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.testFramework.VfsTestUtil;
import git4idea.commands.GitHttpAuthService;
import git4idea.commands.GitHttpAuthenticator;
import git4idea.config.GitConfigUtil;
import git4idea.test.GitHttpAuthTestService;
import git4idea.repo.GitRepository;
import git4idea.test.GitExecutor;
import git4idea.test.GitPlatformTest;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.github.util.GithubAuthData;
import org.jetbrains.plugins.github.util.GithubSettings;
import org.jetbrains.plugins.github.util.GithubUtil;

import static org.junit.Assume.assumeNotNull;

/**
 * <p>The base class for JUnit platform tests of the github plugin.<br/>
 *    Extend this test to write a test on GitHub which has the following features/limitations:
 * <ul>
 * <li>This is a "platform test case", which means that IDEA [almost] production platform is set up before the test starts.</li>
 * <li>Project base directory is the root of everything. </li>
 * </ul></p>
 * <p>All tests inherited from this class are required to have a login and a password to access the Github server.
 *    They are set up in Environment variables: <br/>
 *    <code>idea.test.github.host=myHost<br/>
 *          idea.test.github.login1=mylogin1<br/> // test user
 *          idea.test.github.login2=mylogin2<br/> // user with configured test repositories
 *          idea.test.github.password=mypassword</code> // password for test user
 * </p>
 *
 */
public abstract class GithubTest extends GitPlatformTest {

  @Nullable protected GitRepository myRepository;

  @NotNull protected GithubSettings myGitHubSettings;
  @NotNull private GitHttpAuthTestService myHttpAuthService;

  @NotNull protected GithubAuthData myAuth;
  @NotNull protected String myHost;
  @NotNull protected String myLogin1;
  @NotNull protected String myLogin2;
  @NotNull protected String myPassword;

  protected void createProjectFiles() {
    VfsTestUtil.createFile(myProjectRoot, "file.txt", "file.txt content");
    VfsTestUtil.createFile(myProjectRoot, "file", "file content");
    VfsTestUtil.createFile(myProjectRoot, "folder/file1", "file1 content");
    VfsTestUtil.createFile(myProjectRoot, "folder/file2", "file2 content");
    VfsTestUtil.createFile(myProjectRoot, "folder/empty_file");
    VfsTestUtil.createFile(myProjectRoot, "folder/dir/file3", "file3 content");
    VfsTestUtil.createDir (myProjectRoot, "folder/empty_folder");
  }

  protected void checkNotification(@NotNull NotificationType type, @Nullable String title, @Nullable String content) {
    Notification actualNotification = myVcsNotifier.getLastNotification();
    assertNotNull("No notification was shown", actualNotification);

    if (title != null) {
      assertEquals("Notification has wrong title (content: " + actualNotification.getContent() + ")", title, actualNotification.getTitle());
    }
    if (content != null) {
      assertEquals("Notification has wrong content", content, actualNotification.getContent());
    }
    assertEquals("Notification has wrong type", type, actualNotification.getType());
  }

  protected void registerHttpAuthService() {
    GitHttpAuthTestService myHttpAuthService = (GitHttpAuthTestService)ServiceManager.getService(GitHttpAuthService.class);
    myHttpAuthService.register(new GitHttpAuthenticator() {
      @NotNull
      @Override
      public String askPassword(@NotNull String url) {
        return myPassword;
      }

      @NotNull
      @Override
      public String askUsername(@NotNull String url) {
        return myLogin1;
      }

      @Override
      public void saveAuthData() {
      }

      @Override
      public void forgetPassword() {
      }

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

  // workaround: user on test server got "" as username, so git can't generate default identity
  protected void setGitIdentity(VirtualFile root) {
    try {
      GitConfigUtil.setValue(myProject, root, "user.name", "Github Test");
      GitConfigUtil.setValue(myProject, root, "user.email", "githubtest@jetbrains.com");
    }
    catch (VcsException e) {
      e.printStackTrace();
    }
  }

  protected void initGitChecks() {
    myRepository = myGitRepositoryManager.getRepositoryForFile(myProjectRoot);
  }

  protected void checkGitExists() {
    assertNotNull("Git repository does not exist", myRepository);
  }

  protected void checkRemoteConfigured() {
    assertNotNull(myRepository);

    assertNotNull("GitHub remote is not configured", GithubUtil.findGithubRemoteUrl(myRepository));
  }

  protected void checkLastCommitPushed() {
    assertNotNull(myRepository);

    String hash = GitExecutor.git(myRepository, "log -1 --pretty=%h");
    String ans = GitExecutor.git(myRepository, "branch --contains " + hash + " -a");
    assertTrue(ans.contains("remotes/origin"));
  }

  @Override
  protected final void setUp() throws Exception {
    super.setUp();

    final String host = System.getenv("idea.test.github.host");
    final String login1 = System.getenv("idea.test.github.login1");
    final String login2 = System.getenv("idea.test.github.login2");
    final String password = System.getenv("idea.test.github.password1");

    // TODO change to assert when a stable Github testing server is ready
    assumeNotNull(host);
    assumeNotNull(login1);
    assumeNotNull(password);

    myHost = host;
    myLogin1 = login1;
    myLogin2 = login2;
    myPassword = password;
    myAuth = GithubAuthData.createBasicAuth(host, login1, password);

    myGitHubSettings = GithubSettings.getInstance();
    myGitHubSettings.setAuthData(myAuth, false);

    myHttpAuthService = (GitHttpAuthTestService)ServiceManager.getService(GitHttpAuthService.class);


    try {
      beforeTest();
    }
    catch (Exception e) {
      try {
        tearDown();
      }
      catch (Exception e2) {
        e2.printStackTrace();
      }
      throw e;
    }
  }

  @Override
  protected final void tearDown() throws Exception {
    try {
      afterTest();
    }
    finally {
      myHttpAuthService.cleanup();
      super.tearDown();
    }
  }

  protected void beforeTest() throws Exception {
  }

  protected void afterTest() throws Exception {
  }
}

@@ -6649,17 +6649,16 @@
 lass);%0A%0A
-%0A
     try 
@@ -6731,24 +6731,25 @@
         
-tearDown
+afterTest
 ();%0A    
@@ -6815,24 +6815,67 @@
 ();%0A      %7D%0A
+      finally %7B%0A        cleanup();%0A      %7D%0A
       throw 
@@ -7008,34 +7008,16 @@
 %7B%0A      
-myHttpAuthService.
 cleanup(
@@ -7046,32 +7046,128 @@
 n();%0A    %7D%0A  %7D%0A%0A
+  private void cleanup() %7B%0A    if (myHttpAuthService != null) myHttpAuthService.cleanup();%0A  %7D%0A%0A
   protected void

fix test