/*
 * Forge Mod Loader
 * Copyright (c) 2012-2013 cpw.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License v2.1
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 *
 * Contributors:
 *     cpw - implementation
 */

package cpw.mods.fml.common;

import java.io.File;
import java.util.regex.Pattern;

import org.objectweb.asm.Type;

import cpw.mods.fml.common.discovery.ModCandidate;
import cpw.mods.fml.common.discovery.asm.ASMModParser;
import cpw.mods.fml.common.discovery.asm.ModAnnotation;

public class ModContainerFactory
{
    private static Pattern modClass = Pattern.compile(".*(\\.|)(mod\\_[^\\s$]+)$");
    private static ModContainerFactory INSTANCE = new ModContainerFactory();
    public static ModContainerFactory instance() {
        return INSTANCE;
    }
    public ModContainer build(ASMModParser modParser, File modSource, ModCandidate container)
    {
        String className = modParser.getASMType().getClassName();
        if (modParser.isBaseMod(container.getRememberedBaseMods()) && modClass.matcher(className).find())
        {
            FMLLog.severe("Found a BaseMod type mod %s", className);
            FMLLog.severe("This will not be loaded and will be ignored. ModLoader mechanisms are no longer available.");
        }
        else if (modClass.matcher(className).find())
        {
            FMLLog.fine("Identified a class %s following modloader naming convention but not directly a BaseMod or currently seen subclass", className);
            container.rememberModCandidateType(modParser);
        }
        else if (modParser.isBaseMod(container.getRememberedBaseMods()))
        {
            FMLLog.fine("Found a basemod %s of non-standard naming format", className);
            container.rememberBaseModType(className);
        }

        for (ModAnnotation ann : modParser.getAnnotations())
        {
            if (ann.getASMType().equals(Type.getType(Mod.class)))
            {
                FMLLog.fine("Identified an FMLMod type mod %s", className);
                return new FMLModContainer(className, container, ann.getValues());
            }
        }

        return null;
    }
}

@@ -429,58 +429,239 @@
 ava.
-util.regex.Pattern;%0A%0Aimport org.objectweb.asm.Type
+lang.reflect.Constructor;%0Aimport java.util.Map;%0Aimport java.util.regex.Pattern;%0A%0Aimport org.apache.logging.log4j.Level;%0Aimport org.objectweb.asm.Type;%0A%0Aimport com.google.common.base.Throwables;%0Aimport com.google.common.collect.Maps
 ;%0A%0Ai
@@ -857,16 +857,111 @@
 ctory%0A%7B%0A
+    public static Map%3CType, Constructor%3C? extends ModContainer%3E%3E modTypes = Maps.newHashMap();%0A
     priv
@@ -1121,79 +1121,772 @@
     
-public static ModContainerFactory instance() %7B%0A        return INSTANCE;
+%0A    private ModContainerFactory() %7B%0A        // We always know about Mod type%0A        registerContainerType(Type.getType(Mod.class), FMLModContainer.class);%0A    %7D%0A    public static ModContainerFactory instance() %7B%0A        return INSTANCE;%0A    %7D%0A    %0A    public void registerContainerType(Type type, Class%3C? extends ModContainer%3E container)%0A    %7B%0A        try %7B%0A            Constructor%3C? extends ModContainer%3E constructor = container.getConstructor(new Class%3C?%3E%5B%5D %7B String.class, ModCandidate.class, Map.class %7D);%0A            modTypes.put(type, constructor);%0A        %7D catch (Exception e) %7B%0A            FMLLog.log(Level.ERROR, e, %22Critical error : cannot register mod container type %25s, it has an invalid constructor%22);%0A            Throwables.propagate(e);%0A        %7D
 %0A   
@@ -2982,54 +2982,44 @@
 if (
-ann.getASMType().equals(Type
+modTypes.containsKey(ann
 .get
+ASM
 Type(
-Mod.class
 )))%0A
@@ -3077,125 +3077,410 @@
 ed a
-n FMLMod type mod %25s%22, className);%0A                return new FMLModContainer(className, container, ann.getValues());
+ mod of type %25s (%25s) - loading%22, ann.getASMType(), className);%0A                try %7B%0A                    return modTypes.get(ann.getASMType()).newInstance(className, container, ann.getValues());%0A                %7D catch (Exception e) %7B%0A                    FMLLog.log(Level.ERROR, e, %22Unable to construct %25s container%22, ann.getASMType().getClassName());%0A                    return null;%0A                %7D
 %0A   

Allow injecting alternative container types. This is the core support code for allowing sponge plugins!