package common.init;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import common.block.artificial.BlockBed;
import common.block.artificial.BlockCarpet;
import common.block.artificial.BlockStainedGlass;
import common.block.artificial.BlockStainedGlassPane;
import common.block.artificial.BlockWool;
import common.block.natural.BlockColoredClay;
import common.collect.Lists;
import common.collect.Maps;
import common.color.DyeColor;
import common.entity.animal.EntitySheep;
import common.inventory.InventoryCrafting;
import common.item.Item;
import common.item.ItemStack;
import common.item.block.ItemBanner;
import common.item.material.ItemDye;
import common.item.tool.ItemArmor;
import common.tags.TagObject;
import common.tileentity.TileEntityBanner;
import common.world.World;

public abstract class CraftingRegistry
{
    private static final String[][] TOOLS = new String[][] {
    	{"XXX", " # ", " # "}, {"X", "#", "#"}, {"XX", "X#", " #"}, {"XX", " #", " #"}
    };
    private static final String[][] WEAPONS = new String[][] {{"X", "X", "#"}};
    private static final String[][] ARMOR = new String[][] {
    	{"XXX", "X X"}, {"X X", "XXX", "XXX"}, {"XXX", "X X", "X X"}, {"X X", "X X"}
    };
    private static final Object[][] COMPRESSED = new Object[][] {
    	{Items.emerald_block, new ItemStack(Items.emerald, 9)}, 
    	{Items.lapis_block, new ItemStack(Items.lapis_lazuli, 9)}, 
    	{Items.redstone_block, new ItemStack(Items.redstone, 9)}, 
    	{Items.coal_block, new ItemStack(Items.coal, 9)}, 
    	{Items.hay_block, new ItemStack(Items.wheats, 9)}, 
    	{Items.slime_block, new ItemStack(Items.slime_ball, 9)}
    };
    
    private static final List<IRecipe> recipes = Lists.<IRecipe>newArrayList();
    private static final List<IRecipe> base = Lists.<IRecipe>newArrayList();

