package projectzombie.entity.tileentity;

import bdf.types.BdfNamedList;
import bdf.types.BdfObject;
import gl_engine.vec.Vec2i;
import projectzombie.Main;
import projectzombie.init.Items;
import projectzombie.init.Tiles;
import projectzombie.inventory.Inventory;
import projectzombie.items.ItemBurnable;
import projectzombie.items.ItemCookable;
import projectzombie.items.ItemFlint;
import projectzombie.items.ItemSmeltable;
import projectzombie.items.modifier.ItemModifierDamage;
import projectzombie.menu.MenuInventoryStorage;
import projectzombie.menu.gui.GUIItemSlotGetter;
import projectzombie.util.ItemStack;
import projectzombie.util.TileState;
import projectzombie.world.chunk.Chunk;
import projectzombie.world.layer.Layer;

public class TileEntityCampfire extends TileEntity
{
	private ItemStack burning;
	private Inventory inventory;
	private int next_level;
	private int burn_time;
	private int cook_time;
	private int cook_slot;
	private int level;
	
	public TileEntityCampfire(BdfObject bdf) {
		BdfClassLoad(bdf);
	}
	
	public TileEntityCampfire(Vec2i pos) {
		inventory = new Inventory(8);
		burning = ItemStack.getEmpty();
	}
	
	@Override
	public void BdfClassLoad(BdfObject bdf) {
		super.BdfClassLoad(bdf);
		
		BdfNamedList nl = bdf.getNamedList();
		
		inventory = new Inventory(nl.get("inventory"));
		burning = new ItemStack(nl.get("burning"));
		
		burn_time = nl.get("burnTime").getInteger();
		cook_time = nl.get("cookTime").getInteger();
		cook_slot = nl.get("cookSlot").getInteger();
		next_level = nl.get("nextLevel").getInteger();
		level = nl.get("level").getInteger();
	}
	
	@Override
	public void BdfClassSave(BdfObject bdf) {
		super.BdfClassSave(bdf);
		
		BdfNamedList nl = bdf.getNamedList();
		
		inventory.BdfClassSave(nl.get("inventory"));
		burning.BdfClassSave(nl.get("burning"));
		
		nl.set("burnTime", bdf.newObject().setInteger(burn_time));
		nl.set("cookTime", bdf.newObject().setInteger(cook_time));
		nl.set("cookSlot", bdf.newObject().setInteger(cook_slot));
		nl.set("nextLevel", bdf.newObject().setInteger(next_level));
		nl.set("level", bdf.newObject().setInteger(level));
	}
	
	private void updateTile() {
		chunk.setFrontTile(new TileState(Tiles.CAMPFIRE, (byte)level), getPos().xz().toInt());
	}
	
	private void checkForFuel()
	{
		for(int i=0;i<inventory.getSlotCount();i++)
		{
			ItemStack stack = inventory.getItem(i);
			
			if(stack.isEmpty()) {
				continue;
			}
			
			if(stack.item instanceof ItemBurnable)
			{
				stack.count -= 1;
				
				burning = stack.copy();
				burning.count = 1;
				
				burn_time = ((ItemBurnable)stack.item).getBurnTime(burning);
				
				if(level < 4)
				{
					level = 4;
					updateTile();
					
					Vec2i tpos = getPos().xz().toInt();
					
					if(chunk.getBackTile(tpos).tile == Tiles.GRASS) {
						chunk.setBackTile(Tiles.GRASS_BURNT.getDefaultState(), tpos);
					}
				}
				
				break;
			}
		}
	}
	
	@Override
	public void tick(Chunk chunk, Layer layer)
	{
		super.tick(chunk, layer);
		
		// Check for fuel if the fuel has run out
		if(burning.isEmpty())
		{
			// Check for fuel and possibly add it if its available
			checkForFuel();
			
			if(!burning.isEmpty()) {
				next_level = 1600;
			}
		}
		
		// Check if there is fuel
		// This could have changed since
		// the last check for fuel
		if(!burning.isEmpty())
		{
			burn_time -= 1;
			
			if(burn_time < 0)
			{
				burn_time = 0;
				burning.count = 0;
				
				for(ItemStack stack : ((ItemBurnable)burning.item).getBurnProducts(burning)) {
					inventory.addItem(stack);
				}
				
				checkForFuel();
			}
		}
		
		if(level > 0)
		{
			ItemStack stack = inventory.getItem(cook_slot);
			
			// Check for cookable items if things aren't being cooked
			if(stack.isEmpty() || !(stack.item instanceof ItemCookable))
			{
				cook_time = 1600;
				
				for(int i=0;i<inventory.getSlotCount();i++)
				{
					ItemStack check = inventory.getItem(i);
					
					if(check.isEmpty()) {
						continue;
					}
					
					if(check.item instanceof ItemCookable) {
						cook_slot = i;
						cook_time = 1600;
						break;
					}
				}
			}
			
			// Cook the item thats currently being cooked
			// and process them if they have finished cooking.
			// Make sure any non-cookable items don't get cooked.
			
			stack = inventory.getItem(cook_slot);
			
			if(!stack.isEmpty() && stack.item instanceof ItemCookable)
			{
				cook_time -= 1;
				
				if(cook_time < 0)
				{
					stack.count -= 1;
					cook_time = 1600;
					
					ItemStack[] result = ((ItemCookable)stack.item).getCookProducts(stack);
					
					for(int i=0;i<result.length;i++) {
						inventory.addItem(result[i]);
					}
				}
			}
		}
		
		next_level -= 1;
		
		// Make the fire burn brighter/darker based on whether there is fuel or not
		if(next_level < 0)
		{
			if(burning.isEmpty())
			{
				next_level = 200;
				level -= 1;
				
				if(level < 0) {
					level = 0;
				}
				
				else {
					updateTile();
				}
			}
			
			else
			{
				next_level = 1600;
				level += 1;
				
				if(level > 16) {
					level = 16;
				}
				
				else {
					updateTile();
				}
			}
		}
	}
	
	public Inventory getInventory() {
		return inventory;
	}

	public void onOpened() {
		Main.menu = new MenuInventoryStorage(Main.menu, inventory, new GUIItemSlotGetter() {
			
			@Override
			public void setItemStack(ItemStack stack) {
			}
			
			@Override
			public boolean isAllowed(ItemStack stack)
			{
				if(stack.item instanceof ItemBurnable) {
					return true;
				}
				
				if(stack.item instanceof ItemCookable) {
					return true;
				}
				
				return false;
			}
			
			@Override
			public ItemStack getItemStack() {
				return null;
			}
		});
	}
}
