/*
 * Copyright 2012 the original author or authors.
 *
 * 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.vertx.java.test.junit;

import java.io.File;
import java.lang.annotation.Annotation;
import java.util.Map;

import org.junit.runner.Description;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.vertx.java.core.Handler;
import org.vertx.java.core.impl.VertxInternal;
import org.vertx.java.deploy.Container;
import org.vertx.java.deploy.Verticle;
import org.vertx.java.deploy.impl.VerticleManager;
import org.vertx.java.test.VertxConfiguration;
import org.vertx.java.test.utils.DeploymentRegistry;
import org.vertx.java.test.utils.DeploymentUtils;
import org.vertx.java.test.utils.InjectionUtils;

/**
 * @author swilliams
 *
 */
public class VertxJUnit4ClassRunner extends JUnit4ClassRunnerAdapter {

  private VertxInternal vertx;

  private VerticleManager manager;

  private VertxConfiguration configuration;

  private File modDir;

  private Map<Annotation, String> classDeployments;

  private Map<Annotation, String> methodDeployments;

  private Verticle verticle;

  public VertxJUnit4ClassRunner(Class<?> klass) throws InitializationError {
    super(klass);
  }

  @Override
  protected void beforeAll() {

    VertxBuilder builder = new VertxBuilder();

    String vertxMods = System.getProperty("vertx.mods");
    this.configuration = getDescription().getAnnotation(VertxConfiguration.class);
    if (configuration != null) {
      if (!"".equalsIgnoreCase(configuration.hostname())) {
        builder.setAddress(configuration.hostname());
      }
      if (configuration.port() > 0) {
        builder.setPort(configuration.port());
      }
      if (!"".equalsIgnoreCase(configuration.modsDir())) {
        vertxMods = configuration.modsDir();
        System.setProperty("vertx.mods", vertxMods);
      }
    }

    this.modDir = new File(vertxMods);
    if (!modDir.exists()) {
      modDir.mkdirs();
    }

    this.vertx = builder.build();
    this.manager = new VerticleManager(vertx);
  }

  @Override
  protected void beforeCreateTest() {
    //
  }

  @Override
  protected void afterCreateTest(Object target) {

    if (target instanceof Verticle) {
      this.verticle = (Verticle) target;
      verticle.setVertx(vertx);
      verticle.setContainer(new Container(manager));
      try {
        System.out.println("Starting test verticle!");
        verticle.start();
      } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
  }

  @Override
  protected void injectResources(Object target) {
    if ((configuration != null && configuration.injectResources()) || configuration == null) {
      InjectionUtils.inject(vertx, target);
      InjectionUtils.inject(manager, target);
    }
  }

  @Override
  protected void injectMethodResources(FrameworkMethod method, Object target) {
//    injectResources(target); // TODO probable double setting... test & remove
  }

  @Override
  protected void beforeClass() {
    long timeout = Long.getLong("vertx.test.timeout", 15000L);
    this.classDeployments = JUnitDeploymentUtils.deploy(manager, modDir, getDescription(), timeout);
  }

  @Override
  protected void beforeTest(Description description, Object target) {
    long timeout = Long.getLong("vertx.test.timeout", 15000L);
    this.methodDeployments = JUnitDeploymentUtils.deploy(manager, modDir, description, timeout);
    DeploymentRegistry.register(methodDeployments);
  }

  @Override
  protected void afterTest(Description description, Object target) {
    if (methodDeployments.size() > 0) {
      DeploymentUtils.undeploy(manager, methodDeployments);
    }

    // avoid leaks
    DeploymentRegistry.clear();
  }

  @Override
  protected void beforeAfterClass() {

    if (this.verticle != null) {
      try {
        verticle.stop();
      } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
  }

  @Override
  protected void afterClass() {
    if (classDeployments.size() > 0) {
      DeploymentUtils.undeploy(manager, classDeployments);
    }
  }

  @Override
  protected void afterAll() {

    manager.undeployAll(new Handler<Void>() {
      @Override
      public void handle(Void event) {
        // TODO log this
      }});
  }

}

@@ -726,16 +726,98 @@
 til.Map;
+%0Aimport java.util.concurrent.CountDownLatch;%0Aimport java.util.concurrent.TimeUnit;
 %0A%0Aimport
@@ -951,44 +951,8 @@
 or;%0A
-import org.vertx.java.core.Handler;%0A
 impo
@@ -1167,24 +1167,84 @@
 figuration;%0A
+import org.vertx.java.test.utils.CountDownLatchDoneHandler;%0A
 import org.v
@@ -2008,16 +2008,39 @@
 tx.mods%22
+, %22build/tmp/mods-test%22
 );%0A    t
@@ -3144,69 +3144,36 @@
     
-// TODO Auto-generated catch block%0A        e.printStackTrace(
+throw new RuntimeException(e
 );%0A 
@@ -4823,112 +4823,530 @@
 ) %7B%0A
-%0A    manager.undeployAll(new Handler%3CVoid%3E() %7B%0A      @Override%0A      public void handle(Void event
+    CountDownLatch latch = new CountDownLatch(1);%0A    CountDownLatchDoneHandler%3CVoid%3E h = new CountDownLatchDoneHandler%3C%3E(latch);%0A    manager.undeployAll(h);%0A    long timeout = 5L;%0A    if (configuration != null) %7B%0A      timeout = configuration.shutdownTimeoutSeconds();%0A    %7D%0A    try %7B%0A      boolean awaited = latch.await(timeout, TimeUnit.SECONDS);%0A      if (!awaited) %7B%0A        System.out.println(%22Waited for %22 + timeout + %22 but not all undeployments may have completed%22);%0A      %7D%0A    %7D catch (InterruptedException e
 ) %7B%0A
-  
     
@@ -5359,27 +5359,67 @@
 ODO 
-log this%0A      %7D%7D);
+Auto-generated catch block%0A      e.printStackTrace();%0A    %7D
 %0A  %7D

use configurable timeout for shutdown