    static void register()
    {
        for(OreType ore : OreType.values()) {
        	Item item = ItemRegistry.getRegisteredItem(ore.item);
        	ore.material.addRepairItem(item);
        	if(ore.material.hasTools()) {
	        	add(new ItemStack(ItemRegistry.getRegisteredItem(ore.name + "_pickaxe")), TOOLS[0], '#', Items.stick, 'X', item);
	        	add(new ItemStack(ItemRegistry.getRegisteredItem(ore.name + "_shovel")), TOOLS[1], '#', Items.stick, 'X', item);
	        	add(new ItemStack(ItemRegistry.getRegisteredItem(ore.name + "_axe")), TOOLS[2], '#', Items.stick, 'X', item);
	        	add(new ItemStack(ItemRegistry.getRegisteredItem(ore.name + "_hoe")), TOOLS[3], '#', Items.stick, 'X', item);
        	}
        	if(ore.material.hasExtras()) {
	        	add(new ItemStack(ItemRegistry.getRegisteredItem(ore.name + "_shears")), " #", "# ", '#', item);
        	}
        	if(ore.material.hasWeapons()) {
	        	add(new ItemStack(ItemRegistry.getRegisteredItem(ore.name + "_sword")), WEAPONS[0], '#', Items.stick, 'X', item);
        	}
        	if(ore.material.hasArmor()) {
	            add(new ItemStack(ItemRegistry.getRegisteredItem(ore.name + "_helmet")), ARMOR[0], 'X', item);
	            add(new ItemStack(ItemRegistry.getRegisteredItem(ore.name + "_chestplate")), ARMOR[1], 'X', item);
	            add(new ItemStack(ItemRegistry.getRegisteredItem(ore.name + "_leggings")), ARMOR[2], 'X', item);
	            add(new ItemStack(ItemRegistry.getRegisteredItem(ore.name + "_boots")), ARMOR[3], 'X', item);
        	}
        	Item block = ItemRegistry.getRegisteredItem(ore.name + "_block");
        	add(new ItemStack(block), "###", "###", "###", '#', item);
            add(new ItemStack(item, 9), "#", '#', block);
        }
        for(MetalType metal : MetalType.values()) {
        	Item item = ItemRegistry.getRegisteredItem(metal.isPowder ? (metal.name + "_powder") : (metal.name + "_ingot"));
        	if(metal.material != null)
        		metal.material.addRepairItem(item);
        	if(metal.material != null && metal.material.hasTools()) {
	        	add(new ItemStack(ItemRegistry.getRegisteredItem(metal.name + "_pickaxe")), TOOLS[0], '#', Items.stick, 'X', item);
	        	add(new ItemStack(ItemRegistry.getRegisteredItem(metal.name + "_shovel")), TOOLS[1], '#', Items.stick, 'X', item);
	        	add(new ItemStack(ItemRegistry.getRegisteredItem(metal.name + "_axe")), TOOLS[2], '#', Items.stick, 'X', item);
	        	add(new ItemStack(ItemRegistry.getRegisteredItem(metal.name + "_hoe")), TOOLS[3], '#', Items.stick, 'X', item);
        	}
        	if(metal.material != null && metal.material.hasExtras()) {
	        	add(new ItemStack(ItemRegistry.getRegisteredItem(metal.name + "_shears")), " #", "# ", '#', item);
        	}
        	if(metal.material != null && metal.material.hasWeapons()) {
	        	add(new ItemStack(ItemRegistry.getRegisteredItem(metal.name + "_sword")), WEAPONS[0], '#', Items.stick, 'X', item);
        	}
        	if(metal.material != null && metal.material.hasArmor()) {
	            add(new ItemStack(ItemRegistry.getRegisteredItem(metal.name + "_helmet")), ARMOR[0], 'X', item);
	            add(new ItemStack(ItemRegistry.getRegisteredItem(metal.name + "_chestplate")), ARMOR[1], 'X', item);
	            add(new ItemStack(ItemRegistry.getRegisteredItem(metal.name + "_leggings")), ARMOR[2], 'X', item);
	            add(new ItemStack(ItemRegistry.getRegisteredItem(metal.name + "_boots")), ARMOR[3], 'X', item);
        	}
        	Item block = ItemRegistry.getRegisteredItem(metal.name + "_block");
        	add(new ItemStack(block), "###", "###", "###", '#', item);
            add(new ItemStack(item, 9), "#", '#', block);
        }
        for(ToolType tool : ToolType.values()) {
        	for(String itm : tool.items) {
	        	Item item = ItemRegistry.getRegisteredItem(itm);
	        	tool.material.addRepairItem(item);
	        	if(tool.material.hasTools()) {
		        	add(new ItemStack(ItemRegistry.getRegisteredItem(tool.name + "_pickaxe")), TOOLS[0], '#', Items.stick, 'X', item);
		        	add(new ItemStack(ItemRegistry.getRegisteredItem(tool.name + "_shovel")), TOOLS[1], '#', Items.stick, 'X', item);
		        	add(new ItemStack(ItemRegistry.getRegisteredItem(tool.name + "_axe")), TOOLS[2], '#', Items.stick, 'X', item);
		        	add(new ItemStack(ItemRegistry.getRegisteredItem(tool.name + "_hoe")), TOOLS[3], '#', Items.stick, 'X', item);
	        	}
	        	if(tool.material.hasExtras()) {
		        	add(new ItemStack(ItemRegistry.getRegisteredItem(tool.name + "_shears")), " #", "# ", '#', item);
	        	}
	        	if(tool.material.hasWeapons()) {
		        	add(new ItemStack(ItemRegistry.getRegisteredItem(tool.name + "_sword")), WEAPONS[0], '#', Items.stick, 'X', item);
	        	}
	        	if(tool.material.hasArmor()) {
		            add(new ItemStack(ItemRegistry.getRegisteredItem(tool.name + "_helmet")), ARMOR[0], 'X', item);
		            add(new ItemStack(ItemRegistry.getRegisteredItem(tool.name + "_chestplate")), ARMOR[1], 'X', item);
		            add(new ItemStack(ItemRegistry.getRegisteredItem(tool.name + "_leggings")), ARMOR[2], 'X', item);
		            add(new ItemStack(ItemRegistry.getRegisteredItem(tool.name + "_boots")), ARMOR[3], 'X', item);
	        	}
        	}
        }
        
        add(new ItemStack(Items.bow, 1), " #X", "# X", " #X", 'X', Items.string, '#', Items.stick);
        add(new ItemStack(Items.arrow, 4), "X", "#", "Y", 'Y', Items.feather, 'X', Items.flint, '#', Items.stick);
        
        for (int i = 0; i < COMPRESSED.length; ++i)
        {
            Item block = (Item)COMPRESSED[i][0];
            ItemStack itemstack = (ItemStack)COMPRESSED[i][1];
            add(new ItemStack(block), "###", "###", "###", '#', itemstack);
            add(itemstack, "#", '#', block);
        }

        add(new ItemStack(Items.gold_ingot), "###", "###", "###", '#', Items.gold_nugget);
        add(new ItemStack(Items.gold_nugget, 9), "#", '#', Items.gold_ingot);
        
        addShapeless(new ItemStack(Items.mushroom_stew), Items.brown_mushroom, Items.red_mushroom, Items.bowl);
        add(new ItemStack(Items.cookie, 8), "#X#", 'X', Items.cocoa, '#', Items.wheats);
        add(new ItemStack(Items.melon_block), "MMM", "MMM", "MMM", 'M', Items.melon);
        add(new ItemStack(Items.melon_stem), "M", 'M', Items.melon);
        add(new ItemStack(Items.pumpkin_stem, 4), "M", 'M', Items.pumpkin);
        addShapeless(new ItemStack(Items.pumpkin_pie), Items.pumpkin, Items.sugar, Items.egg);
        addShapeless(new ItemStack(Items.fermented_spider_eye), Items.spider_eye, Items.brown_mushroom, Items.sugar);
        addShapeless(new ItemStack(Items.blazing_powder, 2), Items.blaze_rod);
        addShapeless(new ItemStack(Items.magma_cream), Items.blazing_powder, Items.slime_ball);
        
        add(new ItemStack(Items.trapped_chest), "#-", '#', Items.chest, '-', Items.tripwire_hook);
        add(new ItemStack(Items.warp_chest), "###", "#E#", "###", '#', Items.obsidian, 'E', Items.charged_orb);
        add(new ItemStack(Items.furnace), "###", "# #", "###", '#', Items.cobblestone);
        add(new ItemStack(Items.sandstone), "##", "##", '#', Items.sand);
        add(new ItemStack(Items.smooth_sandstone, 4), "##", "##", '#', Items.sandstone);
        add(new ItemStack(Items.quartz_pillar, 2), "#", "#", '#', Items.quartz_block);
        add(new ItemStack(Items.stonebrick, 4), "##", "##", '#', Items.stone);
        addShapeless(new ItemStack(Items.mossy_stonebrick), Items.stonebrick, Items.vine);
        addShapeless(new ItemStack(Items.mossy_cobblestone), Items.cobblestone, Items.vine);
        add(new ItemStack(Items.iron_bars, 16), "###", "###", '#', Items.iron_ingot);
        add(new ItemStack(Items.glass_pane, 16), "###", "###", '#', Items.glass);
        add(new ItemStack(Items.redstone_lamp, 1), " R ", "RGR", " R ", 'R', Items.redstone, 'G', Items.glowstone);
        add(new ItemStack(Items.beacon, 1), "GGG", "GSG", "OOO", 'G', Items.glass, 'S', Items.charge_crystal, 'O', Items.obsidian);
        add(new ItemStack(Items.blood_brick, 1), "NN", "NN", 'N', Items.bloodbrick);
        add(new ItemStack(Items.coarse_dirt, 4), "DG", "GD", 'D', Items.dirt, 'G', Items.gravel);

        add(new ItemStack(Items.lamp, 1), " R ", "RGR", " R ", 'R', Items.glass, 'G', Items.glowstone);
        
        for (DyeColor color : DyeColor.values())
        {
        	ItemDye dye = ItemDye.getByColor(color);
        	if(color != DyeColor.WHITE)
        		addShapeless(new ItemStack(BlockWool.getByColor(color).getItem()), dye, Items.white_wool);
            add(new ItemStack(BlockColoredClay.getByColor(color).getItem(), 8), "###", "#X#", "###", '#', Items.hardened_clay, 'X', dye);
            add(new ItemStack(BlockStainedGlass.getByColor(color).getItem(), 8), "###", "#X#", "###", '#', Items.glass, 'X', dye);
            add(new ItemStack(BlockStainedGlassPane.getByColor(color).getItem(), 16), "###", "###", '#', BlockStainedGlass.getByColor(color).getItem());
        }

        addShapeless(new ItemStack(ItemDye.getByColor(DyeColor.YELLOW)), Items.dandelion);
        addShapeless(new ItemStack(ItemDye.getByColor(DyeColor.RED)), Items.rose);
        addShapeless(new ItemStack(ItemDye.getByColor(DyeColor.RED)), Items.poppy);
        addShapeless(new ItemStack(ItemDye.getByColor(DyeColor.WHITE), 3), Items.bone);
        addShapeless(new ItemStack(ItemDye.getByColor(DyeColor.PINK), 2), new ItemStack(ItemDye.getByColor(DyeColor.RED)), new ItemStack(ItemDye.getByColor(DyeColor.WHITE)));
        addShapeless(new ItemStack(ItemDye.getByColor(DyeColor.ORANGE), 2), new ItemStack(ItemDye.getByColor(DyeColor.RED)), new ItemStack(ItemDye.getByColor(DyeColor.YELLOW)));
        addShapeless(new ItemStack(ItemDye.getByColor(DyeColor.LIME), 2), new ItemStack(ItemDye.getByColor(DyeColor.GREEN)), new ItemStack(ItemDye.getByColor(DyeColor.WHITE)));
        addShapeless(new ItemStack(ItemDye.getByColor(DyeColor.GRAY), 2), new ItemStack(ItemDye.getByColor(DyeColor.BLACK)), new ItemStack(ItemDye.getByColor(DyeColor.WHITE)));
        addShapeless(new ItemStack(ItemDye.getByColor(DyeColor.SILVER), 2), new ItemStack(ItemDye.getByColor(DyeColor.GRAY)), new ItemStack(ItemDye.getByColor(DyeColor.WHITE)));
        addShapeless(new ItemStack(ItemDye.getByColor(DyeColor.SILVER), 3), new ItemStack(ItemDye.getByColor(DyeColor.BLACK)), new ItemStack(ItemDye.getByColor(DyeColor.WHITE)), new ItemStack(ItemDye.getByColor(DyeColor.WHITE)));
        addShapeless(new ItemStack(ItemDye.getByColor(DyeColor.LIGHT_BLUE), 2), new ItemStack(ItemDye.getByColor(DyeColor.BLUE)), new ItemStack(ItemDye.getByColor(DyeColor.WHITE)));
        addShapeless(new ItemStack(ItemDye.getByColor(DyeColor.CYAN), 2), new ItemStack(ItemDye.getByColor(DyeColor.BLUE)), new ItemStack(ItemDye.getByColor(DyeColor.GREEN)));
        addShapeless(new ItemStack(ItemDye.getByColor(DyeColor.PURPLE), 2), new ItemStack(ItemDye.getByColor(DyeColor.BLUE)), new ItemStack(ItemDye.getByColor(DyeColor.RED)));
        addShapeless(new ItemStack(ItemDye.getByColor(DyeColor.MAGENTA), 2), new ItemStack(ItemDye.getByColor(DyeColor.PURPLE)), new ItemStack(ItemDye.getByColor(DyeColor.PINK)));
        addShapeless(new ItemStack(ItemDye.getByColor(DyeColor.MAGENTA), 3), new ItemStack(ItemDye.getByColor(DyeColor.BLUE)), new ItemStack(ItemDye.getByColor(DyeColor.RED)), new ItemStack(ItemDye.getByColor(DyeColor.PINK)));
        addShapeless(new ItemStack(ItemDye.getByColor(DyeColor.MAGENTA), 4), new ItemStack(ItemDye.getByColor(DyeColor.BLUE)), new ItemStack(ItemDye.getByColor(DyeColor.RED)), new ItemStack(ItemDye.getByColor(DyeColor.RED)), new ItemStack(ItemDye.getByColor(DyeColor.WHITE)));
        addShapeless(new ItemStack(ItemDye.getByColor(DyeColor.LIGHT_BLUE)), Items.blue_orchid);
        addShapeless(new ItemStack(ItemDye.getByColor(DyeColor.MAGENTA)), Items.allium);
        addShapeless(new ItemStack(ItemDye.getByColor(DyeColor.SILVER)), Items.houstonia);
        addShapeless(new ItemStack(ItemDye.getByColor(DyeColor.RED)), Items.red_tulip);
        addShapeless(new ItemStack(ItemDye.getByColor(DyeColor.ORANGE)), Items.orange_tulip);
        addShapeless(new ItemStack(ItemDye.getByColor(DyeColor.SILVER)), Items.white_tulip);
        addShapeless(new ItemStack(ItemDye.getByColor(DyeColor.PINK)), Items.pink_tulip);
        addShapeless(new ItemStack(ItemDye.getByColor(DyeColor.SILVER)), Items.daisy);
        addShapeless(new ItemStack(ItemDye.getByColor(DyeColor.YELLOW), 2), Items.sunflower);
        addShapeless(new ItemStack(ItemDye.getByColor(DyeColor.MAGENTA), 2), Items.syringa);
        addShapeless(new ItemStack(ItemDye.getByColor(DyeColor.RED), 2), Items.rose_bush);
        addShapeless(new ItemStack(ItemDye.getByColor(DyeColor.PINK), 2), Items.paeonia);

        for (DyeColor color : DyeColor.values())
        {
            add(new ItemStack(BlockCarpet.getByColor(color).getItem(), 3), "##", '#', BlockWool.getByColor(color).getItem());
        }
        
        recipes.add(new RecipesArmorDyes());
        recipes.add(new RecipeFireworks());
        recipes.add(new RecipeRepairItem());
        
        for (DyeColor color : DyeColor.values())
        {
            add(ItemBanner.getColoredBanner(color), "###", "###", " | ", '#', BlockWool.getByColor(color).getItem(), '|', Items.stick);
        }

        recipes.add(new RecipeDuplicatePattern());
        recipes.add(new RecipeAddPattern());
        
        add(new ItemStack(Items.paper, 3), "###", '#', Items.reeds);
        addShapeless(new ItemStack(Items.book, 1), Items.paper, Items.paper, Items.paper, Items.leather);
        addShapeless(new ItemStack(Items.writable_book, 1), Items.book, Items.ink_sack, Items.feather);
        for(WoodType wood : WoodType.values()) {
        	Item planks = ItemRegistry.getRegisteredItem(wood.getName() + "_planks");
	        add(new ItemStack(ItemRegistry.getRegisteredItem(wood.getName() + "_fence"), 3), "W#W", "W#W", '#', Items.stick, 'W', planks);
	        add(new ItemStack(ItemRegistry.getRegisteredItem(wood.getName() + "_fence_gate"), 1), "#W#", "#W#", '#', Items.stick, 'W', planks);
	        add(new ItemStack(ItemRegistry.getRegisteredItem(wood.getName() + "_door"), 3), "##", "##", "##", '#', planks);
	        addBasic(new ItemStack(planks, 4), "#", '#', ItemRegistry.getRegisteredItem(wood.getName() + "_log"));
	        Item slab = ItemRegistry.getRegisteredItem(wood.getName() + "_slab");
	        add(new ItemStack(slab, 6), "###", '#', planks);
	        add(new ItemStack(ItemRegistry.getRegisteredItem(wood.getName() + "_stairs"), 4), "#  ", "## ", "###", '#', planks);
	        add(new ItemStack(Items.daylight_detector), "GGG", "QQQ", "WWW", 'G', Items.glass, 'Q', Items.quartz, 'W', slab);
	        
	        add(new ItemStack(Items.chest), "###", "# #", "###", '#', planks);
	        addBasic(new ItemStack(Items.workbench), "##", "##", '#', planks);
	        add(new ItemStack(Items.assembly_unit), "----", "XXXX", "X##X", '#', Items.construction_table, '-', Items.titanium_ingot, 'X', planks);
	        

	        add(new ItemStack(Items.jukebox, 1), "###", "#X#", "###", '#', planks, 'X', Items.diamond);
	        add(new ItemStack(Items.noteblock, 1), "###", "#X#", "###", '#', planks, 'X', Items.redstone);
	        add(new ItemStack(Items.bookshelf, 1), "###", "XXX", "###", '#', planks, 'X', Items.book);
	        add(new ItemStack(Items.trapdoor, 2), "###", "###", '#', planks);
	        add(new ItemStack(Items.sign, 3), "###", "###", " X ", '#', planks, 'X', Items.stick);
	        add(new ItemStack(Items.stick, 4), "#", "#", '#', planks);
	        add(new ItemStack(Items.bowl, 4), "# #", " # ", '#', planks);
	        add(new ItemStack(Items.boat, 1), "# #", "###", '#', planks);
	        add(new ItemStack(Items.tripwire_hook, 2), "I", "S", "#", '#', planks, 'S', Items.stick, 'I', Items.iron_ingot);
	        add(new ItemStack(Items.wooden_button, 1), "#", '#', planks);
	        add(new ItemStack(Items.wooden_pressure_plate, 1), "##", '#', planks);
	        add(new ItemStack(Items.piston, 1), "TTT", "#X#", "#R#", '#', Items.cobblestone, 'X', Items.iron_ingot, 'R', Items.redstone, 'T', planks);
	        for(DyeColor color : BlockBed.COLORS) {
	        	add(new ItemStack(ItemRegistry.getRegisteredItem(color.getName() + "_bed"), 1), "###", "XXX", '#', BlockWool.getByColor(color).getItem(), 'X', planks);
	        }
        }

        add(new ItemStack(Items.cobblestone_wall, 6), "###", "###", '#', Items.cobblestone);
        add(new ItemStack(Items.mossy_cobblestone_wall, 6), "###", "###", '#', Items.mossy_cobblestone);
        add(new ItemStack(Items.blood_brick_fence, 6), "###", "###", '#', Items.blood_brick);
        
        add(new ItemStack(Items.lead, 2), "~~ ", "~O ", "  ~", '~', Items.string, 'O', Items.slime_ball);
        add(new ItemStack(Items.snow, 1), "##", "##", '#', Items.snowball);
        add(new ItemStack(Items.snow_layer, 6), "###", '#', Items.snow);
        add(new ItemStack(Items.clay, 1), "##", "##", '#', Items.clay_ball);
        add(new ItemStack(Items.brick_block, 1), "##", "##", '#', Items.brick);
        add(new ItemStack(Items.glowstone, 1), "##", "##", '#', Items.glowstone_dust);
        add(new ItemStack(Items.quartz_block, 1), "##", "##", '#', Items.quartz);
        add(new ItemStack(Items.white_wool, 1), "##", "##", '#', Items.string);
        add(new ItemStack(Items.tnt, 1), "X#X", "#X#", "X#X", 'X', Items.gunpowder, '#', Items.sand);

        add(new ItemStack(Items.tnt_1), "X#X", "#X#", "X#X", 'X', Items.gunpowder, '#', Items.tnt);
        add(new ItemStack(Items.tnt_2), "##", "##", '#', Items.tnt_1);
        addShapeless(new ItemStack(Items.tnt_3), Items.tnt_2, Items.tnt_2);
        addShapeless(new ItemStack(Items.tnt_4), Items.tnt_3, Items.tnt_3);
        addShapeless(new ItemStack(Items.tnt_5), Items.tnt_4, Items.tnt_4);
        addShapeless(new ItemStack(Items.tnt_6), Items.tnt_5, Items.tnt_5);
        addShapeless(new ItemStack(Items.tnt_7), Items.tnt_6, Items.tnt_6);
        add(new ItemStack(Items.nuke, 1), "###", "###", "###", '#', Items.tnt_7);
        
        add(new ItemStack(Items.ladder, 3), "# #", "###", "# #", '#', Items.stick);
        
        add(new ItemStack(Items.iron_door, 3), "##", "##", "##", '#', Items.iron_ingot);
        add(new ItemStack(Items.iron_trapdoor, 1), "##", "##", '#', Items.iron_ingot);
        add(new ItemStack(Items.cake, 1), "AAA", "BEB", "CCC", 'A', Items.milk_bucket, 'B', Items.sugar, 'C', Items.wheats, 'E', Items.egg);
        add(new ItemStack(Items.sugar, 1), "#", '#', Items.reeds);
        
        add(new ItemStack(Items.torch, 4), "X", "#", 'X', Items.coal, '#', Items.stick);
        add(new ItemStack(Items.torch, 4), "X", "#", 'X', Items.charcoal, '#', Items.stick);
        add(new ItemStack(Items.glass_bottle, 3), "# #", " # ", '#', Items.glass);
        add(new ItemStack(Items.rail, 16), "X X", "X#X", "X X", 'X', Items.iron_ingot, '#', Items.stick);
        add(new ItemStack(Items.golden_rail, 6), "X X", "X#X", "XRX", 'X', Items.gold_ingot, 'R', Items.redstone, '#', Items.stick);
        add(new ItemStack(Items.activator_rail, 6), "XSX", "X#X", "XSX", 'X', Items.iron_ingot, '#', Items.redstone_torch, 'S', Items.stick);
        add(new ItemStack(Items.detector_rail, 6), "X X", "X#X", "XRX", 'X', Items.iron_ingot, 'R', Items.redstone, '#', Items.stone_pressure_plate);
        add(new ItemStack(Items.minecart, 1), "# #", "###", '#', Items.iron_ingot);
        add(new ItemStack(Items.cauldron, 1), "# #", "# #", "###", '#', Items.iron_ingot);
        add(new ItemStack(Items.brewing_stand, 1), " B ", "###", '#', Items.cobblestone, 'B', Items.blaze_rod);
        add(new ItemStack(Items.lit_pumpkin, 1), "A", "B", 'A', Items.pumpkin, 'B', Items.torch);
        add(new ItemStack(Items.chest_minecart, 1), "A", "B", 'A', Items.chest, 'B', Items.minecart);
        add(new ItemStack(Items.tnt_minecart, 1), "A", "B", 'A', Items.tnt, 'B', Items.minecart);
        add(new ItemStack(Items.hopper_minecart, 1), "A", "B", 'A', Items.hopper, 'B', Items.minecart);
        add(new ItemStack(Items.bucket, 1), "# #", " # ", '#', Items.iron_ingot);
        add(new ItemStack(Items.flowerpot, 1), "# #", " # ", '#', Items.brick);
        addShapeless(new ItemStack(Items.flint_and_steel, 1), new ItemStack(Items.iron_ingot, 1), new ItemStack(Items.flint, 1));
        add(new ItemStack(Items.bread, 1), "###", '#', Items.wheats);
        
        add(new ItemStack(Items.fishing_rod, 1), "  #", " #X", "# X", '#', Items.stick, 'X', Items.string);
        add(new ItemStack(Items.carrot_on_a_stick, 1), "# ", " X", '#', Items.fishing_rod, 'X', Items.carrot);
        add(new ItemStack(Items.cobblestone_stairs, 4), "#  ", "## ", "###", '#', Items.cobblestone);
        add(new ItemStack(Items.brick_stairs, 4), "#  ", "## ", "###", '#', Items.brick_block);
        add(new ItemStack(Items.stonebrick_stairs, 4), "#  ", "## ", "###", '#', Items.stonebrick);
        add(new ItemStack(Items.blood_brick_stairs, 4), "#  ", "## ", "###", '#', Items.blood_brick);
        add(new ItemStack(Items.sandstone_stairs, 4), "#  ", "## ", "###", '#', Items.sandstone);
        add(new ItemStack(Items.quartz_stairs, 4), "#  ", "## ", "###", '#', Items.quartz_block);
        add(new ItemStack(Items.golden_apple, 1), "###", "#X#", "###", '#', Items.gold_ingot, 'X', Items.apple);
        add(new ItemStack(Items.charged_apple, 1), "###", "#X#", "###", '#', Items.gold_block, 'X', Items.apple);
        add(new ItemStack(Items.golden_carrot, 1), "###", "#X#", "###", '#', Items.gold_nugget, 'X', Items.carrot);
        add(new ItemStack(Items.speckled_melon, 1), "###", "#X#", "###", '#', Items.gold_nugget, 'X', Items.melon);
        add(new ItemStack(Items.lever, 1), "X", "#", '#', Items.cobblestone, 'X', Items.stick);
        add(new ItemStack(Items.redstone_torch, 1), "X", "#", '#', Items.stick, 'X', Items.redstone);
        add(new ItemStack(Items.repeater, 1), "#X#", "III", '#', Items.redstone_torch, 'X', Items.redstone, 'I', Items.stone);
        add(new ItemStack(Items.comparator, 1), " # ", "#X#", "III", '#', Items.redstone_torch, 'X', Items.quartz, 'I', Items.stone);
        add(new ItemStack(Items.navigator, 1), " # ", "#X#", " # ", '#', Items.iron_ingot, 'X', Items.redstone);
        add(new ItemStack(Items.stone_button, 1), "#", '#', Items.stone);
        add(new ItemStack(Items.stone_pressure_plate, 1), "##", '#', Items.stone);
        add(new ItemStack(Items.heavy_weighted_pressure_plate, 1), "##", '#', Items.iron_ingot);
        add(new ItemStack(Items.light_weighted_pressure_plate, 1), "##", '#', Items.gold_ingot);
        add(new ItemStack(Items.dispenser, 1), "###", "#X#", "#R#", '#', Items.cobblestone, 'X', Items.bow, 'R', Items.redstone);
        add(new ItemStack(Items.dropper, 1), "###", "# #", "#R#", '#', Items.cobblestone, 'R', Items.redstone);
        add(new ItemStack(Items.sticky_piston, 1), "S", "P", 'S', Items.slime_ball, 'P', Items.piston);
        add(new ItemStack(Items.enchanting_table, 1), " B ", "D#D", "###", '#', Items.obsidian, 'B', Items.book, 'D', Items.diamond);
        add(new ItemStack(Items.anvil, 1), "III", " i ", "iii", 'I', Items.iron_block, 'i', Items.iron_ingot);
        addShapeless(new ItemStack(Items.charged_orb, 1), Items.orb, Items.blazing_powder);
        addShapeless(new ItemStack(Items.fire_charge, 3), Items.gunpowder, Items.blazing_powder, Items.coal);
        addShapeless(new ItemStack(Items.fire_charge, 3), Items.gunpowder, Items.blazing_powder, Items.charcoal);
        add(new ItemStack(Items.hopper), "I I", "ICI", " I ", 'I', Items.iron_ingot, 'C', Items.chest);
        
        
        add(new ItemStack(Items.dynamite, 1), "X#X", "#X#", "X#X", 'X', Items.gunpowder, '#', Items.clay_ball);
        add(new ItemStack(Items.dynamite_1), "X#X", "#X#", "X#X", 'X', Items.gunpowder, '#', Items.dynamite);
        add(new ItemStack(Items.dynamite_2), "##", "##", '#', Items.dynamite_1);
        addShapeless(new ItemStack(Items.dynamite_3), Items.dynamite_2, Items.dynamite_2);
        addShapeless(new ItemStack(Items.dynamite_4), Items.dynamite_3, Items.dynamite_3);
        addShapeless(new ItemStack(Items.dynamite_5), Items.dynamite_4, Items.dynamite_4);
        addShapeless(new ItemStack(Items.dynamite_6), Items.dynamite_5, Items.dynamite_5);
        addShapeless(new ItemStack(Items.dynamite_7), Items.dynamite_6, Items.dynamite_6);

        add(new ItemStack(Items.portal_frame, 1), "XYX", "X#X", "XXX", 'X', Items.obsidian, 'Y', Items.orb, '#', Items.charged_orb);
        add(new ItemStack(Items.experience_bottle, 1), "YXY", "X#X", "YXY", 'X', Items.glass_pane, 'Y', Items.glowstone, '#', Items.emerald);
        add(new ItemStack(Items.mob_spawner, 1), "###", "#X#", "###", 'X', Items.charge_crystal, '#', Items.iron_bars);
        add(new ItemStack(Items.dragon_egg, 1), "###", "#X#", "#D#", 'X', Items.charge_crystal, 'D', Items.diamond, '#', Items.obsidian);

        add(new ItemStack(Items.red_button, 1), "#", '#', Items.redstone);
        add(new ItemStack(Items.chick_magnet, 1), "A A", "N N", " C ", 'A', Items.aluminium_ingot, 'N', Items.nickel_ingot, 'C', Items.cobalt_ingot);
        add(new ItemStack(Items.magnet, 1), "I I", "N N", " R ", 'I', Items.iron_ingot, 'N', Items.neodymium_ingot, 'R', Items.redstone);
        
        addShapeless(new ItemStack(Items.splash_potion), Items.potion, Items.gunpowder);

        add(new ItemStack(Items.construction_table), "---", "-#-", "---", '#', Items.workbench, '-', Items.iron_ingot);
        add(new ItemStack(Items.bedrock), "#####", "#####", "#####", "#####", "#####", '#', Items.obsidian);
        
        Collections.sort(recipes, new Comparator<IRecipe>()
        {
            public int compare(IRecipe r1, IRecipe r2)
            {
                return r1 instanceof ShapelessRecipes && r2 instanceof ShapedRecipes ? 1 : (r2 instanceof ShapelessRecipes && r1 instanceof ShapedRecipes ? -1 : (r2.getRecipeSize() < r1.getRecipeSize() ? -1 : (r2.getRecipeSize() > r1.getRecipeSize() ? 1 : 0)));
            }
        });
    }
    
