package info.u_team.u_team_core.util.annotation;

import java.lang.reflect.InvocationTargetException;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
import org.objectweb.asm.Type;

import info.u_team.u_team_core.api.construct.Construct;
import info.u_team.u_team_core.api.construct.IModConstruct;
import info.u_team.u_team_core.api.integration.IModIntegration;
import info.u_team.u_team_core.api.integration.Integration;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.loading.FMLEnvironment;
import net.minecraftforge.forgespi.language.ModFileScanData.AnnotationData;

public class AnnotationManager {
	
	private static final Logger LOGGER = LogManager.getLogger("AnnotationManager");
	private static final Marker CONSTRUCT_MARKER = MarkerManager.getMarker("Construct");
	private static final Marker INTEGRATION_MARKER = MarkerManager.getMarker("Integration");
	
	public static void callAnnotations(String modid) {
		callConstructs(modid);
		callIntegrations(modid);
	}
	
	public static void callConstructs(String modid) {
		for (final var data : AnnotationUtil.getAnnotations(modid, Type.getType(Construct.class))) {
			if (canBeCalled(modid, data)) {
				LOGGER.debug(CONSTRUCT_MARKER, "Load construct (" + data.memberName() + ") for mod " + modid);
				try {
					Class.forName(data.memberName()).asSubclass(IModConstruct.class).getConstructor().newInstance().construct();
				} catch (LinkageError | ClassNotFoundException | InstantiationException | IllegalAccessException | ClassCastException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException ex) {
					LOGGER.error(CONSTRUCT_MARKER, "Failed to load and call mod construct : {}", data.memberName(), ex);
					throw new RuntimeException(ex);
				}
			}
		}
	}
	
	public static void callIntegrations(String modid) {
		for (final var data : AnnotationUtil.getAnnotations(modid, Type.getType(Integration.class))) {
			final var integrationModid = (String) data.annotationData().get("integration");
			if (canBeCalled(modid, data) && ModList.get().isLoaded(integrationModid)) {
				LOGGER.debug(INTEGRATION_MARKER, "Load " + integrationModid + " integration (" + data.memberName() + ") for mod " + modid);
				try {
					Class.forName(data.memberName()).asSubclass(IModIntegration.class).getConstructor().newInstance().construct();
				} catch (LinkageError | ClassNotFoundException | InstantiationException | IllegalAccessException | ClassCastException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException ex) {
					LOGGER.error(INTEGRATION_MARKER, "Failed to load and call integration : {}", data.memberName(), ex);
					throw new RuntimeException(ex);
				}
			}
		}
	}
	
	private static boolean canBeCalled(String modid, AnnotationData data) {
		final var annotationModid = (String) data.annotationData().get("modid");
		final var client = (Boolean) data.annotationData().get("client");
		return modid.equals(annotationModid) && (client == null || !client || client && FMLEnvironment.dist == Dist.CLIENT);
	}
	
}

@@ -756,16 +756,149 @@
 nData;%0A%0A
+/**%0A * Manager for calling the classes that are annotated with %7B@link Construct%7D or %7B@link Integration%7D%0A * %0A * @author HyCraftHD%0A */%0A
 public c
@@ -1188,115 +1188,576 @@
 %0A%09%0A%09
-public static void callAnnotations(String modid) %7B%0A%09%09callConstructs(modid);%0A%09%09callIntegrations(modid);%0A%09%7D%0A%09
+/**%0A%09 * Tries to invoke %7B@link IModConstruct#construct()%7D and %7B@link IModIntegration#construct()%7D methods of classes that are%0A%09 * annotated with %7B@link Construct%7D or %7B@link Integration%7D.%0A%09 * %0A%09 * @param modid The modid that should be respected for calling%0A%09 */%0A%09public static void callAnnotations(String modid) %7B%0A%09%09callConstructs(modid);%0A%09%09callIntegrations(modid);%0A%09%7D%0A%09%0A%09/**%0A%09 * Tries to invoke all %7B@link IModConstruct#construct()%7D methods of classes that are annotated with %7B@link Construct%7D.%0A%09 * %0A%09 * @param modid The modid that should be respected for calling%0A%09 */
 %0A%09pu
@@ -2547,16 +2547,224 @@
 %09%7D%0A%09%7D%0A%09%0A
+%09/**%0A%09 * Tries to invoke all %7B@link IModIntegrationg#construct()%7D methods of classes that are annotated with%0A%09 * %7B@link Integration%7D.%0A%09 * %0A%09 * @param modid The modid that should be respected for calling%0A%09 */%0A
 %09public 
@@ -3711,16 +3711,286 @@
 %09%7D%0A%09%7D%0A%09%0A
+%09/**%0A%09 * Determines if an annotated class with the construct method can be called. Checks for the right modid and if the%0A%09 * environment matches.%0A%09 * %0A%09 * @param modid The modid%0A%09 * @param data Annotation data to check with%0A%09 * @return True if method can be called%0A%09 */%0A
 %09private

Document annotation manager