@Config(modid=RealFilingCabinet.MOD_ID)
public static class ConfigRFC {
		
	// RECIPES
	@Comment({"Enable Crafting Upgrade recipe"})
	@Tap
	public static boolean craftingUpgrade = true;
	@Comment({"Enable Ender Upgrade recipe"})
	@Tap
	public static boolean enderUpgrade = true;
	@Comment({"Enable Oredict Upgrade recipe"})
	@Tap
	public static boolean oreDictUpgrade = true;
	@Comment({"Enable Mob Upgrade recipe"})
	@Tap
	public static boolean mobUpgrade = true;
	@Comment({"Enable Fluid Upgrade recipe"})
	@Tap
	public static boolean fluidUpgrade = true;
	@Comment({"Enable Life Upgrade recipe"})
	@Tap
	public static boolean lifeUpgrade = true;
	@Comment({"Enable Smelting Upgrade recipe"})
	@Tap
	public static boolean smeltingUpgrade = true;
		
	// MISC
	@Comment({"Disable this if you want TheOneProbe to handle the overlay instead."})
	@Tap
	public static boolean magnifyingGlassGui = true;
	@Comment({"If enabled, will let Mob Folders with a villager in it spawn villagers with their professions randomized."})
	@Tap
	public static boolean randomVillager = false;
	@Comment({"If enabled, will let filing cabinets use a different texture depending on the season."})
	@Tap
	public static boolean seasonalCabinets = true;
	@Comment({"If enabled, will let Fluid Folders place water in the nether."})
	@Tap
	public static boolean waterNether = false;
	@Comment({"If disabled, will not let folders pick up dropped items."})
	@Tap
	public static boolean pickupStuff = true;
	@Comment({"Will output stuff to console for debugging purposes."})
	@Tap
	public static boolean debugLogger = false;
	@Comment({"Use this to blacklist certain mobs from being captured in the Mob Folder. Put the class names of the entities here."})
	public static String[] mobFolderBlacklist = new String[]{};
	@Comment({"If enabled, A fluid cabinet filled with more than 3000mb of water will never run out of water."})
	@Tap
	public static boolean infiniteWaterSource = true;
	@Comment({"Configure the general folder storage limit for dyed folders."})
	@Tap
	public static int folderSizeLimit = 1000;
		
	// INTEGRATION
	@Comment({"If enabled, will add mana cabinets and folders for Botania"})
	@Tap
	public static boolean botaniaIntegration = true;
	@Comment({"If enabled, will add a folder and a cabinet when it detects that Thaumcraft is installed."})
	@Tap
	public static boolean tcIntegration = true;
} @Mod(modid=RealFilingCabinet.MOD_ID, name=RealFilingCabinet.MOD_NAME, version=RealFilingCabinet.VERSION, dependencies = "after:forge@[" + RealFilingCabinet.FORGE_VER + ",);")
public class RealFilingCabinet {

	public static final String MOD_ID = "realfilingcabinet";
	public static final String MOD_NAME = "Real Filing Cabinet";
	public static final String VERSION = "@VERSION@";
	public static final String FORGE_VER = "14.21.0.2363";
	
	// intentional typo in order to disable integration with storage drawers for now
	public static final String STORAGEDRAWERS = "storageDrawers";
	
	@SidedProxy(clientSide="com.bafomdad.realfilingcabinet.proxies.ClientProxy", serverSide="com.bafomdad.realfilingcabinet.proxies.CommonProxy")
	public static CommonProxy proxy;
	
	@Mod.Instance(MOD_ID)
	public static RealFilingCabinet instance;
	
	public static Logger logger;
	
	public static boolean botaniaLoaded = Loader.isModLoaded("botania");
	public static boolean topLoaded = Loader.isModLoaded("theoneprobe");
	public static boolean wailaLoaded = Loader.isModLoaded("waila");
	public static boolean tcLoaded = Loader.isModLoaded("thaumcraft");
	public static boolean crtLoaded = Loader.isModLoaded("crafttweaker");
	
	@Mod.EventHandler
	public void preInit(FMLPreInitializationEvent event) {
		
		NetworkRegistry.INSTANCE.registerGuiHandler(this, new GuiHandlerRFC());
		NewConfigRFC.preInit(event);
		logger = event.getModLog();
		
		proxy.preInit(event);
		proxy.initAllModels();
	}
	
	@Mod.EventHandler
	public void init(FMLInitializationEvent event) {

		proxy.init(event);
	}
	
	@Mod.EventHandler
	public void postInit(FMLPostInitializationEvent event) {
		
		proxy.postInit(event);
		MinecraftForge.EVENT_BUS.register(new EventHandlerServer());
		CapabilityProviderFolder.register();
	}
	
	@Mod.EventHandler
	public void serverLoad(FMLServerStartingEvent event) {
		
		event.registerServerCommand(new CommandRFC());
	}
} @Optional.Interface(iface = "com.jaquadro.minecraft.storagedrawers.api.storage.IDrawerGroup", modid = RealFilingCabinet.STORAGEDRAWERS, striprefs = true)
public class TileEntityRFC extends TileFilingCabinet implements ITickable, ILockableCabinet, IDrawerGroup {

	private InventoryRFC inv = new InventoryRFC(this, 8);
	private FluidRFC fluidinv = new FluidRFC(this);
	
	private UUID owner;
	
	// MISC variables
	private long lastClickTime;
	private UUID lastClickUUID;
	
	// NBT variables
	private int rfcHash = -1;
	public boolean isCreative = false;
	public String upgrades = "";
	public List<int[]> smeltingJobs = Lists.newArrayList();
	public int fuelTime = 0;
	public ItemStack uncraftableItem = ItemStack.EMPTY;
	
	// Rendering variables
	public static final float offsetSpeed = 0.1F;
	public boolean isOpen = false;

	@Override
	public void update() {
		
		if (isOpen) {
			offset -= offsetSpeed;
			if (offset <= -0.75F)
				offset = -0.75F;
		} else {
			offset += offsetSpeed;
			if (offset >= 0.05F)
				offset = 0.05F;
		}
		if (SmeltingUtils.canSmelt(this)) {
//			if (!world.isRemote) {
				SmeltingUtils.incrementSmeltTime(this);
				if (getWorld().getTotalWorldTime() % 40 == 0) {
					SmeltingUtils.createSmeltingJob(this);
					this.markBlockForUpdate();
				}
//			}
			return;
		}
		if (UpgradeHelper.getUpgrade(this, StringLibs.TAG_LIFE) != null) {
			if (!world.isRemote) {
				EntityCabinet cabinet = new EntityCabinet(world);
				IBlockState state = world.getBlockState(getPos());
				float angle = state.getActualState(world, pos).getValue(BlockHorizontal.FACING).getHorizontalAngle();
				cabinet.setPosition(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5);
				cabinet.setRotationYawHead(angle);
				
				for (int i = 0; i < this.getInventory().getSlots(); i++) {
					ItemStack folder = this.getInventory().getTrueStackInSlot(i);
					if (folder != null) {
						cabinet.setInventory(i, folder.copy());
					}
				}
				if (this.isCabinetLocked()) {
					UUID uuid = this.getCabinetOwner();
					cabinet.setOwnerId(uuid);
				} else
					cabinet.homePos = getPos().toLong();
				
				if (!cabinet.isLegit())
					cabinet.setLegit();
				
				world.spawnEntity(cabinet);
			}
			world.setBlockToAir(getPos());
		}
	}
	