    private static ShapedRecipes addBasic(ItemStack stack, Object ... recipeComponents) {
    	ShapedRecipes recipe = add(stack, recipeComponents);
    	base.add(recipe);
    	return recipe;
    }
    
    private static ShapedRecipes add(ItemStack stack, Object ... recipeComponents)
    {
        String s = "";
        int i = 0;
        int j = 0;
        int k = 0;

        if (recipeComponents[i] instanceof String[])
        {
            String[] astring = (String[])((String[])recipeComponents[i++]);

            for (int l = 0; l < astring.length; ++l)
            {
                String s2 = astring[l];
                ++k;
                j = s2.length();
                s = s + s2;
            }
        }
        else
        {
            while (recipeComponents[i] instanceof String)
            {
                String s1 = (String)recipeComponents[i++];
                ++k;
                j = s1.length();
                s = s + s1;
            }
        }

        Map<Character, ItemStack> map;

        for (map = Maps.<Character, ItemStack>newHashMap(); i < recipeComponents.length; i += 2)
        {
            Character character = (Character)recipeComponents[i];
            ItemStack itemstack = null;

            if (recipeComponents[i + 1] instanceof Item)
            {
                itemstack = new ItemStack((Item)recipeComponents[i + 1]);
            }
            else if (recipeComponents[i + 1] instanceof ItemStack)
            {
                itemstack = (ItemStack)recipeComponents[i + 1];
            }
            else
            {
            	throw new IllegalArgumentException("Invalid shaped recipe: unknown type " + recipeComponents[i + 1].getClass().getName() + "!");
            }

            map.put(character, itemstack);
        }

        ItemStack[] aitemstack = new ItemStack[j * k];

        for (int i1 = 0; i1 < j * k; ++i1)
        {
            char c0 = s.charAt(i1);

            if (map.containsKey(Character.valueOf(c0)))
            {
                aitemstack[i1] = ((ItemStack)map.get(Character.valueOf(c0))).copy();
            }
            else
            {
                aitemstack[i1] = null;
            }
        }

        ShapedRecipes shapedrecipes = new ShapedRecipes(j, k, aitemstack, stack);
        recipes.add(shapedrecipes);
        return shapedrecipes;
    }
    
