package io.vertx.lang.groovy;

import groovy.lang.GroovyClassLoader;
import groovy.lang.Script;
import io.vertx.core.AsyncResult;
import io.vertx.core.DeploymentOptions;
import io.vertx.core.Handler;
import io.vertx.core.Vertx;
import io.vertx.core.json.JsonObject;
import io.vertx.groovy.core.GroovyVerticle;
import io.vertx.groovy.core.ScriptVerticle;
import junit.framework.AssertionFailedError;
import org.junit.Before;
import org.junit.Test;

import static org.junit.Assert.*;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author <a href="mailto:julien@julienviet.com">Julien Viet</a>
 */
public class DeploymentTest {

  public static final AtomicBoolean started = new AtomicBoolean();
  public static final AtomicBoolean stopped = new AtomicBoolean();

  private static <T>  T assertResult(AsyncResult<T> asyncResult) {
    if (asyncResult.succeeded()) {
      return asyncResult.result();
    } else {
      AssertionFailedError afe = new AssertionFailedError();
      afe.initCause(asyncResult.cause());
      throw afe;
    }
  }

  private Class assertScript(String script) {
    GroovyClassLoader loader = new GroovyClassLoader(getClass().getClassLoader());
    try {
      return loader.loadClass(getClass().getPackage().getName() + "." + script);
    } catch (ClassNotFoundException e) {
      AssertionFailedError afe = new AssertionFailedError();
      afe.initCause(e);
      throw afe;
    }
  }

  @Before
  public void before() {
    started.set(false);
    stopped.set(false);
  }

  @Test
  public void testDeployVerticleClass() throws Exception {
    assertDeploy((vertx, onDeploy) ->
        vertx.deployVerticle(
            "groovy:io/vertx/lang/groovy/LifeCycleVerticleClass.groovy",
            DeploymentOptions.options(),
            onDeploy));
    assertTrue(started.get());
    assertTrue(stopped.get());
  }

  @Test
  public void testDeployVerticleClassInstance() throws Exception {
    Class clazz = assertScript("LifeCycleVerticleClass");
    GroovyVerticle verticle = (GroovyVerticle) clazz.newInstance();
    assertDeploy((vertx, onDeploy) ->
        vertx.deployVerticleInstance(
            verticle.asJavaVerticle(),
            DeploymentOptions.options(),
            onDeploy));
    assertTrue(started.get());
    assertTrue(stopped.get());
  }

  @Test
  public void testDeployVerticleScriptInstance() throws Exception {
    Class clazz = assertScript("LifeCycleVerticleScript");
    Script script = (Script) clazz.newInstance();
    ScriptVerticle verticle = new ScriptVerticle(script);
    assertDeploy((vertx, onDeploy) ->
        vertx.deployVerticleInstance(
            verticle,
            DeploymentOptions.options(),
            onDeploy));
    assertTrue(started.get());
    assertTrue(stopped.get());
  }

  @Test
  public void testDeployVerticleInClass() throws Exception {
    assertDeploy((vertx, onDeploy) ->
        vertx.deployVerticle(
            "groovy:io/vertx/lang/groovy/LifeCycleVerticleScript.groovy",
            DeploymentOptions.options(),
            onDeploy));
    assertTrue(started.get());
    assertTrue(stopped.get());
  }

  @Test
  public void testResolveVertxInScript() throws Exception {
    assertDeploy((vertx, onDeploy) ->
        vertx.deployVerticle(
            "groovy:io/vertx/lang/groovy/ResolveVertxVerticleScript.groovy",
            DeploymentOptions.options().setConfig(new JsonObject()),
            onDeploy));
    assertTrue(started.get());
  }

  @Test
  public void testResolveVertxScript() throws Exception {
    assertDeploy((vertx, onDeploy) ->
        vertx.deployVerticle(
            "groovy:io/vertx/lang/groovy/ResolveVertxVerticleScript.groovy",
            DeploymentOptions.options().setConfig(new JsonObject()),
            onDeploy));
    assertTrue(started.get());
  }

  @Test
  public void testDeployVerticleGroovyScriptNoStop() throws Exception {
    Vertx vertx = Vertx.vertx();
    try {
      BlockingQueue<AsyncResult<String>> deployed = new ArrayBlockingQueue<>(1);
      vertx.deployVerticle("groovy:io/vertx/lang/groovy//NoStopVerticleScript.groovy", DeploymentOptions.options(), deployed::add);
      AsyncResult<String> deployment = deployed.poll(10, TimeUnit.SECONDS);
      String deploymentId = assertResult(deployment);
      BlockingQueue<AsyncResult<Void>> undeployed = new ArrayBlockingQueue<>(1);
      vertx.undeployVerticle(deploymentId, undeployed::add);
      AsyncResult<?> undeployment = undeployed.poll(10, TimeUnit.SECONDS);
      assertResult(undeployment);
    } finally {
      vertx.close();
    }
  }

  @FunctionalInterface
  static interface Deployer {
    void deploy(Vertx vertx, Handler<AsyncResult<String>> onDeploy);
  }

  private void assertDeploy(Deployer deployer) throws Exception {
    Vertx vertx = Vertx.vertx();
    try {
      BlockingQueue<AsyncResult<String>> deployed = new ArrayBlockingQueue<>(1);
      deployer.deploy(vertx, deployed::add);
      AsyncResult<String> deployment = deployed.poll(10, TimeUnit.SECONDS);
      String deploymentId = assertResult(deployment);
      BlockingQueue<AsyncResult<Void>> undeployed = new ArrayBlockingQueue<>(1);
      vertx.undeployVerticle(deploymentId, undeployed::add);
      AsyncResult<?> undeployment = undeployed.poll(10, TimeUnit.SECONDS);
      assertResult(undeployment);
    } finally {
      vertx.close();
    }
  }
}

@@ -2473,24 +2473,16 @@
 leScript
-Instance
 () throw
@@ -2499,175 +2499,8 @@
 n %7B%0A
-    Class clazz = assertScript(%22LifeCycleVerticleScript%22);%0A    Script script = (Script) clazz.newInstance();%0A    ScriptVerticle verticle = new ScriptVerticle(script);%0A
     
@@ -2557,32 +2557,24 @@
 ployVerticle
-Instance
 (%0A          
@@ -2575,24 +2575,76 @@
         
-verticle
+%22groovy:io/vertx/lang/groovy/LifeCycleVerticleScript.groovy%22
 ,%0A      
@@ -2813,15 +2813,22 @@
 icle
-InClass
+ScriptInstance
 () t
@@ -2837,32 +2837,199 @@
 ows Exception %7B%0A
+    Class clazz = assertScript(%22LifeCycleVerticleScript%22);%0A    Script script = (Script) clazz.newInstance();%0A    ScriptVerticle verticle = new ScriptVerticle(script);%0A
     assertDeploy
@@ -3070,32 +3070,40 @@
 x.deployVerticle
+Instance
 (%0A            %22g
@@ -3104,68 +3104,16 @@
     
-%22groovy:io/vertx/lang/groovy/LifeCycleVerticleScript.groovy%22
+verticle
 ,%0A  
@@ -3282,22 +3282,21 @@
 eVertxIn
-Script
+Class
 () throw
@@ -3430,38 +3430,37 @@
 lveVertxVerticle
-Script
+Class
 .groovy%22,%0A      
@@ -3620,16 +3620,18 @@
 lveVertx
+In
 Script()

Fix wrong tests