	@Override
    public NBTTagCompound getUpdateTag() {
		
		return writeToNBT(new NBTTagCompound());
    }
	
	@Nullable
	@Override
	public SPacketUpdateTileEntity getUpdatePacket() {
		
		NBTTagCompound nbtTag = new NBTTagCompound();
		this.writeCustomNBT(nbtTag);
		
		return new SPacketUpdateTileEntity(getPos(), 1, nbtTag);
	}

	@Override
	public void writeCustomNBT(NBTTagCompound tag) {
		
		tag.setTag("inventory", inv.serializeNBT());
		tag.setBoolean("isOpen", this.isOpen);
		tag.setBoolean(StringLibs.TAG_CREATIVE, this.isCreative);
		tag.setTag(StringLibs.RFC_CRAFTABLE, uncraftableItem.serializeNBT());
		
		if (owner != null)
			tag.setString("Own", owner.toString());
		if (rfcHash != -1)
			tag.setInteger(StringLibs.RFC_HASH, rfcHash);
		
		tag.setString(StringLibs.RFC_UPGRADE, upgrades);
		
		SmeltingUtils.writeSmeltNBT(this, tag);
	}
	
	@Override
	public void readCustomNBT(NBTTagCompound tag) {
		
		inv.deserializeNBT(tag.getCompoundTag("inventory"));
		this.isOpen = tag.getBoolean("isOpen");
		this.isCreative = tag.getBoolean(StringLibs.TAG_CREATIVE);
		if (tag.hasKey(StringLibs.RFC_CRAFTABLE))
			this.uncraftableItem = new ItemStack((NBTTagCompound) tag.getTag(StringLibs.RFC_CRAFTABLE));
		
		this.owner = null;
		if (tag.hasKey("Own"))
			owner = UUID.fromString(tag.getString("Own"));
		if (tag.hasKey(StringLibs.RFC_HASH))
			rfcHash = tag.getInteger(StringLibs.RFC_HASH);
		upgrades = tag.getString(StringLibs.RFC_UPGRADE);
		
		SmeltingUtils.readSmeltNBT(this, tag);
	}
	
	public void readInv(NBTTagCompound nbt) {
		
		NBTTagList invList = nbt.getTagList("inventory", 10);
		for (int i = 0; i < invList.tagCount(); i++) {
			NBTTagCompound itemTag = invList.getCompoundTagAt(i);
			int slot = itemTag.getByte("Slot");
			if (slot >= 0 && slot < inv.getSlots())
				inv.getStacks().set(slot, new ItemStack(itemTag));
		}
	}
	
	public void writeInv(NBTTagCompound nbt, boolean toItem) {
		
		boolean write = false;
		NBTTagList invList = new NBTTagList();
		for (int i = 0; i < inv.getSlots(); i++) {
			if (!inv.getTrueStackInSlot(i).isEmpty()) {
				if (toItem)
					write = true;
				NBTTagCompound itemTag = new NBTTagCompound();
				itemTag.setByte("Slot", (byte)i);
				inv.getTrueStackInSlot(i).writeToNBT(itemTag);
				invList.appendTag(itemTag);
			}
		}
		if (!toItem || write)
			nbt.setTag("inventory", invList);
	}
	
	public InventoryRFC getInventory() {
		
		return inv;
	}
	
	public IFluidHandler getFluidInventory() {
		
		return fluidinv;
	}
	
	public boolean calcLastClick(EntityPlayer player) {
		
		boolean bool = false;
		
		if (getWorld().getTotalWorldTime() - lastClickTime < 10 && player.getPersistentID().equals(lastClickUUID)) {
			bool = true;
		}
		lastClickTime = getWorld().getTotalWorldTime();
		lastClickUUID = player.getPersistentID();
		
		return bool;
	}
	
	public boolean hasItemFrame() {
		
		AxisAlignedBB aabb = new AxisAlignedBB(pos.add(0, 1, 0), pos.add(1, 2, 1));
		List<EntityItemFrame> frames = this.getWorld().getEntitiesWithinAABB(EntityItemFrame.class, aabb);
		for (EntityItemFrame frame : frames) {
			EnumFacing orientation = frame.getAdjustedHorizontalFacing();
			IBlockState state = getWorld().getBlockState(getPos());
			EnumFacing rfcOrientation = (EnumFacing)state.getValue(BlockRFC.FACING);
			
			return frame != null && orientation == rfcOrientation;
		}
		return false;
	}
	
	public ItemStack getFilter() {
		
		AxisAlignedBB aabb = new AxisAlignedBB(pos.add(0, 1, 0), pos.add(1, 2, 1));
		List<EntityItemFrame> frames = this.getWorld().getEntitiesWithinAABB(EntityItemFrame.class, aabb);
		for (EntityItemFrame frame : frames) {
			EnumFacing orientation = frame.getAdjustedHorizontalFacing();
			IBlockState state = getWorld().getBlockState(getPos());
			EnumFacing rfcOrientation = (EnumFacing)state.getValue(BlockRFC.FACING);
			if (frame != null && !frame.getDisplayedItem().isEmpty() && (orientation == rfcOrientation)) {
				if (frame.getDisplayedItem().getItem() == RFCItems.filter) {
					int rotation = frame.getRotation();
					return inv.getStackFromFolder(rotation);
				}
				return frame.getDisplayedItem();
			}
		}
		return ItemStack.EMPTY;
	}
	
	@Override
	public boolean hasCapability(@Nonnull Capability<?> cap, EnumFacing side) {
		
		if (cap == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY && UpgradeHelper.getUpgrade(this, StringLibs.TAG_FLUID) != null)
			return cap == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY;
		if (cap == DRAWER_GROUP_CAPABILITY && !UpgradeHelper.hasUpgrade(this))
			return cap == DRAWER_GROUP_CAPABILITY;
		
		return cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY;
	}
	
	@Override
	public <T> T getCapability(@Nonnull Capability<T> cap, EnumFacing side) {
		
		if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) {
			return CapabilityItemHandler.ITEM_HANDLER_CAPABILITY.cast(inv);
		}
		if (cap == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY)
			return CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY.cast(fluidinv);
		if (cap == DRAWER_GROUP_CAPABILITY)
			return (T) this;
		