    private static void addShapeless(ItemStack stack, Object ... recipeComponents)
    {
        List<ItemStack> list = Lists.<ItemStack>newArrayList();

        for (Object object : recipeComponents)
        {
            if (object instanceof ItemStack)
            {
                list.add(((ItemStack)object).copy());
            }
            else if (object instanceof Item)
            {
                list.add(new ItemStack((Item)object));
            }
            else
            {
                throw new IllegalArgumentException("Invalid shapeless recipe: unknown type " + object.getClass().getName() + "!");
            }
        }

        recipes.add(new ShapelessRecipes(stack, list));
    }
    
    public static ItemStack getMatching(InventoryCrafting inv, World world)
    {
        for (IRecipe irecipe : recipes)
        {
            if (irecipe.matches(inv, world))
            {
                return irecipe.getCraftingResult(inv);
            }
        }

        return null;
    }
    
    public static ItemStack getBasic(InventoryCrafting inv, World world)
    {
    	for (IRecipe irecipe : base)
        {
            if (irecipe.matches(inv, world))
            {
                return irecipe.getCraftingResult(inv);
            }
        }

        return null;
    }

    public static ItemStack[] getRequired(InventoryCrafting inv, World world)
    {
        for (IRecipe irecipe : recipes)
        {
            if (irecipe.matches(inv, world))
            {
                return irecipe.getRemainingItems(inv);
            }
        }

        ItemStack[] aitemstack = new ItemStack[inv.getSizeInventory()];

        for (int i = 0; i < aitemstack.length; ++i)
        {
            aitemstack[i] = inv.getStackInSlot(i);
        }

        return aitemstack;
    }

