package net.kencochrane.raven;

import net.kencochrane.raven.dsn.Dsn;

import java.util.Collection;
import java.util.LinkedList;
import java.util.ServiceLoader;

/**
 * Factory in charge of creating {@link Raven} instances.
 * <p>
 * The factories register themselves through the {@link ServiceLoader} system.
 * </p>
 */
public abstract class RavenFactory {
    private static final ServiceLoader<RavenFactory> AUTO_REGISTERED_FACTORIES = ServiceLoader.load(RavenFactory.class);
    private static final Collection<RavenFactory> MANUALLY_REGISTERED_FACTORIES = new LinkedList<RavenFactory>();

    public static void registerFactory(RavenFactory ravenFactory) {
        MANUALLY_REGISTERED_FACTORIES.add(ravenFactory);
    }

    public static Raven ravenInstance() {
        return ravenInstance(Dsn.dsnLookup());
    }

    public static Raven ravenInstance(String dsn) {
        return ravenInstance(new Dsn(dsn));
    }

    public static Raven ravenInstance(Dsn dsn) {
        for (RavenFactory ravenFactory : MANUALLY_REGISTERED_FACTORIES) {
            Raven raven = ravenFactory.createRavenInstance(dsn);
            if (raven != null) {
                return raven;
            }
        }

        for (RavenFactory ravenFactory : AUTO_REGISTERED_FACTORIES) {
            Raven raven = ravenFactory.createRavenInstance(dsn);
            if (raven != null) {
                return raven;
            }
        }

        throw new IllegalStateException("Couldn't create a raven instance for '" + dsn + "'");
    }

    public static Raven ravenInstance(Dsn dsn, String ravenFactoryName) {
        if (ravenFactoryName == null)
            return ravenInstance(dsn);

        for (RavenFactory ravenFactory : MANUALLY_REGISTERED_FACTORIES) {
            if (!ravenFactoryName.equals(ravenFactory.getClass().getName()))
                continue;

            Raven raven = ravenFactory.createRavenInstance(dsn);
            if (raven != null) {
                return raven;
            }
        }

        for (RavenFactory ravenFactory : AUTO_REGISTERED_FACTORIES) {
            if (!ravenFactoryName.equals(ravenFactory.getClass().getName()))
                continue;

            Raven raven = ravenFactory.createRavenInstance(dsn);
            if (raven != null) {
                return raven;
            }
        }

        throw new IllegalStateException("Couldn't create a raven instance for '" + dsn + "'");
    }

    protected abstract Raven createRavenInstance(Dsn dsn);
}

@@ -980,542 +980,38 @@
     
-for (RavenFactory ravenFactory : MANUALLY_REGISTERED_FACTORIES) %7B%0A            Raven raven = ravenFactory.createRavenInstance(dsn);%0A            if (raven != null) %7B%0A                return raven;%0A            %7D%0A        %7D%0A%0A        for (RavenFactory ravenFactory : AUTO_REGISTERED_FACTORIES) %7B%0A            Raven raven = ravenFactory.createRavenInstance(dsn);%0A            if (raven != null) %7B%0A                return raven;%0A            %7D%0A        %7D%0A%0A        throw new IllegalStateException(%22Couldn't create a raven instance for '%22 + dsn + %22'%22
+return ravenInstance(dsn, null
 );%0A 
@@ -1094,86 +1094,8 @@
 ) %7B%0A
-        if (ravenFactoryName == null)%0A            return ravenInstance(dsn);%0A%0A
     
@@ -1172,32 +1172,60 @@
             if (
+ravenFactoryName != null && 
 !ravenFactoryNam
@@ -1535,16 +1535,44 @@
     if (
+ravenFactoryName != null && 
 !ravenFa

Deduplicate the ravenFactory code to generate instances