		return super.getCapability(cap, side);
	}

	@Override
	public UUID getCabinetOwner() {

		return owner;
	}

	@Override
	public boolean setOwner(UUID owner) {

		if ((this.owner != null && !this.owner.equals(owner)) || (owner != null && !owner.equals(this.owner))) {
			this.owner = owner;
			
			if (getWorld() != null && !getWorld().isRemote) {
				markDirty();
				this.markBlockForUpdate();
			}
		}
		return true;
	}

	@Override
	public boolean isCabinetLocked() {

		return getCabinetOwner() != null;
	}
	
	public boolean hasKeyCopy(EntityPlayer player, UUID uuid) {
		
		for (int i = 0; i < player.inventory.mainInventory.size(); i++) {
			ItemStack keyCopy = player.inventory.mainInventory.get(i);
			if (keyCopy.isEmpty())
				continue;
			if (keyCopy.getItem() == RFCItems.keys && keyCopy.getItemDamage() == 1) {
				if (keyCopy.hasTagCompound() && keyCopy.getTagCompound().hasKey(StringLibs.RFC_COPY)) {
					return uuid.equals(UUID.fromString(NBTUtils.getString(keyCopy, StringLibs.RFC_COPY, "")));
				}
			}
		}
		return false;
	}
	
	public void setHash(TileEntity tile) {
		
		this.rfcHash = EnderUtils.createHash(this);
	}
	
	public int getHash(TileEntityRFC tile) {
		
		return this.rfcHash;
	}