    public static void getRecipeList(Set<Item> set)
    {
        for (IRecipe irecipe : recipes)
        {
            if (irecipe.getRecipeOutput() != null)
            {
                set.add(irecipe.getRecipeOutput().getItem());
            }
        }
    }
    
    private static interface IRecipe {
        boolean matches(InventoryCrafting inv, World world);
        ItemStack getCraftingResult(InventoryCrafting inv);
        int getRecipeSize();
        ItemStack getRecipeOutput();
        ItemStack[] getRemainingItems(InventoryCrafting inv);
    }
    
    private static class RecipeAddPattern implements IRecipe
    {
        public boolean matches(InventoryCrafting inv, World worldIn)
        {
            boolean flag = false;

            for (int i = 0; i < inv.getSizeInventory(); ++i)
            {
                ItemStack itemstack = inv.getStackInSlot(i);

                if (itemstack != null && itemstack.getItem() == Items.banner)
                {
                    if (flag)
                    {
                        return false;
                    }

                    if (TileEntityBanner.getPatterns(itemstack) >= 6)
                    {
                        return false;
                    }

                    flag = true;
                }
            }

            if (!flag)
            {
                return false;
            }
            else
            {
                return this.getBannerPattern(inv) != null;
            }
        }

        public ItemStack getCraftingResult(InventoryCrafting inv)
        {
            ItemStack itemstack = null;

            for (int i = 0; i < inv.getSizeInventory(); ++i)
            {
                ItemStack itemstack1 = inv.getStackInSlot(i);

                if (itemstack1 != null && itemstack1.getItem() == Items.banner)
                {
                    itemstack = itemstack1.copy();
                    itemstack.size = 1;
                    break;
                }
            }

            TileEntityBanner.EnumBannerPattern type = this.getBannerPattern(inv);

            if (type != null)
            {
                int k = 0;

                for (int j = 0; j < inv.getSizeInventory(); ++j)
                {
                    ItemStack itemstack2 = inv.getStackInSlot(j);

                    if (itemstack2 != null && itemstack2.getItem() instanceof ItemDye dye)
                    {
                        k = dye.getColor().getDyeDamage();
                        break;
                    }
                }

                TagObject tag = itemstack.getSubCompound("BlockEntityTag", true);
                List<TagObject> list = null;

                if (tag.hasList("Patterns"))
                {
                    list = tag.getList("Patterns");
                }
                else
                {
                    list = Lists.newArrayList();
                    tag.setList("Patterns", list);
                }

                TagObject pattern = new TagObject();
                pattern.setString("Pattern", type.getPatternID());
                pattern.setInt("Color", k);
                list.add(pattern);
            }

            return itemstack;
        }

        public int getRecipeSize()
        {
            return 10;
        }

        public ItemStack getRecipeOutput()
        {
            return null;
        }

        public ItemStack[] getRemainingItems(InventoryCrafting inv)
        {
            ItemStack[] aitemstack = new ItemStack[inv.getSizeInventory()];

            for (int i = 0; i < aitemstack.length; ++i)
            {
                ItemStack itemstack = inv.getStackInSlot(i);

                if (itemstack != null && itemstack.getItem().hasContainerItem())
                {
                    aitemstack[i] = new ItemStack(itemstack.getItem().getContainerItem());
                }
            }

            return aitemstack;
        }

