package openperipheral;

import java.util.Deque;
import java.util.List;
import java.util.Set;

import openmods.Log;
import openperipheral.api.ITypeConverter;
import openperipheral.api.ITypeConvertersRegistry;
import openperipheral.converter.*;

import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

@ApiSingleton
public class TypeConversionRegistry implements ITypeConvertersRegistry {

	public static final TypeConversionRegistry INSTANCE = new TypeConversionRegistry();

	private final Deque<ITypeConverter> converters = Lists.newLinkedList();

	private final Set<Class<?>> directlyIgnored = Sets.newHashSet();

	private final List<Class<?>> subclassIngored = Lists.newArrayList();

	@Override
	public void registerIgnored(Class<?> ignored, boolean includeSubclasses) {
		// I'm so cool!
		(includeSubclasses? subclassIngored : directlyIgnored).add(ignored);
	}

	private boolean isIgnored(Class<?> cls) {
		if (directlyIgnored.contains(cls)) return true;

		for (Class<?> ingored : subclassIngored)
			if (ingored.isAssignableFrom(cls)) return true;

		return false;
	}

	private TypeConversionRegistry() {
		converters.add(new ConverterGameProfile());
		converters.add(new ConverterFluidTankInfo());
		converters.add(new ConverterFluidTankInfo());
		converters.add(new ConverterItemStack());

		// DO NOT REORDER ANYTHING BELOW (unless you have good reason)
		converters.add(new ConverterArray());
		converters.add(new ConverterList());
		converters.add(new ConverterMap());
		converters.add(new ConverterSet());
		converters.add(new ConverterEnum());
		converters.add(new ConverterDefault());
		converters.add(new ConverterNumber());
		converters.add(new ConverterString());
	}

	@Override
	public void register(ITypeConverter converter) {
		Log.trace("Registering type converter %s", converter);
		converters.addFirst(converter);
	}

	@Override
	public Object fromLua(Object obj, Class<?> expected) {
		for (ITypeConverter converter : converters) {
			try {
				Object response = converter.fromLua(this, obj, expected);
				if (response != null) return response;
			} catch (Throwable e) {
				Log.warn(e, "Type converter %s failed", converter);
				throw Throwables.propagate(e);
			}
		}

		return null;
	}

	@Override
	public Object toLua(Object obj) {
		if (obj == null || isIgnored(obj.getClass())) return obj;

		for (ITypeConverter converter : converters) {
			try {
				Object response = converter.toLua(this, obj);
				if (response != null) return response;
			} catch (Throwable e) {
				Log.warn(e, "Type converter %s failed", converter);
				throw Throwables.propagate(e);
			}
		}

		// should never get here, since ConverterString is catch-all
		throw new IllegalStateException("Conversion failed on value " + obj);
	}
}

@@ -360,16 +360,65 @@
 .Sets;%0A%0A
+import dan200.computercraft.api.lua.ILuaObject;%0A%0A
 @ApiSing
@@ -1086,18 +1086,18 @@
 ass%3C?%3E i
-n
 g
+n
 ored : s
@@ -1120,18 +1120,18 @@
 %09%09%09if (i
-n
 g
+n
 ored.isA
@@ -1220,16 +1220,60 @@
 try() %7B%0A
+%09%09registerIgnored(ILuaObject.class, true);%0A%0A
 %09%09conver

Fix invalid ILuaObject conversion