/**
 * Storage Drawers Integration begins here
 */
	@CapabilityInject(IDrawerGroup.class)
	static Capability<IDrawerGroup> DRAWER_GROUP_CAPABILITY = null;
	
	@Override
	public int getDrawerCount() {

		return this.inv.getSlots();
	}

	@Optional.Method(modid = RealFilingCabinet.STORAGEDRAWERS)
	@Override
	public IDrawer getDrawer(int slot) {

		return new CabinetData(this, slot);
	}

	@Override
	public int[] getAccessibleDrawerSlots() {

		return new int[this.inv.getSlots()];
	}
} public class BotaniaRFC {
	
	private static final NavigableMap<Integer, String> manaSuffixes = new TreeMap();
	
	public static Item manaFolder;
	public static Block manaCabinet;
	
	public static void initBlock() {
		
		manaCabinet = new BlockManaCabinet();
		GameRegistry.registerTileEntity(TileManaCabinet.class, "tileManaCabinet");
	}
	
	public static void initItem() {
		
		manaFolder = new ItemManaFolder();
	}
	
	public static void initManaFolder(RegistryEvent.Register<Item> event) {
		
		event.getRegistry().register(manaFolder);
		event.getRegistry().register(new ItemBlockMana(manaCabinet).setRegistryName(manaCabinet.getRegistryName()));
	}
	
	public static void initManaCabinet(RegistryEvent.Register<Block> event) {
		
		event.getRegistry().register(manaCabinet);
	}
	
	@SideOnly(Side.CLIENT)
	public static void initClient(ModelRegistryEvent event) {
		
		ModelLoader.setCustomModelResourceLocation(Item.getItemFromBlock(manaCabinet), 0, new ModelResourceLocation(manaCabinet.getRegistryName(), "inventory"));
		ModelLoader.setCustomModelResourceLocation(manaFolder, 0, new ModelResourceLocation(manaFolder.getRegistryName(), "inventory"));
		
		manaSuffixes.put(0, TextHelper.localize("tooltip." + RealFilingCabinet.MOD_ID + ".mana0"));
		manaSuffixes.put(120, TextHelper.localize("tooltip." + RealFilingCabinet.MOD_ID + ".mana120"));
		manaSuffixes.put(500, TextHelper.localize("tooltip." + RealFilingCabinet.MOD_ID + ".mana500"));
		manaSuffixes.put(2500, TextHelper.localize("tooltip." + RealFilingCabinet.MOD_ID + ".mana2500"));
		manaSuffixes.put(3000, TextHelper.localize("tooltip." + RealFilingCabinet.MOD_ID + ".mana3000"));
		manaSuffixes.put(6000, TextHelper.localize("tooltip." + RealFilingCabinet.MOD_ID + ".mana6000"));
		manaSuffixes.put(10000, TextHelper.localize("tooltip." + RealFilingCabinet.MOD_ID + ".mana10000"));
		manaSuffixes.put(15000, TextHelper.localize("tooltip." + RealFilingCabinet.MOD_ID + ".mana15000"));
		manaSuffixes.put(20000, TextHelper.localize("tooltip." + RealFilingCabinet.MOD_ID + ".mana20000"));
		manaSuffixes.put(500000, TextHelper.localize("tooltip." + RealFilingCabinet.MOD_ID + ".mana500000"));
		manaSuffixes.put(1000000, TextHelper.localize("tooltip." + RealFilingCabinet.MOD_ID + ".mana1000000"));
		manaSuffixes.put(10000000, TextHelper.localize("tooltip." + RealFilingCabinet.MOD_ID + ".mana10000000"));
		manaSuffixes.put(100000000, TextHelper.localize("tooltip." + RealFilingCabinet.MOD_ID + ".mana10000000"));
		manaSuffixes.put(1000000000, TextHelper.localize("tooltip." + RealFilingCabinet.MOD_ID + ".mana10000000"));
	}
	
	public static String formatMana(int value) {
		
		Entry<Integer, String> e = manaSuffixes.floorEntry(value);
		String suffix = e.getValue();
		
		return suffix;
	}
} public class ItemAspectFolder extends Item implements IFolder {
	
	private static final String TAG_ASPECT = "RFC_aspectType";
	private static final String TAG_ASPECT_COUNT = "RFC_aspectCount";
	private static final int MAX_COUNT = 10000;
	
	public ItemAspectFolder() {
		
		setRegistryName("folder_aspect");
		setTranslationKey(RealFilingCabinet.MOD_ID + ".aspectfolder");
		setMaxStackSize(1);
		setCreativeTab(TabRFC.instance);
	}
	
	@Override
	public void addInformation(ItemStack stack, World player, List list, ITooltipFlag whatisthis) {
		
		if (stack.hasTagCompound() && stack.getTagCompound().hasKey(TAG_ASPECT)) {
			Aspect asp = getAspectFromFolder(stack);
			int count = getAspectCount(stack);
			list.add(asp.getName() + " x" + count);
		}
		else
			list.add("<Empty>");
	}
	
	@Optional.Method(modid = "thaumcraft")
	public static boolean isAspectFolderEmpty(ItemStack stack) {
		
		return (!stack.hasTagCompound()) || (stack.hasTagCompound() && !stack.getTagCompound().hasKey(TAG_ASPECT));
	}
	
	@Optional.Method(modid = "thaumcraft")
	public static Aspect getAspectFromFolder(ItemStack stack) {
		
		return Aspect.getAspect(NBTUtils.getString(stack, TAG_ASPECT, ""));
	}
	
	@Optional.Method(modid = "thaumcraft")
	public static int getAspectCount(ItemStack stack) {
		
		return NBTUtils.getInt(stack, TAG_ASPECT_COUNT, 0);
	}
	
	@Optional.Method(modid = "thaumcraft")
	public static void setAspect(ItemStack stack, Aspect asp) {
		
		NBTUtils.setString(stack, TAG_ASPECT, asp.getTag());
	}
	
	@Optional.Method(modid = "thaumcraft")
	public static void setAspectCount(ItemStack stack, int amount) {
		
		NBTUtils.setInt(stack, TAG_ASPECT_COUNT, amount);
	}
	
	@Optional.Method(modid = "thaumcraft")
	public static void addAspect(ItemStack stack, int amount) {
		
		int current = getAspectCount(stack);
		setAspectCount(stack, current + amount);
	}
	
	@Optional.Method(modid = "thaumcraft")
	public static void removeAspect(ItemStack stack, int amount) {
		
		int current = getAspectCount(stack);
		setAspectCount(stack, Math.max(current - amount, 0));
	}
	
	public static int getMaxAmount() {
		
		return MAX_COUNT;
	}

	@Override
	public ItemStack isFolderEmpty(ItemStack stack) {

		if (getAspectCount(stack) == 0)
			return stack;
		
		return ItemStack.EMPTY;
	}
} public class ItemEmptyFolder extends Item implements IEmptyFolder {
	
	public enum FolderType {
		NORMAL,
		DURA,
		MOB,
		FLUID,
		NBT;
	}
	
	public ItemEmptyFolder() {
		
		setRegistryName("emptyfolder");
		setTranslationKey(RealFilingCabinet.MOD_ID + ".emptyfolder");
		setMaxStackSize(8);
		setHasSubtypes(true);
		setMaxDamage(0);
		setCreativeTab(TabRFC.instance);
	}
	
	@Override
	public String getTranslationKey(ItemStack stack) {
		
		return getTranslationKey() + "_" + FolderType.values()[stack.getItemDamage()].toString().toLowerCase();
	}
	
	@Override
	@SideOnly(Side.CLIENT)
	public void getSubItems(CreativeTabs tab, NonNullList<ItemStack> list) {
		
		if (isInCreativeTab(tab)) {
			for (int i = 0; i < FolderType.values().length; ++i)
				list.add(new ItemStack(this, 1, i));
		}
	}
	
	@Override
	public void addInformation(ItemStack stack, World player, List list, ITooltipFlag whatisthis) {
	
		switch(stack.getItemDamage())
		{
			case 1: list.add(TextHelper.localize("tooltip." + RealFilingCabinet.MOD_ID + ".emptyfolder1")); return;
			case 2: list.add(TextHelper.localize("tooltip." + RealFilingCabinet.MOD_ID + ".emptyfolder2")); 
			if (!ConfigRFC.mobUpgrade)
				list.add(TextHelper.localize("message." + RealFilingCabinet.MOD_ID + ".disabled")); return;
			case 3: list.add(TextHelper.localize("tooltip." + RealFilingCabinet.MOD_ID + ".emptyfolder3")); return;
			default: list.add(TextHelper.localize("tooltip." + RealFilingCabinet.MOD_ID + ".emptyfolder0"));
		}
	}
	
	@Override
    public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand) {
        
		ItemStack stack = player.getHeldItemMainhand();
		if (!stack.isEmpty() && stack.getItemDamage() != FolderType.FLUID.ordinal())
			return ActionResult.newResult(EnumActionResult.PASS, stack);
		
		RayTraceResult rtr = rayTrace(world, player, true);
		if (rtr == null)
			return ActionResult.newResult(EnumActionResult.PASS, stack);
		
		if (!MobUtils.canPlayerChangeStuffHere(world, player, stack, rtr.getBlockPos(), rtr.sideHit))
			return ActionResult.newResult(EnumActionResult.PASS, stack);
		
		else {
			if (rtr.typeOfHit == RayTraceResult.Type.BLOCK) {
				
				BlockPos pos = rtr.getBlockPos();			
				Block block = world.getBlockState(pos).getBlock();
				int l = world.getBlockState(pos).getBlock().getMetaFromState(world.getBlockState(pos));
				
				if ((block instanceof BlockLiquid || block instanceof IFluidBlock) && l == 0) {
					if (!world.isRemote) {
						Fluid fluid = FluidRegistry.lookupFluidForBlock(block);
						if (fluid != null) {
							ItemStack newFolder = new ItemStack(RFCItems.folder, 1, 4);
							if (ItemFolder.setObject(newFolder, new FluidStack(fluid, 1000))) {							
								ItemHandlerHelper.giveItemToPlayer(player, newFolder);
								world.setBlockToAir(pos);
								stack.shrink(1);
							}
						}
					}
					return ActionResult.newResult(EnumActionResult.SUCCESS, stack);
				}
			}
		}
		return ActionResult.newResult(EnumActionResult.PASS, stack);
    }
	
	@Override
	public boolean itemInteractionForEntity(ItemStack stack, EntityPlayer player, EntityLivingBase target, EnumHand hand) {
		
		if (!player.world.isRemote && stack.getItemDamage() == FolderType.MOB.ordinal()) {
			if (!ConfigRFC.mobUpgrade) return false;
			String entityblacklist = target.getClass().getSimpleName();
			for (String toBlacklist : ConfigRFC.mobFolderBlacklist) {
				if (toBlacklist.contains(entityblacklist))
					return false;
			}
			
			ItemStack newFolder = new ItemStack(RFCItems.folder, 1, 3);
			if (ItemFolder.setObject(newFolder, target)) {
				if (!player.inventory.addItemStackToInventory(newFolder))
					player.dropItem(newFolder, true);
				stack.shrink(1);
				MobUtils.dropMobEquips(player.world, target);
				target.setDead();
			}
			return true;
		}
		return false;
	}
} public class ItemFilter extends Item {

	public ItemFilter() {
		
		setRegistryName("filter");
		setTranslationKey(RealFilingCabinet.MOD_ID + ".filter");
		setMaxStackSize(16);
		setCreativeTab(TabRFC.instance);
	}
	
	public void addInformation(ItemStack stack, EntityPlayer player, List list, boolean whatisthis) {
		
		list.add(TextHelper.localize("tooltip." + RealFilingCabinet.MOD_ID + ".itemfilter"));
	}
} public class ItemFolder extends Item implements IFolder {
	
	public static int extractSize = 0; // TODO: Figure out how to move this to CapabilityFolder
	
	public enum FolderType {
		NORMAL,
		ENDER,
		DURA,
		MOB,
		FLUID,
		NBT;
	}

	public ItemFolder() {
		
		setRegistryName("folder");
		setTranslationKey(RealFilingCabinet.MOD_ID + ".folder");
		setHasSubtypes(true);
		setMaxStackSize(1);
	}
	
	@Override
	public NBTTagCompound getNBTShareTag(ItemStack stack) {
		
		if(!stack.hasCapability(CapabilityProviderFolder.FOLDER_CAP, null))
			return super.getNBTShareTag(stack);
		
		NBTTagCompound tag = stack.hasTagCompound() ? stack.getTagCompound().copy() : new NBTTagCompound();
		tag.setTag("folderCap", stack.getCapability(CapabilityProviderFolder.FOLDER_CAP, null).serializeNBT());
		LogRFC.debug("Sharing tag: " + tag.toString());
		return tag;
	}
	
	@Override
	public String getTranslationKey(ItemStack stack) {
		
		return getTranslationKey() + "_" + FolderType.values()[stack.getItemDamage()].toString().toLowerCase();
	}
	
	@Override
	public void addInformation(ItemStack stack, World player, List<String> list, ITooltipFlag whatisthis) {
		
		if(stack.hasCapability(CapabilityProviderFolder.FOLDER_CAP, null)) // Direction doesn't really matter here.
			stack.getCapability(CapabilityProviderFolder.FOLDER_CAP, null).addTooltips(player, list, whatisthis);
	}
	
	public ItemStack getContainerItem(ItemStack stack) {
		
		if(!stack.hasCapability(CapabilityProviderFolder.FOLDER_CAP, null))
			return ItemStack.EMPTY;
		
		CapabilityFolder cap = stack.getCapability(CapabilityProviderFolder.FOLDER_CAP, null);
		long count = cap.getCount();
		long extract = 0;
		if (count > 0 && cap.isItemStack())
			extract = Math.min(cap.getItemStack().getMaxStackSize(), count);
		
		if (NBTUtils.getBoolean(stack, StringLibs.RFC_TAPED, false))
			return ItemStack.EMPTY;
		
		ItemStack copy = stack.copy();
		if (stack.getItemDamage() == FolderType.DURA.ordinal() && count == 0) // TODO: This works with 0 items? Might want to test this later
			setRemSize(copy, 0);

		remove(copy, extract);
		extractSize = (int)extract;
		
		return copy;
	}
	
	public boolean hasContainerItem(ItemStack stack) {
		
		return !getContainerItem(stack).isEmpty();
	}
	
	public static String getFolderDisplayName(ItemStack stack) {
		
		if(stack.hasCapability(CapabilityProviderFolder.FOLDER_CAP, null))
			return stack.getCapability(CapabilityProviderFolder.FOLDER_CAP, null).getDisplayName();
		
		return "";
	}
	
	public static int getFileMeta(ItemStack stack) {
		
		if(stack.hasCapability(CapabilityProviderFolder.FOLDER_CAP, null)) {
			CapabilityFolder cap = stack.getCapability(CapabilityProviderFolder.FOLDER_CAP, null);
			if(cap.isFluidStack()) {
				return cap.getItemStack().getItemDamage();
			} else if(cap.isBlock()) {
				return cap.getBlock().getBlock().getMetaFromState(cap.getBlock());
			}
		}
		return 0;
	}
	
	public static void setFileMeta(ItemStack stack, int meta) {
		
		if(stack.hasCapability(CapabilityProviderFolder.FOLDER_CAP, null)) {
			CapabilityFolder cap = stack.getCapability(CapabilityProviderFolder.FOLDER_CAP, null);
			if(cap.isFluidStack()) {
				cap.getItemStack().setItemDamage(meta);
			} else if(cap.isBlock()) {
				cap.setContents(cap.getBlock().getBlock().getMetaFromState(cap.getBlock()));
			}
		}
	}
	
	public static void setFileSize(ItemStack stack, long count) {
		
		if(stack.hasCapability(CapabilityProviderFolder.FOLDER_CAP, null))
			stack.getCapability(CapabilityProviderFolder.FOLDER_CAP, null).setCount(count);
	}
	
	public static long getFileSize(ItemStack stack) {
		
		if(stack.hasCapability(CapabilityProviderFolder.FOLDER_CAP, null))
			return stack.getCapability(CapabilityProviderFolder.FOLDER_CAP, null).getCount();
		
		return 0;
	}
	
	public static void remove(ItemStack stack, long count) {
		
		long current = getFileSize(stack);
		setFileSize(stack, Math.max(current - count, 0));
	}
	
	// trial new way of adding to contents of folder, while also returning the remainder in cases of reaching the storage limit
	public static ItemStack insert(ItemStack folder, ItemStack items, boolean simulate) {
		
		if (folder.hasCapability(CapabilityProviderFolder.FOLDER_CAP, null))
			return folder.getCapability(CapabilityProviderFolder.FOLDER_CAP, null).insertItems(items, simulate);
		
		return items;
	}
	
	/*
	 * Maybe find a better way of adding things?
	 */
	@Deprecated
	public static void add(ItemStack stack, long count) {
		
		long current = getFileSize(stack);
		setFileSize(stack, current + count);
	}
	
	public static void setRemSize(ItemStack stack, int count) {
		
		if(stack.hasCapability(CapabilityProviderFolder.FOLDER_CAP, null))
			stack.getCapability(CapabilityProviderFolder.FOLDER_CAP, null).setRemaining(count);
	}
	
	public static int getRemSize(ItemStack stack) {
		
		if(stack.hasCapability(CapabilityProviderFolder.FOLDER_CAP, null))
			return stack.getCapability(CapabilityProviderFolder.FOLDER_CAP, null).getRemaining();
		
		return 0;
	}
	
	public static void addRem(ItemStack stack, int count) {
		
		int current = getRemSize(stack);
		setRemSize(stack, current + count);
	}
	
	public static void remRem(ItemStack stack, int count) {
		
		int current = getRemSize(stack);
		setRemSize(stack, Math.max(current - count, 0));
	}
	
	public static NBTTagCompound getItemTag(ItemStack stack) {
		
		if(stack.hasCapability(CapabilityProviderFolder.FOLDER_CAP, null)) {
			
			CapabilityFolder cap = stack.getCapability(CapabilityProviderFolder.FOLDER_CAP, null);
			if(cap.isItemStack())
				return cap.getItemStack().getTagCompound();
		}
		
		return new NBTTagCompound();
	}
	
	public static void setItemTag(ItemStack stack, NBTTagCompound tag) {
		
		if(stack.hasCapability(CapabilityProviderFolder.FOLDER_CAP, null)) {
			CapabilityFolder cap = stack.getCapability(CapabilityProviderFolder.FOLDER_CAP, null);
			
			if(cap.isItemStack())
				cap.getItemStack().setTagCompound(tag);
		}
	}

	public static Object getObject(ItemStack folder) {

		if(folder.hasCapability(CapabilityProviderFolder.FOLDER_CAP, null))
			return folder.getCapability(CapabilityProviderFolder.FOLDER_CAP, null).getContents();
		
		return null;
	}

	public static boolean setObject(ItemStack folder, Object object) {
		
		if(folder.hasCapability(CapabilityProviderFolder.FOLDER_CAP, null) && folder.getCapability(CapabilityProviderFolder.FOLDER_CAP, null).getContents() == null)
			return folder.getCapability(CapabilityProviderFolder.FOLDER_CAP, null).setContents(object);
		
		return false;
	}
	
//	@Override
//	public boolean itemInteractionForEntity(ItemStack stack, EntityPlayer player, EntityLivingBase target, EnumHand hand) {
//		
//		if (target.isChild() && !(target instanceof EntityZombie))
//			return false;
//		
//		if (target instanceof EntityCabinet)
//			return false;
//		
//		if (target instanceof IEntityOwnable && ((IEntityOwnable)target).getOwner() != null)
//			return false;
//		
//		String entityblacklist = target.getClass().getSimpleName();
//		for (String toBlacklist : ConfigRFC.mobFolderBlacklist) {
//			if (toBlacklist.contains(entityblacklist))
//				return false;
//		}
//		ItemStack folder = player.getHeldItemMainhand();
//		if (!folder.isEmpty() && folder.getItem() == this && folder.getItemDamage() == FolderType.MOB.ordinal()) {
//			if (!ConfigRFC.mobUpgrade) return false;
//			
//			if (getObject(folder) != null) {
//				ResourceLocation res = EntityList.getKey(target);
//				if (getObject(folder).equals(res.toString()))
//				{
//					add(folder, 1);
//					MobUtils.dropMobEquips(player.world, target);
//					target.setDead();
//				}
//			}
//			return true;
//		}
//		return false;
//	}
	
	@Override
	public EnumActionResult onItemUse(EntityPlayer player, World world, BlockPos pos, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ) {
		
		ItemStack stack = player.getHeldItem(hand);
		if (getObject(stack) != null) {
			if (stack.getItemDamage() < 2) {
				if (((ItemStack)getObject(stack)).getItem() instanceof ItemBlock) {	
					long count = ItemFolder.getFileSize(stack);
					if (stack.getItemDamage() == FolderType.ENDER.ordinal() && !EnderUtils.preValidateEnderFolder(stack))
						return EnumActionResult.FAIL;
					
					if (count > 0) {
						ItemStack stackToPlace = new ItemStack(((ItemStack)getObject(stack)).getItem(), 1, ((ItemStack)getObject(stack)).getItemDamage());
						ItemStack savedfolder = player.getHeldItem(hand);
						
						player.setHeldItem(hand, stackToPlace);
						EnumActionResult ear = stackToPlace.onItemUse(player, world, pos, hand, side, hitX, hitY, hitZ);
						player.setHeldItem(hand, savedfolder);
						
						if (ear == EnumActionResult.SUCCESS) {
							if (!player.capabilities.isCreativeMode) {
								if (stack.getItemDamage() == FolderType.ENDER.ordinal() && !world.isRemote) {
									EnderUtils.syncToTile(EnderUtils.getTileLoc(stack), NBTUtils.getInt(stack, StringLibs.RFC_DIM, 0), NBTUtils.getInt(stack, StringLibs.RFC_SLOTINDEX, 0), 1, true);
									if (player instanceof FakePlayer)
										EnderUtils.syncToFolder(EnderUtils.getTileLoc(stack), stack, NBTUtils.getInt(stack, StringLibs.RFC_SLOTINDEX, 0));
								}
								else
									remove(stack, 1);
							}
							return EnumActionResult.SUCCESS;
						}
					}
				}
			}
			if (stack.getItemDamage() == 3) {
				if (MobUtils.spawnEntityFromFolder(world, player, stack, pos, side))
					return EnumActionResult.SUCCESS;
			}
			if (stack.getItemDamage() == 4) {
				if (!(getObject(stack) instanceof FluidStack))
					return EnumActionResult.PASS;
				
				if (FluidUtils.doPlace(world, player, stack, pos, side))
					return EnumActionResult.SUCCESS;
			}
		}
		return EnumActionResult.PASS;
	}
	
	@Override
    public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand) {
        
		ItemStack stack = player.getHeldItem(hand);
		if (!stack.isEmpty() && stack.getItem() != this)
			return ActionResult.newResult(EnumActionResult.PASS, stack);

		if (stack.getItemDamage() == FolderType.DURA.ordinal()) {
			NBTTagCompound tag = stack.getTagCompound();
			tag.setBoolean(StringLibs.RFC_IGNORENBT, !tag.getBoolean(StringLibs.RFC_IGNORENBT));
			return ActionResult.newResult(EnumActionResult.SUCCESS, stack);
		}
		if (!stack.isEmpty() && stack.getItemDamage() != FolderType.FLUID.ordinal())
			return ActionResult.newResult(EnumActionResult.PASS, stack);
		
		RayTraceResult rtr = rayTrace(world, player, true);
		if (rtr == null)
			return ActionResult.newResult(EnumActionResult.PASS, stack);
		
		if (!MobUtils.canPlayerChangeStuffHere(world, player, stack, rtr.getBlockPos(), rtr.sideHit))
			return ActionResult.newResult(EnumActionResult.PASS, stack);
		
		else {
			if (rtr.typeOfHit == RayTraceResult.Type.BLOCK) {
				BlockPos pos = rtr.getBlockPos();
				if (FluidUtils.doDrain(world, player, stack, pos, rtr.sideHit))
					return ActionResult.newResult(EnumActionResult.SUCCESS, stack);
			}
		}
		return ActionResult.newResult(EnumActionResult.PASS, stack);
    }
	
	@Override
    public boolean onEntitySwing(EntityLivingBase entityLiving, ItemStack stack) {
        
		if (entityLiving instanceof EntityPlayer && entityLiving.isSneaking()) {
			if (!stack.isEmpty() && stack.getItem() == this) {
				if (stack.getItemDamage() == 4) {	
					NBTTagCompound tag = stack.getTagCompound();
					tag.setBoolean(StringLibs.RFC_PLACEMODE, !tag.getBoolean(StringLibs.RFC_PLACEMODE));
					return true;
				}
			}
		}
		return false;
    }
	
	@Override
	public void onUpdate(ItemStack stack, World world, Entity entity, int itemSlot, boolean isSelected) {
		
		if (!stack.hasCapability(CapabilityProviderFolder.FOLDER_CAP, null) || !stack.hasTagCompound() || !stack.getTagCompound().hasKey("folderCap", 10))
			return;
		
		CapabilityFolder cap = stack.getCapability(CapabilityProviderFolder.FOLDER_CAP, null);
		LogRFC.debug("Deserializing: " + stack.getTagCompound().getCompoundTag("folderCap").toString());
		cap.deserializeNBT(stack.getTagCompound().getCompoundTag("folderCap"));
		stack.getTagCompound().removeTag("folderCap");
		
		if (stack.getTagCompound().getSize() <= 0)
			stack.setTagCompound(null);
	}
	
	@Override
	public boolean shouldCauseReequipAnimation(ItemStack oldstack, ItemStack newstack, boolean slotchanged) {
		
		return oldstack.getItem() != newstack.getItem() || (oldstack.getItem() == newstack.getItem() && oldstack.getItemDamage() != newstack.getItemDamage());
	}
	
	@Override
	public ItemStack isFolderEmpty(ItemStack stack) {

		switch (stack.getItemDamage()) 
		{
			case 0: return new ItemStack(RFCItems.emptyFolder, 1, 0);
			case 2: return new ItemStack(RFCItems.emptyFolder, 1, 1);
			case 3: return new ItemStack(RFCItems.emptyFolder, 1, 2);
			case 4: return new ItemStack(RFCItems.emptyFolder, 1, 3);
			case 5: return new ItemStack(RFCItems.emptyFolder, 1, 4);
		}
		return ItemStack.EMPTY;
	}
} public class ItemUpgrades extends Item implements IUpgrades {
	
	public enum UpgradeType {
		CREATIVE,
		CRAFTING,
		ENDER,
		OREDICT,
		MOB,
		FLUID,
		LIFE,
		SMELTING;
	}
	
	public ItemUpgrades() {
		
		setRegistryName("upgrade");
		setTranslationKey(RealFilingCabinet.MOD_ID + ".upgrade");
		setHasSubtypes(true);
		setMaxDamage(0);
		setMaxStackSize(16);
		setCreativeTab(TabRFC.instance);
	}
	
	@Override
	public String getTranslationKey(ItemStack stack) {
		
		return getTranslationKey() + "_" + UpgradeType.values()[stack.getItemDamage()].toString().toLowerCase();
	}
	
	@Override
	public void addInformation(ItemStack stack, World player, List list, ITooltipFlag whatisthis) {
		
		if (stack.getItemDamage() == UpgradeType.CRAFTING.ordinal() && !ConfigRFC.craftingUpgrade)
			list.add(TextHelper.localize("message." + RealFilingCabinet.MOD_ID + ".disabled"));
		if (stack.getItemDamage() == UpgradeType.ENDER.ordinal() && !ConfigRFC.enderUpgrade)
			list.add(TextHelper.localize("message." + RealFilingCabinet.MOD_ID + ".disabled"));
		if (stack.getItemDamage() == UpgradeType.OREDICT.ordinal() && !ConfigRFC.oreDictUpgrade)
			list.add(TextHelper.localize("message." + RealFilingCabinet.MOD_ID + ".disabled"));
		if (stack.getItemDamage() == UpgradeType.MOB.ordinal() && !ConfigRFC.mobUpgrade)
			list.add(TextHelper.localize("message." + RealFilingCabinet.MOD_ID + ".disabled"));
		if (stack.getItemDamage() == UpgradeType.FLUID.ordinal() && !ConfigRFC.fluidUpgrade)
			list.add(TextHelper.localize("message." + RealFilingCabinet.MOD_ID + ".disabled"));
		if (stack.getItemDamage() == UpgradeType.LIFE.ordinal() && !ConfigRFC.lifeUpgrade)
			list.add(TextHelper.localize("message." + RealFilingCabinet.MOD_ID + ".disabled"));
		if (stack.getItemDamage() == UpgradeType.SMELTING.ordinal() && !ConfigRFC.smeltingUpgrade)
			list.add(TextHelper.localize("message." + RealFilingCabinet.MOD_ID + ".disabled"));
	}
	
	@Override
	@SideOnly(Side.CLIENT)
	public void getSubItems(CreativeTabs tab, NonNullList<ItemStack> list) {
		
		if (isInCreativeTab(tab)) {
			for (int i = 0; i < UpgradeType.values().length; ++i)
				list.add(new ItemStack(this, 1, i));
		}
	}
	
	@SideOnly(Side.CLIENT)
    public EnumRarity getRarity(ItemStack stack) {
    	
		switch (stack.getItemDamage())
		{
			case 0: return EnumRarity.EPIC;
			case 2: return EnumRarity.RARE;
			default: return EnumRarity.COMMON;
		}
    }

	@Override
	public boolean canApply(TileEntityRFC tile, ItemStack upgrade, EntityPlayer player) {

		switch (upgrade.getItemDamage()) {
			case 1: if (!ConfigRFC.craftingUpgrade) return false;
			case 2: if (!ConfigRFC.enderUpgrade) return false;
			case 3: if (!ConfigRFC.oreDictUpgrade) return false;
			case 4: if (!ConfigRFC.mobUpgrade) return false;
			case 5: if (!ConfigRFC.fluidUpgrade) return false;
			case 6: if (!ConfigRFC.lifeUpgrade) return false;
			case 7: if (!ConfigRFC.smeltingUpgrade) return false; 
		}
		
		if (upgrade.getItemDamage() == UpgradeType.CREATIVE.ordinal()) {
			return !UpgradeHelper.isCreative(tile);
		}
		if (upgrade.getItemDamage() == UpgradeType.ENDER.ordinal()) {
			for (ItemStack stack : tile.getInventory().getStacks()) {
				if (stack.isEmpty()) 
					continue;
				if (!stack.isEmpty() && stack.getItem() == RFCItems.folder && stack.getItemDamage() == 0)
					continue;
				else {
					player.sendStatusMessage(new TextComponentString(TextHelper.localize("message." + RealFilingCabinet.MOD_ID + ".errorEnder")), true);
					return false;
				}
			}
		}
		return true;
	}
} public class PacketMouse implements IMessage {
	
	private boolean next;
	
	public PacketMouse() {}
	
	public PacketMouse(boolean next) {
		
		this.next = next;
	}

	@Override
	public void fromBytes(ByteBuf buf) {

		next = buf.readBoolean();
	}

	@Override
	public void toBytes(ByteBuf buf) {

		buf.writeBoolean(next);
	}
	
	public static class Handler implements IMessageHandler<PacketMouse, IMessage> {

		@Override
		public IMessage onMessage(PacketMouse message, MessageContext ctx) {

			FMLCommonHandler.instance().getWorldThread(ctx.netHandler).addScheduledTask(new Runnable() {
				
				@Override
				public void run() {
					
					handle(message, ctx);
				}
			});
			return null;
		}
		
		private void handle(PacketMouse message, MessageContext ctx) {
			
			EntityPlayerMP player = ctx.getServerHandler().player;
			ItemStack stack = player.getHeldItemMainhand();
			if (!stack.isEmpty() && stack.getItem() == RFCItems.suitcase) {
				((ItemSuitcase)stack.getItem()).cycleIndex(stack, message.next);
			}
		}
	}
} public class RFCPacketHandler {

	public static final SimpleNetworkWrapper INSTANCE = NetworkRegistry.INSTANCE.newSimpleChannel("RealFilingCabinet".toLowerCase());
	private static byte packetId = 0;
	
	public static void init() {
		
		INSTANCE.registerMessage(PacketMouse.Handler.class, PacketMouse.class, packetId++, Side.SERVER);
//		INSTANCE.registerMessage(RFCTileMessage.Handler.class, RFCTileMessage.class, packetId++, Side.SERVER);
	}
	
	public static void initClient() {
		
		INSTANCE.registerMessage(PacketRFC.Handler.class, PacketRFC.class, packetId++, Side.CLIENT);
	}
}
import thaumcraft.api.aspects.Aspect;
import com.bafomdad.realfilingcabinet.NewConfigRFC.ConfigRFC;
import com.bafomdad.realfilingcabinet.RealFilingCabinet;
import com.bafomdad.realfilingcabinet.blocks.tiles.TileEntityRFC;
import com.bafomdad.realfilingcabinet.init.*;
import com.bafomdad.realfilingcabinet.integration.BotaniaRFC;
import com.bafomdad.realfilingcabinet.items.ItemAspectFolder;
import com.bafomdad.realfilingcabinet.items.ItemEmptyFolder;
import com.bafomdad.realfilingcabinet.items.ItemFilter;
import com.bafomdad.realfilingcabinet.items.ItemFolder;
import com.bafomdad.realfilingcabinet.items.ItemUpgrades;
import com.bafomdad.realfilingcabinet.network.PacketMouse;
import com.bafomdad.realfilingcabinet.network.RFCPacketHandler;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.client.renderer.color.IItemColor;
import net.minecraft.client.renderer.color.ItemColors;
import net.minecraft.entity.item.EntityItemFrame;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.EnumDyeColor;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.client.event.ColorHandlerEvent;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.event.MouseEvent;
import net.minecraftforge.client.event.RenderItemInFrameEvent;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.common.config.Config;
import net.minecraftforge.common.config.ConfigManager;
import net.minecraftforge.fml.client.event.ConfigChangedEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
package com.bafomdad.realfilingcabinet.events;




