/*
 * Copyright 2000-2013 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;

import com.intellij.openapi.progress.EmptyProgressIndicator;
import cucumber.annotation.en.Then;
import cucumber.annotation.en.When;
import git4idea.checkout.GitCheckoutProvider;
import git4idea.commands.GitHttpAuthenticator;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import static git4idea.GitCucumberWorld.*;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

/**
 * @author Kirill Likhodedov
 */
public class GitRemoteSteps {

  private TestAuthenticator myAuthenticator;
  private CountDownLatch myCloneCompleted = new CountDownLatch(1);

  @When("I clone (\\S+)")
  public void I_clone_the_repository(final String url) {
    myAuthenticator = new TestAuthenticator();

    myHttpAuthService.register(myAuthenticator);

    executeOnPooledThread(new Runnable() {
      @Override
      public void run() {
        String projectName = url.substring(url.lastIndexOf('/') + 1).replace(".git", "");
        GitCheckoutProvider.doClone(myProject, new EmptyProgressIndicator(), myGit, projectName, myTestRoot, url);
        myCloneCompleted.countDown();
      }
    });
  }

  @Then("I should be asked for the password")
  public void I_should_be_asked_for_the_password() throws InterruptedException {
    myAuthenticator.waitUntilPasswordIsAsked();
    assertTrue("Password was not requested", myAuthenticator.wasPasswordAsked());
  }

  @Then("I should be asked for the username")
  public void I_should_be_asked_for_the_username() throws InterruptedException {
    myAuthenticator.waitUntilUsernameIsAsked();
    assertTrue("Password was not requested", myAuthenticator.wasUsernameAsked());
  }

  @When("I provide password '(\\S+)'")
  public void I_provide_password(String password) {
    myAuthenticator.supplyPassword(password);
  }

  @When("I provide username '(\\S+)'")
  public void I_provide_username(String username) {
    myAuthenticator.supplyUsername(username);
  }

  @Then("repository should (not )?be cloned to (\\S+)")
  public void the_repository_should_be_cloned(String negation, String dir) throws InterruptedException {
    assertTrue("Clone didn't complete during the reasonable period of time", myCloneCompleted.await(5, TimeUnit.SECONDS));
    if (negation == null) {
      assertTrue("Repository directory was not found", new File(myTestRoot, dir).exists());
    }
    else {
      assertFalse("Repository directory shouldn't exist", new File(myTestRoot, dir).exists());
    }
  }

  private static class TestAuthenticator implements GitHttpAuthenticator {

    private static final int TIMEOUT = 10;

    private final CountDownLatch myPasswordAskedWaiter = new CountDownLatch(1);
    private final CountDownLatch myUsernameAskedWaiter = new CountDownLatch(1);
    private final CountDownLatch myPasswordSuppliedWaiter = new CountDownLatch(1);
    private final CountDownLatch myUsernameSuppliedWaiter = new CountDownLatch(1);

    private volatile boolean myPasswordAsked;
    private volatile boolean myUsernameAsked;

    private volatile String myPassword;
    private volatile String myUsername;

    @NotNull
    @Override
    public String askPassword(@NotNull String url) {
      myPasswordAskedWaiter.countDown();
      myPasswordAsked  = true;
      try {
        assertTrue("Password was not supplied during the reasonable period of time",
                   myPasswordSuppliedWaiter.await(TIMEOUT, TimeUnit.SECONDS));
      }
      catch (InterruptedException e) {
        throw new RuntimeException(e);
      }
      return myPassword;
    }

    @NotNull
    @Override
    public String askUsername(@NotNull String url) {
      myUsernameAskedWaiter.countDown();
      myUsernameAsked  = true;
      try {
        assertTrue("Password was not supplied during the reasonable period of time",
                   myUsernameSuppliedWaiter.await(TIMEOUT, TimeUnit.SECONDS));
      }
      catch (InterruptedException e) {
        throw new RuntimeException(e);
      }
      return myUsername;
    }


    void supplyPassword(@NotNull String password) {
      myPasswordSuppliedWaiter.countDown();
      myPassword = password;
    }

    void supplyUsername(@NotNull String username) {
      myUsernameSuppliedWaiter.countDown();
      myUsername = username;
    }

    void waitUntilPasswordIsAsked() throws InterruptedException {
      assertTrue("Password was not asked during the reasonable period of time",
                 myPasswordAskedWaiter.await(TIMEOUT, TimeUnit.SECONDS));
    }

    void waitUntilUsernameIsAsked() throws InterruptedException {
      assertTrue("Username was not asked during the reasonable period of time",
                 myUsernameAskedWaiter.await(TIMEOUT, TimeUnit.SECONDS));
    }

    @Override
    public void saveAuthData() {
    }

    @Override
    public void forgetPassword() {
    }

    boolean wasPasswordAsked() {
      return myPasswordAsked;
    }

    boolean wasUsernameAsked() {
      return myUsernameAsked;
    }
  }
}


@@ -3885,34 +3885,24 @@
 ordAsked
-Waiter.countDown()
+  = true
 ;%0A      
@@ -3912,32 +3912,42 @@
 asswordAsked
-  = true
+Waiter.countDown()
 ;%0A      try 
@@ -4339,34 +4339,24 @@
 ameAsked
-Waiter.countDown()
+  = true
 ;%0A      
@@ -4366,32 +4366,42 @@
 sernameAsked
-  = true
+Waiter.countDown()
 ;%0A      try 
@@ -4765,63 +4765,63 @@
 word
-SuppliedWaiter.countDown();%0A      myPassword = password
+ = password;%0A      myPasswordSuppliedWaiter.countDown()
 ;%0A  
@@ -4897,63 +4897,63 @@
 name
-SuppliedWaiter.countDown();%0A      myUsername = username
+ = username;%0A      myUsernameSuppliedWaiter.countDown()
 ;%0A  

Fix possible race condition in http tests