package protocolsupport.injector;

import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.Map;

import org.bukkit.Bukkit;

import net.minecraft.server.v1_11_R1.Block;
import net.minecraft.server.v1_11_R1.Blocks;
import net.minecraft.server.v1_11_R1.IBlockData;
import net.minecraft.server.v1_11_R1.Item;
import net.minecraft.server.v1_11_R1.ItemAnvil;
import net.minecraft.server.v1_11_R1.ItemBlock;
import net.minecraft.server.v1_11_R1.ItemWaterLily;
import net.minecraft.server.v1_11_R1.MinecraftKey;
import net.minecraft.server.v1_11_R1.TileEntity;
import protocolsupport.server.block.BlockAnvil;
import protocolsupport.server.block.BlockEnchantTable;
import protocolsupport.server.block.BlockWaterLily;
import protocolsupport.server.tileentity.TileEntityEnchantTable;
import protocolsupport.utils.ReflectionUtils;

public class ServerInjector {

	public static void inject() throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
		registerTileEntity(TileEntityEnchantTable.class, "EnchantTable");
		registerBlock(116, "enchanting_table", new BlockEnchantTable());
		ItemBlock itemanvil = new ItemAnvil(new BlockAnvil());
		itemanvil.c("anvil");
		registerBlock(145, "anvil", itemanvil);
		registerBlock(111, "waterlily", new ItemWaterLily(new BlockWaterLily()));
		fixBlocksRefs();
		Bukkit.resetRecipes();
	}

	@SuppressWarnings("unchecked")
	private static void registerTileEntity(Class<? extends TileEntity> entityClass, String name) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
		((Map<String, Class<? extends TileEntity>>) ReflectionUtils.setAccessible(TileEntity.class.getDeclaredField("f")).get(null)).put(name, entityClass);
		((Map<Class<? extends TileEntity>, String>) ReflectionUtils.setAccessible(TileEntity.class.getDeclaredField("g")).get(null)).put(entityClass, name);
	}

	private static void registerBlock(int id, String name, Block block) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
		registerBlock(id, name, new ItemBlock(block));
	}

	@SuppressWarnings("unchecked")
	private static void registerBlock(int id, String name, ItemBlock itemblock) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
		MinecraftKey stringkey = new MinecraftKey(name);
		Block block = itemblock.getBlock();
		Block.REGISTRY.a(id, stringkey, block);
		Iterator<IBlockData> blockdataiterator = block.s().a().iterator();
		while (blockdataiterator.hasNext()) {
			IBlockData blockdata = blockdataiterator.next();
			final int stateId = (id << 4) | block.toLegacyData(blockdata);
			Block.REGISTRY_ID.a(blockdata, stateId);
		}
		Item.REGISTRY.a(id, stringkey, itemblock);
		((Map<Block, Item>) ReflectionUtils.setAccessible(Item.class.getDeclaredField("a")).get(null)).put(block, itemblock);
	}

	private static void fixBlocksRefs() throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
		for (Field field : Blocks.class.getDeclaredFields()) {
			field.setAccessible(true);
			if (Block.class.isAssignableFrom(field.getType())) {
				Block block = (Block) field.get(null);
				Block newblock = Block.getById(Block.getId(block));
				if (block != newblock) {
					Iterator<IBlockData> blockdataiterator = block.s().a().iterator();
					while (blockdataiterator.hasNext()) {
						IBlockData blockdata = blockdataiterator.next();
						ReflectionUtils.getField(blockdata.getClass(), "a").set(blockdata, block);
					}
					ReflectionUtils.setStaticFinalField(field, newblock);
				}
			}
		}
	}

}

@@ -517,16 +517,72 @@
 aftKey;%0A
+import net.minecraft.server.v1_11_R1.RegistryMaterials;%0A
 import n
@@ -1661,165 +1661,113 @@
 %7B%0A%09%09
-((Map%3CString, Class%3C? extends TileEntity%3E%3E) ReflectionUtils.setAccessible(TileEntity.class.getDeclaredField(%22f%22)).get(null)).put(name, entityClass);%0A%09%09((Map%3C
+RegistryMaterials%3CMinecraftKey, Class%3C? extends TileEntity%3E%3E registry = (RegistryMaterials%3CMinecraftKey, 
 Clas
@@ -1789,24 +1789,16 @@
 eEntity%3E
-, String
 %3E) Refle
@@ -1808,29 +1808,24 @@
 onUtils.
-setAccessible
+getField
 (TileEnt
@@ -1837,47 +1837,63 @@
 lass
-.getDeclaredField(%22g%22)).get(null)).put(
+, %22f%22).get(null);%0A%09%09registry.a(new MinecraftKey(name), 
 enti
@@ -1899,22 +1899,16 @@
 ityClass
-, name
 );%0A%09%7D%0A%0A%09

Fix tile entity injection