public class EventHandlerClient {
	
	@SubscribeEvent
	public void registerModels(ModelRegistryEvent event) {
		
		if (RealFilingCabinet.botaniaLoaded && ConfigRFC.botaniaIntegration)
			BotaniaRFC.initClient(event);
		
		// BLOCKS
		ModelLoader.setCustomModelResourceLocation(Item.getItemFromBlock(RFCBlocks.blockRFC), 0, new ModelResourceLocation(RFCBlocks.blockRFC.getRegistryName(), "inventory"));
		
		// ITEMS
		for (int i = 0; i < ItemEmptyFolder.FolderType.values().length; ++i)
			ModelLoader.setCustomModelResourceLocation(RFCItems.emptyFolder, i, new ModelResourceLocation(RFCItems.emptyFolder.getRegistryName() + "_" + ItemEmptyFolder.FolderType.values()[i].toString().toLowerCase(), "inventory"));
		
		for (int i = 0; i < ItemFolder.FolderType.values().length; ++i)
			ModelLoader.setCustomModelResourceLocation(RFCItems.folder, i, new ModelResourceLocation(RFCItems.folder.getRegistryName() + "_" + ItemFolder.FolderType.values()[i].toString().toLowerCase(), "inventory"));
		
		for (int i = 0; i < ItemUpgrades.UpgradeType.values().length; ++i)
			ModelLoader.setCustomModelResourceLocation(RFCItems.upgrades, i, new ModelResourceLocation(RFCItems.upgrades.getRegistryName() + "_" + ItemUpgrades.UpgradeType.values()[i].toString().toLowerCase(), "inventory"));
		
		for (int i = 0; i < EnumDyeColor.values().length; ++i) {
			ModelLoader.setCustomModelResourceLocation(RFCItems.emptyDyedFolder, i, new ModelResourceLocation(RFCItems.emptyDyedFolder.getRegistryName(), "inventory"));
			ModelLoader.setCustomModelResourceLocation(RFCItems.dyedFolder, i, new ModelResourceLocation(RFCItems.dyedFolder.getRegistryName(), "inventory"));
		}
		ModelLoader.setCustomModelResourceLocation(RFCItems.magnifyingGlass, 0, new ModelResourceLocation(RFCItems.magnifyingGlass.getRegistryName(), "inventory"));
		ModelLoader.setCustomModelResourceLocation(RFCItems.whiteoutTape, 0, new ModelResourceLocation(RFCItems.whiteoutTape.getRegistryName(), "inventory"));
		ModelLoader.setCustomModelResourceLocation(RFCItems.filter, 0, new ModelResourceLocation(RFCItems.filter.getRegistryName(), "inventory"));
		ModelLoader.setCustomModelResourceLocation(RFCItems.debugger, 0, new ModelResourceLocation(RFCItems.debugger.getRegistryName(), "inventory"));
		ModelLoader.setCustomModelResourceLocation(RFCItems.mysteryFolder, 0, new ModelResourceLocation(RFCItems.mysteryFolder.getRegistryName(), "inventory"));
//		ModelLoader.setCustomModelResourceLocation(RFCItems.autoFolder, 0, new ModelResourceLocation(RFCItems.autoFolder.getRegistryName(), "inventory"));
//		ModelLoader.setCustomModelResourceLocation(RFCItems.autoFolder, 1, new ModelResourceLocation(RFCItems.autoFolder.getRegistryName(), "inventory"));
		ModelLoader.setCustomModelResourceLocation(RFCItems.suitcase, 0, new ModelResourceLocation(RealFilingCabinet.MOD_ID + ":itemsuitcase", "inventory"));
		
		ModelLoader.setCustomModelResourceLocation(RFCItems.keys, 0, new ModelResourceLocation(RFCItems.keys.getRegistryName() + "_" + RFCItems.keys.keyTypes[0], "inventory"));
		ModelLoader.setCustomModelResourceLocation(RFCItems.keys, 1, new ModelResourceLocation(RFCItems.keys.getRegistryName() + "_" + RFCItems.keys.keyTypes[1], "inventory"));
		
		if (RealFilingCabinet.tcLoaded && ConfigRFC.tcIntegration) {
			ModelLoader.setCustomModelResourceLocation(RFCItems.aspectFolder, 0, new ModelResourceLocation(RFCItems.aspectFolder.getRegistryName(), "inventory"));
			ModelLoader.setCustomModelResourceLocation(Item.getItemFromBlock(RFCBlocks.blockAC), 0, new ModelResourceLocation(RFCBlocks.blockAC.getRegistryName(), "inventory"));
		}
	}
	