        private TileEntityBanner.EnumBannerPattern getBannerPattern(InventoryCrafting p_179533_1_)
        {
            for (TileEntityBanner.EnumBannerPattern tileentitybanner$enumbannerpattern : TileEntityBanner.EnumBannerPattern.values())
            {
                if (tileentitybanner$enumbannerpattern.hasValidCrafting())
                {
                    boolean flag = true;

                    if (tileentitybanner$enumbannerpattern.hasCraftingStack())
                    {
                        boolean flag1 = false;
                        boolean flag2 = false;

                        for (int i = 0; i < p_179533_1_.getSizeInventory() && flag; ++i)
                        {
                            ItemStack itemstack = p_179533_1_.getStackInSlot(i);

                            if (itemstack != null && itemstack.getItem() != Items.banner)
                            {
                                if (itemstack.getItem() instanceof ItemDye)
                                {
                                    if (flag2)
                                    {
                                        flag = false;
                                        break;
                                    }

                                    flag2 = true;
                                }
                                else
                                {
                                    if (flag1 || !itemstack.isItemEqual(tileentitybanner$enumbannerpattern.getCraftingStack()))
                                    {
                                        flag = false;
                                        break;
                                    }

                                    flag1 = true;
                                }
                            }
                        }

                        if (!flag1)
                        {
                            flag = false;
                        }
                    }
                    else if (p_179533_1_.getSizeInventory() == tileentitybanner$enumbannerpattern.getCraftingLayers().length * tileentitybanner$enumbannerpattern.getCraftingLayers()[0].length())
                    {
                        DyeColor j = null;

                        for (int k = 0; k < p_179533_1_.getSizeInventory() && flag; ++k)
                        {
                            int l = k / 3;
                            int i1 = k % 3;
                            ItemStack itemstack1 = p_179533_1_.getStackInSlot(k);

                            if (itemstack1 != null && itemstack1.getItem() != Items.banner)
                            {
                                if (!(itemstack1.getItem() instanceof ItemDye dye))
                                {
                                    flag = false;
                                    break;
                                }

                                if (j != null && j != dye.getColor())
                                {
                                    flag = false;
                                    break;
                                }

                                if (tileentitybanner$enumbannerpattern.getCraftingLayers()[l].charAt(i1) == 32)
                                {
                                    flag = false;
                                    break;
                                }

                                j = dye.getColor();
                            }
                            else if (tileentitybanner$enumbannerpattern.getCraftingLayers()[l].charAt(i1) != 32)
                            {
                                flag = false;
                                break;
                            }
                        }
                    }
                    else
                    {
                        flag = false;
                    }

                    if (flag)
                    {
                        return tileentitybanner$enumbannerpattern;
                    }
                }
            }

            return null;
        }
    }
    
    private static class RecipeDuplicatePattern implements IRecipe
    {
        public boolean matches(InventoryCrafting inv, World worldIn)
        {
            ItemStack itemstack = null;
            ItemStack itemstack1 = null;

            for (int i = 0; i < inv.getSizeInventory(); ++i)
            {
                ItemStack itemstack2 = inv.getStackInSlot(i);

                if (itemstack2 != null)
                {
                    if (itemstack2.getItem() != Items.banner)
                    {
                        return false;
                    }

                    if (itemstack != null && itemstack1 != null)
                    {
                        return false;
                    }

                    DyeColor j = TileEntityBanner.getBaseColor(itemstack2);
                    boolean flag = TileEntityBanner.getPatterns(itemstack2) > 0;

                    if (itemstack != null)
                    {
                        if (flag)
                        {
                            return false;
                        }

                        if (j != TileEntityBanner.getBaseColor(itemstack))
                        {
                            return false;
                        }

                        itemstack1 = itemstack2;
                    }
                    else if (itemstack1 != null)
                    {
                        if (!flag)
                        {
                            return false;
                        }

                        if (j != TileEntityBanner.getBaseColor(itemstack1))
                        {
                            return false;
                        }

                        itemstack = itemstack2;
                    }
                    else if (flag)
                    {
                        itemstack = itemstack2;
                    }
                    else
                    {
                        itemstack1 = itemstack2;
                    }
                }
            }

            return itemstack != null && itemstack1 != null;
        }

        public ItemStack getCraftingResult(InventoryCrafting inv)
        {
            for (int i = 0; i < inv.getSizeInventory(); ++i)
            {
                ItemStack itemstack = inv.getStackInSlot(i);

                if (itemstack != null && TileEntityBanner.getPatterns(itemstack) > 0)
                {
                    ItemStack itemstack1 = itemstack.copy();
                    itemstack1.size = 1;
                    return itemstack1;
                }
            }

            return null;
        }

        public int getRecipeSize()
        {
            return 2;
        }

        public ItemStack getRecipeOutput()
        {
            return null;
        }

        public ItemStack[] getRemainingItems(InventoryCrafting inv)
        {
            ItemStack[] aitemstack = new ItemStack[inv.getSizeInventory()];

            for (int i = 0; i < aitemstack.length; ++i)
            {
                ItemStack itemstack = inv.getStackInSlot(i);

                if (itemstack != null)
                {
                    if (itemstack.getItem().hasContainerItem())
                    {
                        aitemstack[i] = new ItemStack(itemstack.getItem().getContainerItem());
                    }
                    else if (itemstack.hasTagCompound() && TileEntityBanner.getPatterns(itemstack) > 0)
                    {
                        aitemstack[i] = itemstack.copy();
                        aitemstack[i].size = 1;
                    }
                }
            }

            return aitemstack;
        }
    }
    
    private static class RecipeFireworks implements IRecipe
    {
        private ItemStack field_92102_a;

