package com.skcraft.plume.common.util.service;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.sk89q.worldedit.util.eventbus.Subscribe;
import com.skcraft.plume.common.event.lifecycle.PostInitializationEvent;
import com.skcraft.plume.common.util.module.AutoRegister;
import com.skcraft.plume.common.util.module.Modules;
import com.skcraft.plume.common.util.FatalError;

import java.util.Collection;
import java.util.Map;

import static com.google.common.base.Preconditions.checkNotNull;

@AutoRegister
@Singleton
public class ServiceFactory {

    private final ServiceLocator locator;
    private final Multimap<Class<?>, Class<?>> required = ArrayListMultimap.create();
    private boolean loaded = false;

    @Inject
    public ServiceFactory(ServiceLocator locator) {
        checkNotNull(locator, "locator");
        this.locator = locator;
    }

    @SuppressWarnings("unchecked")
    public <T> Service<T> create(Class<?> service, Class<?> requester) {
        synchronized (this) {
            if (!loaded) {
                required.put(service, requester);
            } else {
                throw new NoProviderExistsException(createMissingProviderMessage(service, Lists.newArrayList(requester)));
            }
        }
        return new Service<>(locator, (Class<T>) service);
    }

    @Subscribe
    public void onPostInitialization(PostInitializationEvent event) {
        synchronized (this) {
            if (!loaded) {
                loaded = true;
                for (Map.Entry<Class<?>, Collection<Class<?>>> entry : required.asMap().entrySet()) {
                    event.getFatalErrors().add(new FatalError(createMissingProviderMessage(entry.getKey(), entry.getValue())));
                }
                required.clear();
            }
        }
    }

    private String createMissingProviderMessage(Class<?> service, Collection<Class<?>> requesters) {
        StringBuilder builder = new StringBuilder();
        builder.append("The service '").append(service.getName()).append("' is required by:");
        for (Class<?> requester : requesters) {
            builder.append("\n\t").append(Modules.getModuleName(requester));
        }
        return builder.toString();
    }

}

@@ -1145,32 +1145,89 @@
 onized (this) %7B%0A
+            if (!locator.get(service).isPresent()) %7B%0A    
             if (
@@ -1229,32 +1229,36 @@
  if (!loaded) %7B%0A
+    
                 
@@ -1303,16 +1303,20 @@
         
+    
 %7D else %7B
@@ -1316,16 +1316,20 @@
  else %7B%0A
+    
         
@@ -1439,24 +1439,42 @@
 quester)));%0A
+                %7D%0A
             
@@ -1822,24 +1822,96 @@
 trySet()) %7B%0A
+                    if (!locator.get(entry.getKey()).isPresent()) %7B%0A    
             
@@ -2022,24 +2022,46 @@
 Value())));%0A
+                    %7D%0A
             

Fix service verification.