content: package com.github.aesteve.vertx.nubes.fixtures;
  
  import com.github.aesteve.vertx.nubes.Config;
  import com.github.aesteve.vertx.nubes.reflections.annotations.ReflectionProviderHelper;
  import com.github.aesteve.vertx.nubes.services.ServiceRegistry;
  import com.github.aesteve.vertx.nubes.utils.async.AsyncUtils;
  import io.vertx.core.Future;
  import io.vertx.core.Handler;
  import io.vertx.core.Vertx;
  import org.reflections.Reflections;
  
  import java.lang.reflect.Field;
  import java.util.ArrayList;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Set;
  
  public class FixtureLoader {
  
    private final Vertx vertx;
    private final Config config;
    private final ServiceRegistry serviceRegistry;
    private final Set<Fixture> fixtures;
  
    public FixtureLoader(Vertx vertx, Config config, ServiceRegistry serviceRegistry) {
      this.vertx = vertx;
      this.config = config;
      this.serviceRegistry = serviceRegistry;
      fixtures = new HashSet<>();
    }
  
    public void setUp(Future<Void> future) {
      instanciateFixtures(future);
      if (future.failed()) {
        return;
      }
      exec(future, "startUp");
    }
  
    public void tearDown(Future<Void> future) {
      exec(future, "tearDown");
    }
  
    private void exec(Future<Void> rootFuture, String methodName) {
      if (fixtures.isEmpty()) {
        rootFuture.complete();
        return;
      }
      List<Handler<Future<Void>>> list = new ArrayList<>();
      fixtures.stream().sorted().forEach(fixture -> {
        switch (methodName) {
          case "startUp":
            list.add(fut -> fixture.startUp(vertx, fut));
            break;
          case "tearDown":
            list.add(fut -> fixture.tearDown(vertx, fut));
            break;
          default:
            throw new IllegalArgumentException("Unknown method : " + methodName);
        }
      });
      AsyncUtils.chainHandlers(rootFuture, list);
    }
  
    private void injectServicesIntoFixture(Fixture fixture) throws IllegalAccessException {
      for (Field field : fixture.getClass().getDeclaredFields()) {
        Object service = serviceRegistry.get(field);
        if (service != null) {
          field.setAccessible(true);
          field.set(fixture, service);
        }
      }
    }
  
    private void instanciateFixtures(Future<Void> future) {
      List<String> fixturePackages = config.getFixturePackages();
      if (fixturePackages == null || fixturePackages.isEmpty()) {
        return;
      }
      for (String fixturePackage : fixturePackages) {
        if (fixturePackage == null)
          continue;
  
        Set<Class<? extends Fixture>> fixtureClasses = ReflectionProviderHelper.getAnnotationProcessor(config, fixturePackage).getSubClassOf(Fixture.class);
        for (Class<? extends Fixture> fixtureClass : fixtureClasses) {
          try {
            Fixture fixture = fixtureClass.newInstance();
            injectServicesIntoFixture(fixture);
            fixtures.add(fixture);
          } catch (Exception e) {
            future.fail(e);
            return;
          }
        }
      }
    }
  
  }
  