        /**
         * Used to check if a recipe matches current crafting inventory
         */
        public boolean matches(InventoryCrafting inv, World worldIn)
        {
            this.field_92102_a = null;
            int i = 0;
            int j = 0;
            int k = 0;
            int l = 0;
            int i1 = 0;
            int j1 = 0;

            for (int k1 = 0; k1 < inv.getSizeInventory(); ++k1)
            {
                ItemStack itemstack = inv.getStackInSlot(k1);

                if (itemstack != null)
                {
                    if (itemstack.getItem() == Items.gunpowder)
                    {
                        ++j;
                    }
                    else if (itemstack.getItem() == Items.firework_charge)
                    {
                        ++l;
                    }
                    else if (itemstack.getItem() instanceof ItemDye)
                    {
                        ++k;
                    }
                    else if (itemstack.getItem() == Items.paper)
                    {
                        ++i;
                    }
                    else if (itemstack.getItem() == Items.glowstone_dust)
                    {
                        ++i1;
                    }
                    else if (itemstack.getItem() == Items.diamond)
                    {
                        ++i1;
                    }
                    else if (itemstack.getItem() == Items.fire_charge)
                    {
                        ++j1;
                    }
                    else if (itemstack.getItem() == Items.feather)
                    {
                        ++j1;
                    }
                    else if (itemstack.getItem() == Items.gold_nugget)
                    {
                        ++j1;
                    }
                    else
                    {
                        if (itemstack.getItem() != Items.skull)
                        {
                            return false;
                        }

                        ++j1;
                    }
                }
            }

            i1 = i1 + k + j1;

            if (j <= 3 && i <= 1)
            {
                if (j >= 1 && i == 1 && i1 == 0)
                {
                    this.field_92102_a = new ItemStack(Items.fireworks);

                    if (l > 0)
                    {
                        TagObject tag = new TagObject();
                        TagObject data = new TagObject();
                        List<TagObject> list = Lists.newArrayList();

                        for (int k2 = 0; k2 < inv.getSizeInventory(); ++k2)
                        {
                            ItemStack itemstack3 = inv.getStackInSlot(k2);

                            if (itemstack3 != null && itemstack3.getItem() == Items.firework_charge && itemstack3.hasTagCompound() && itemstack3.getTagCompound().hasObject("Explosion"))
                            {
                                list.add(itemstack3.getTagCompound().getObject("Explosion"));
                            }
                        }

                        data.setList("Explosions", list);
                        data.setByte("Flight", (byte)j);
                        tag.setObject("Fireworks", data);
                        this.field_92102_a.setTagCompound(tag);
                    }

                    return true;
                }
                else if (j == 1 && i == 0 && l == 0 && k > 0 && j1 <= 1)
                {
                    this.field_92102_a = new ItemStack(Items.firework_charge);
                    TagObject tag = new TagObject();
                    TagObject data = new TagObject();
                    byte b0 = 0;
                    List<Integer> list = Lists.<Integer>newArrayList();

                    for (int l1 = 0; l1 < inv.getSizeInventory(); ++l1)
                    {
                        ItemStack itemstack2 = inv.getStackInSlot(l1);

                        if (itemstack2 != null)
                        {
                            if (itemstack2.getItem() instanceof ItemDye dye)
                            {
                                list.add(ItemDye.FIREWORK_COLORS[dye.getColor().getDyeDamage()]);
                            }
                            else if (itemstack2.getItem() == Items.glowstone_dust)
                            {
                                data.setBool("Flicker", true);
                            }
                            else if (itemstack2.getItem() == Items.diamond)
                            {
                                data.setBool("Trail", true);
                            }
                            else if (itemstack2.getItem() == Items.fire_charge)
                            {
                                b0 = 1;
                            }
                            else if (itemstack2.getItem() == Items.feather)
                            {
                                b0 = 4;
                            }
                            else if (itemstack2.getItem() == Items.gold_nugget)
                            {
                                b0 = 2;
                            }
                            else if (itemstack2.getItem() == Items.skull)
                            {
                                b0 = 3;
                            }
                        }
                    }

                    int[] aint1 = new int[list.size()];

                    for (int l2 = 0; l2 < aint1.length; ++l2)
                    {
                        aint1[l2] = ((Integer)list.get(l2)).intValue();
                    }

                    data.setIntArray("Colors", aint1);
                    data.setByte("Type", b0);
                    tag.setObject("Explosion", data);
                    this.field_92102_a.setTagCompound(tag);
                    return true;
                }
                else if (j == 0 && i == 0 && l == 1 && k > 0 && k == i1)
                {
                    List<Integer> list1 = Lists.<Integer>newArrayList();

                    for (int i2 = 0; i2 < inv.getSizeInventory(); ++i2)
                    {
                        ItemStack itemstack1 = inv.getStackInSlot(i2);

                        if (itemstack1 != null)
                        {
                            if (itemstack1.getItem() instanceof ItemDye dye)
                            {
                                list1.add(ItemDye.FIREWORK_COLORS[dye.getColor().getDyeDamage()]);
                            }
                            else if (itemstack1.getItem() == Items.firework_charge)
                            {
                                this.field_92102_a = itemstack1.copy();
                                this.field_92102_a.size = 1;
                            }
                        }
                    }

                    int[] aint = new int[list1.size()];

                    for (int j2 = 0; j2 < aint.length; ++j2)
                    {
                        aint[j2] = ((Integer)list1.get(j2)).intValue();
                    }

                    if (this.field_92102_a != null && this.field_92102_a.hasTagCompound())
                    {
                        TagObject tag = this.field_92102_a.getTagCompound().getObject("Explosion");

                        if (tag == null)
                        {
                            return false;
                        }
                        else
                        {
                            tag.setIntArray("FadeColors", aint);
                            return true;
                        }
                    }
                    else
                    {
                        return false;
                    }
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }

        /**
         * Returns an Item that is the result of this recipe
         */
        public ItemStack getCraftingResult(InventoryCrafting inv)
        {
            return this.field_92102_a.copy();
        }

        /**
         * Returns the size of the recipe area
         */
        public int getRecipeSize()
        {
            return 10;
        }

        public ItemStack getRecipeOutput()
        {
            return this.field_92102_a;
        }

        public ItemStack[] getRemainingItems(InventoryCrafting inv)
        {
            ItemStack[] aitemstack = new ItemStack[inv.getSizeInventory()];

            for (int i = 0; i < aitemstack.length; ++i)
            {
                ItemStack itemstack = inv.getStackInSlot(i);

                if (itemstack != null && itemstack.getItem().hasContainerItem())
                {
                    aitemstack[i] = new ItemStack(itemstack.getItem().getContainerItem());
                }
            }

            return aitemstack;
        }
    }
    
    private static class RecipeRepairItem implements IRecipe
    {
        /**
         * Used to check if a recipe matches current crafting inventory
         */
        public boolean matches(InventoryCrafting inv, World worldIn)
        {
            List<ItemStack> list = Lists.<ItemStack>newArrayList();

            for (int i = 0; i < inv.getSizeInventory(); ++i)
            {
                ItemStack itemstack = inv.getStackInSlot(i);

                if (itemstack != null)
                {
                    list.add(itemstack);

                    if (list.size() > 1)
                    {
                        ItemStack itemstack1 = (ItemStack)list.get(0);

                        if (itemstack.getItem() != itemstack1.getItem() || itemstack1.size != 1 || itemstack.size != 1 || !itemstack1.getItem().isDamageable())
                        {
                            return false;
                        }
                    }
                }
            }

            return list.size() == 2;
        }

        /**
         * Returns an Item that is the result of this recipe
         */
        public ItemStack getCraftingResult(InventoryCrafting inv)
        {
            List<ItemStack> list = Lists.<ItemStack>newArrayList();

            for (int i = 0; i < inv.getSizeInventory(); ++i)
            {
                ItemStack itemstack = inv.getStackInSlot(i);

                if (itemstack != null)
                {
                    list.add(itemstack);

                    if (list.size() > 1)
                    {
                        ItemStack itemstack1 = (ItemStack)list.get(0);

                        if (itemstack.getItem() != itemstack1.getItem() || itemstack1.size != 1 || itemstack.size != 1 || !itemstack1.getItem().isDamageable())
                        {
                            return null;
                        }
                    }
                }
            }

            if (list.size() == 2)
            {
                ItemStack itemstack2 = (ItemStack)list.get(0);
                ItemStack itemstack3 = (ItemStack)list.get(1);

                if (itemstack2.getItem() == itemstack3.getItem() && itemstack2.size == 1 && itemstack3.size == 1 && itemstack2.getItem().isDamageable())
                {
                    Item item = itemstack2.getItem();
                    int j = item.getMaxDamage() - itemstack2.getItemDamage();
                    int k = item.getMaxDamage() - itemstack3.getItemDamage();
                    int l = j + k + item.getMaxDamage() * 5 / 100;
                    int i1 = item.getMaxDamage() - l;

                    if (i1 < 0)
                    {
                        i1 = 0;
                    }

                    ItemStack stack = new ItemStack(itemstack2.getItem());
                    stack.setItemDamage(i1);
                    return stack;
                }
            }

            return null;
        }

        /**
         * Returns the size of the recipe area
         */
        public int getRecipeSize()
        {
            return 4;
        }

        public ItemStack getRecipeOutput()
        {
            return null;
        }

        public ItemStack[] getRemainingItems(InventoryCrafting inv)
        {
            ItemStack[] aitemstack = new ItemStack[inv.getSizeInventory()];

            for (int i = 0; i < aitemstack.length; ++i)
            {
                ItemStack itemstack = inv.getStackInSlot(i);

                if (itemstack != null && itemstack.getItem().hasContainerItem())
                {
                    aitemstack[i] = new ItemStack(itemstack.getItem().getContainerItem());
                }
            }

            return aitemstack;
        }
    }
    
    private static class RecipesArmorDyes implements IRecipe
    {
        /**
         * Used to check if a recipe matches current crafting inventory
         */
        public boolean matches(InventoryCrafting inv, World worldIn)
        {
            ItemStack itemstack = null;
            List<ItemStack> list = Lists.<ItemStack>newArrayList();

            for (int i = 0; i < inv.getSizeInventory(); ++i)
            {
                ItemStack itemstack1 = inv.getStackInSlot(i);

                if (itemstack1 != null)
                {
                    if (itemstack1.getItem() instanceof ItemArmor)
                    {
                        ItemArmor itemarmor = (ItemArmor)itemstack1.getItem();

                        if (!itemarmor.getArmorMaterial().canBeDyed() || itemstack != null)
                        {
                            return false;
                        }

                        itemstack = itemstack1;
                    }
                    else
                    {
                        if (!(itemstack1.getItem() instanceof ItemDye))
                        {
                            return false;
                        }

                        list.add(itemstack1);
                    }
                }
            }

            return itemstack != null && !list.isEmpty();
        }

        /**
         * Returns an Item that is the result of this recipe
         */
        public ItemStack getCraftingResult(InventoryCrafting inv)
        {
            ItemStack itemstack = null;
            int[] aint = new int[3];
            int i = 0;
            int j = 0;
            ItemArmor itemarmor = null;

            for (int k = 0; k < inv.getSizeInventory(); ++k)
            {
                ItemStack itemstack1 = inv.getStackInSlot(k);

                if (itemstack1 != null)
                {
                    if (itemstack1.getItem() instanceof ItemArmor)
                    {
                        itemarmor = (ItemArmor)itemstack1.getItem();

                        if (!itemarmor.getArmorMaterial().canBeDyed() || itemstack != null)
                        {
                            return null;
                        }

                        itemstack = itemstack1.copy();
                        itemstack.size = 1;

                        if (itemarmor.hasColor(itemstack1))
                        {
                            int l = itemarmor.getArmorColor(itemstack);
                            float f = (float)(l >> 16 & 255) / 255.0F;
                            float f1 = (float)(l >> 8 & 255) / 255.0F;
                            float f2 = (float)(l & 255) / 255.0F;
                            i = (int)((float)i + Math.max(f, Math.max(f1, f2)) * 255.0F);
                            aint[0] = (int)((float)aint[0] + f * 255.0F);
                            aint[1] = (int)((float)aint[1] + f1 * 255.0F);
                            aint[2] = (int)((float)aint[2] + f2 * 255.0F);
                            ++j;
                        }
                    }
                    else
                    {
                        if (!(itemstack1.getItem() instanceof ItemDye dye))
                        {
                            return null;
                        }

                        float[] afloat = EntitySheep.getDyeRgb(dye.getColor());
                        int l1 = (int)(afloat[0] * 255.0F);
                        int i2 = (int)(afloat[1] * 255.0F);
                        int j2 = (int)(afloat[2] * 255.0F);
                        i += Math.max(l1, Math.max(i2, j2));
                        aint[0] += l1;
                        aint[1] += i2;
                        aint[2] += j2;
                        ++j;
                    }
                }
            }

            if (itemarmor == null)
            {
                return null;
            }
            else
            {
                int i1 = aint[0] / j;
                int j1 = aint[1] / j;
                int k1 = aint[2] / j;
                float f3 = (float)i / (float)j;
                float f4 = (float)Math.max(i1, Math.max(j1, k1));
                i1 = (int)((float)i1 * f3 / f4);
                j1 = (int)((float)j1 * f3 / f4);
                k1 = (int)((float)k1 * f3 / f4);
                int lvt_12_3_ = (i1 << 8) + j1;
                lvt_12_3_ = (lvt_12_3_ << 8) + k1;
                itemarmor.setColor(itemstack, lvt_12_3_);
                return itemstack;
            }
        }

        /**
         * Returns the size of the recipe area
         */
        public int getRecipeSize()
        {
            return 10;
        }

        public ItemStack getRecipeOutput()
        {
            return null;
        }

        public ItemStack[] getRemainingItems(InventoryCrafting inv)
        {
            ItemStack[] aitemstack = new ItemStack[inv.getSizeInventory()];

            for (int i = 0; i < aitemstack.length; ++i)
            {
                ItemStack itemstack = inv.getStackInSlot(i);

                if (itemstack != null && itemstack.getItem().hasContainerItem())
                {
                    aitemstack[i] = new ItemStack(itemstack.getItem().getContainerItem());
                }
            }

            return aitemstack;
        }
    }
    
    private static class ShapedRecipes implements IRecipe
    {
        /** How many horizontal slots this recipe is wide. */
        private final int recipeWidth;

        /** How many vertical slots this recipe uses. */
        private final int recipeHeight;

        /** Is a array of ItemStack that composes the recipe. */
        private final ItemStack[] recipeItems;

        /** Is the ItemStack that you get when craft the recipe. */
        private final ItemStack recipeOutput;
        private boolean copyIngredientTag;

        public ShapedRecipes(int width, int height, ItemStack[] p_i1917_3_, ItemStack output)
        {
            this.recipeWidth = width;
            this.recipeHeight = height;
            this.recipeItems = p_i1917_3_;
            this.recipeOutput = output;
        }

        public ItemStack getRecipeOutput()
        {
            return this.recipeOutput;
        }

        public ItemStack[] getRemainingItems(InventoryCrafting inv)
        {
            ItemStack[] aitemstack = new ItemStack[inv.getSizeInventory()];

            for (int i = 0; i < aitemstack.length; ++i)
            {
                ItemStack itemstack = inv.getStackInSlot(i);

                if (itemstack != null && itemstack.getItem().hasContainerItem())
                {
                    aitemstack[i] = new ItemStack(itemstack.getItem().getContainerItem());
                }
            }

            return aitemstack;
        }

        /**
         * Used to check if a recipe matches current crafting inventory
         */
        public boolean matches(InventoryCrafting inv, World worldIn)
        {
            for (int i = 0; i <= inv.getWidth() - this.recipeWidth; ++i)
            {
                for (int j = 0; j <= inv.getHeight() - this.recipeHeight; ++j)
                {
                    if (this.checkMatch(inv, i, j, true))
                    {
                        return true;
                    }

                    if (this.checkMatch(inv, i, j, false))
                    {
                        return true;
                    }
                }
            }

            return false;
        }

        /**
         * Checks if the region of a crafting inventory is match for the recipe.
         */
        private boolean checkMatch(InventoryCrafting inv, int xPos, int yPos, boolean mirror)
        {
            for (int x = 0; x < inv.getWidth(); ++x)
            {
                for (int y = 0; y < inv.getHeight(); ++y)
                {
                    int rx = x - xPos;
                    int ry = y - yPos;
                    ItemStack stack = null;

                    if (rx >= 0 && ry >= 0 && rx < this.recipeWidth && ry < this.recipeHeight)
                    {
                        if (mirror)
                        {
                            stack = this.recipeItems[this.recipeWidth - rx - 1 + ry * this.recipeWidth];
                        }
                        else
                        {
                            stack = this.recipeItems[rx + ry * this.recipeWidth];
                        }
                    }

                    ItemStack ingredient = inv.getStackInRowAndColumn(x, y);

                    if (ingredient != null || stack != null)
                    {
                        if (ingredient == null && stack != null || ingredient != null && stack == null)
                        {
                            return false;
                        }

                        if (stack.getItem() != ingredient.getItem())
                        {
                            return false;
                        }
                    }
                }
            }

            return true;
        }

        /**
         * Returns an Item that is the result of this recipe
         */
        public ItemStack getCraftingResult(InventoryCrafting inv)
        {
            ItemStack itemstack = this.getRecipeOutput().copy();

            if (this.copyIngredientTag)
            {
                for (int i = 0; i < inv.getSizeInventory(); ++i)
                {
                    ItemStack itemstack1 = inv.getStackInSlot(i);

                    if (itemstack1 != null && itemstack1.hasTagCompound())
                    {
                        itemstack.setTagCompound(itemstack1.getTagCompound().copy());
                    }
                }
            }

            return itemstack;
        }

        /**
         * Returns the size of the recipe area
         */
        public int getRecipeSize()
        {
            return this.recipeWidth * this.recipeHeight;
        }
    }
    
    private static class ShapelessRecipes implements IRecipe
    {
        /** Is the ItemStack that you get when craft the recipe. */
        private final ItemStack recipeOutput;
        private final List<ItemStack> recipeItems;

        public ShapelessRecipes(ItemStack output, List<ItemStack> inputList)
        {
            this.recipeOutput = output;
            this.recipeItems = inputList;
        }

        public ItemStack getRecipeOutput()
        {
            return this.recipeOutput;
        }

        public ItemStack[] getRemainingItems(InventoryCrafting inv)
        {
            ItemStack[] aitemstack = new ItemStack[inv.getSizeInventory()];

            for (int i = 0; i < aitemstack.length; ++i)
            {
                ItemStack itemstack = inv.getStackInSlot(i);

                if (itemstack != null && itemstack.getItem().hasContainerItem())
                {
                    aitemstack[i] = new ItemStack(itemstack.getItem().getContainerItem());
                }
            }

            return aitemstack;
        }

        /**
         * Used to check if a recipe matches current crafting inventory
         */
        public boolean matches(InventoryCrafting inv, World worldIn)
        {
            List<ItemStack> list = Lists.newArrayList(this.recipeItems);

            for (int i = 0; i < inv.getHeight(); ++i)
            {
                for (int j = 0; j < inv.getWidth(); ++j)
                {
                    ItemStack itemstack = inv.getStackInRowAndColumn(j, i);

                    if (itemstack != null)
                    {
                        boolean flag = false;

                        for (ItemStack itemstack1 : list)
                        {
                            if (itemstack.getItem() == itemstack1.getItem())
                            {
                                flag = true;
                                list.remove(itemstack1);
                                break;
                            }
                        }

                        if (!flag)
                        {
                            return false;
                        }
                    }
                }
            }

            return list.isEmpty();
        }

        /**
         * Returns an Item that is the result of this recipe
         */
        public ItemStack getCraftingResult(InventoryCrafting inv)
        {
            return this.recipeOutput.copy();
        }

        /**
         * Returns the size of the recipe area
         */
        public int getRecipeSize()
        {
            return this.recipeItems.size();
        }
    }
}