	@SubscribeEvent
	public void onRenderItemFrame(RenderItemInFrameEvent event) {
		
		if (!event.getItem().isEmpty() && event.getItem().getItem() instanceof ItemFilter) {
			EntityItemFrame frame = event.getEntityItemFrame();
			int rotation = frame.getRotation();
			
			TileEntity tile = frame.getEntityWorld().getTileEntity(new BlockPos(frame.posX, frame.posY - 1, frame.posZ));
			if (tile instanceof TileEntityRFC) {
				TileEntityRFC tileRFC = (TileEntityRFC)tile;
				ItemStack stack = tileRFC.getInventory().getStackFromFolder(rotation);
				if (!stack.isEmpty()) {
					event.setCanceled(true);
					GlStateManager.pushMatrix();
					GlStateManager.enableLighting();
					GlStateManager.rotate(180.0F, 1.0F, 0.0F, 0.0F);
					GlStateManager.rotate(180.0F, 0.0F, 0.0F, 1.0F);
					GlStateManager.rotate((frame.getRotation() % 8 * 2) * 180.0F / 8.0F, 0.0F, 0.0F, 1.0F);
					if (stack.getItem() instanceof ItemBlock)
						GlStateManager.scale(0.25F, 0.25F, 0.25F);
					else
						GlStateManager.scale(0.5F, 0.5F, 0.5F);
					Minecraft.getMinecraft().getRenderItem().renderItem(stack, ItemCameraTransforms.TransformType.NONE);
					GlStateManager.popMatrix();
				}
			}
		}
	}
	
	@SubscribeEvent
	public void handleMouseWheel(MouseEvent event) {
		
		if (event.getDwheel() != 0) {
			EntityPlayer player = Minecraft.getMinecraft().player;
			if (!player.isSneaking()) return;
			
			ItemStack suitcase = player.getHeldItemMainhand();
			if (!suitcase.isEmpty() && suitcase.getItem() == RFCItems.suitcase) {
				boolean next = (event.getDwheel() > 0) ? true : false;
				
				RFCPacketHandler.INSTANCE.sendToServer(new PacketMouse(next));