package common.item;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Queue;
import java.util.Set;

import common.block.Block;
import common.block.BlockDynamicLiquid;
import common.block.BlockLiquid;
import common.block.BlockStaticLiquid;
import common.collect.Sets;
import common.entity.npc.EntityNPC;
import common.init.BlockRegistry;
import common.init.Blocks;
import common.init.FluidRegistry;
import common.init.ItemRegistry;
import common.init.Items;
import common.init.SoundEvent;
import common.material.Material;
import common.model.Model;
import common.model.ModelProvider;
import common.model.ParticleType;
import common.util.BlockPos;
import common.util.HitPosition;
import common.util.Vec3i;
import common.world.State;
import common.world.World;
import common.world.AWorldServer;

public class ItemBucket extends Item
{
	private final boolean recursive;
    private final BlockDynamicLiquid liquid;
    
	private static boolean test(AWorldServer world, BlockPos pos, Set<Block> blocks, int max, BlockPos origin, int radius) {
		if(pos.getY() < 0 || pos.getY() > max)
			return false;
		if(pos.getX() < origin.getX() - radius || pos.getX() > origin.getX() + radius)
			return false;
		if(pos.getY() < origin.getY() - radius || pos.getY() > origin.getY() + radius)
			return false;
		if(pos.getZ() < origin.getZ() - radius || pos.getZ() > origin.getZ() + radius)
			return false;
		Block block = world.getState(pos).getBlock();
		return blocks == null ? block instanceof BlockLiquid : blocks.contains(block);
	}
	
	private static void setRecursive(AWorldServer world, BlockPos origin, int radius, BlockStaticLiquid liquid) {
        Queue<BlockPos> queue = new ArrayDeque<BlockPos>();
        Set<BlockPos> visited = new HashSet<BlockPos>();
        List<Vec3i> dirs = new ArrayList<Vec3i>();
        Set<Block> blocks = liquid == null ? null : Sets.newHashSet(FluidRegistry.getDynamicBlock(liquid), liquid, Blocks.air);
        State state = (liquid == null ? Blocks.air : liquid).getState();
        int max = 511;
    	
        if(liquid != null) {
        	dirs.add(new Vec3i(1, 0, 0));
            dirs.add(new Vec3i(-1, 0, 0));
            dirs.add(new Vec3i(0, 0, 1));
            dirs.add(new Vec3i(0, 0, -1));
            dirs.add(new Vec3i(0, -1, 0));
            max = Math.min(origin.getY(), max);
        }
        else {
	        dirs.add(new Vec3i(0, -1, 0));
	        dirs.add(new Vec3i(0, 1, 0));
	        dirs.add(new Vec3i(-1, 0, 0));
	        dirs.add(new Vec3i(1, 0, 0));
	        dirs.add(new Vec3i(0, 0, -1));
	        dirs.add(new Vec3i(0, 0, 1));
        }

    	for(int x = -1; x <= 1; x++) {
        	for(int y = -1; y <= 1; y++) {
            	for(int z = -1; z <= 1; z++) {
            		BlockPos pos = new BlockPos(origin.getX() + x, origin.getY() + y, origin.getZ() + z);
                    if (!visited.contains(pos)) {
                    	if(test(world, pos, blocks, max, origin, radius))
                    		queue.add(pos);
                        visited.add(pos);
                    }
            	}
        	}
    	}
    	BlockPos loc;
        while ((loc = queue.poll()) != null) {
        	world.setState(loc, state);
            for (Vec3i dir : dirs) {
            	BlockPos pos = loc.add(dir);
                if (!visited.contains(pos)) {
                    visited.add(pos);
                    if (test(world, pos, blocks, max, origin, radius))
                        queue.add(pos);
                }
            }
        }
    }

    public ItemBucket(BlockDynamicLiquid liquid, boolean recursive)
    {
        this.maxStackSize = liquid == null ? 16 : 1;
        this.liquid = liquid;
        this.recursive = recursive;
        this.setTab(CheatTab.tabTools);
//        if(!empty)
//            this.setHasSubtypes(true);
    }
    
    public BlockDynamicLiquid getLiquid() {
    	return this.liquid;
    }

    /**
     * Called whenever this item is equipped and the right mouse button is pressed. Args: itemStack, world, entityPlayer
     */
    public ItemStack onItemRightClick(ItemStack itemStackIn, World worldIn, EntityNPC playerIn)
    {
//        boolean flag = this.fillBlock == Blocks.air;
        HitPosition movingobjectposition = this.getMovingObjectPositionFromPlayer(worldIn, playerIn, this.liquid == null);

        if (movingobjectposition == null)
        {
            return itemStackIn;
        }
        else
        {
            if (movingobjectposition.type == HitPosition.ObjectType.BLOCK)
            {
                BlockPos blockpos = movingobjectposition.block;

                if (!World.isValidXZ(blockpos))
                {
                    return itemStackIn;
                }

                if (this.liquid == null)
                {
                    if (!playerIn.canPlayerEdit(blockpos.offset(movingobjectposition.side), movingobjectposition.side, itemStackIn))
                    {
                        return itemStackIn;
                    }

                    State iblockstate = worldIn.getState(blockpos);
                    Material material = iblockstate.getBlock().getMaterial();

//                    if (material == Material.water && ((Integer)iblockstate.getValue(BlockLiquid.LEVEL)).intValue() == 0)
//                    {
//                        worldIn.setBlockToAir(blockpos);
//                        playerIn.triggerAchievement(StatList.objectUseStats[ItemRegistry.getIdFromItem(this)]);
//                        return this.fillBucket(itemStackIn, playerIn, new ItemStack(Items.water_bucket));
//                    }
//                    else if (material == Material.lava && ((Integer)iblockstate.getValue(BlockLiquid.LEVEL)).intValue() == 0)
//                    {
//                        worldIn.setBlockToAir(blockpos);
//                        playerIn.triggerAchievement(StatList.objectUseStats[ItemRegistry.getIdFromItem(this)]);
//                        return this.fillBucket(itemStackIn, playerIn, new ItemStack(Items.lava_bucket));
//                    }
//                    else
                    if(this.recursive) {
                    	if (material.isLiquid()) {
                    		if(!worldIn.client)
                    			setRecursive((AWorldServer)worldIn, blockpos, 4, null);
//                    		playerIn.triggerAchievement(StatRegistry.objectUseStats[ItemRegistry.getIdFromItem(this)]);
//                    		if(!playerIn.creative)
                    		--itemStackIn.stackSize;
                    		return itemStackIn;
                    	}
                    }
                    else {
	                    if (material.isLiquid() && ((Integer)iblockstate.getValue(BlockLiquid.LEVEL)).intValue() == 0)
	                    {
	                        worldIn.setBlockToAir(blockpos);
//	                        playerIn.triggerAchievement(StatRegistry.objectUseStats[ItemRegistry.getIdFromItem(this)]);
	                        Block block = iblockstate.getBlock();
	                        return this.fillBucket(itemStackIn, playerIn, new ItemStack(
	                        		ItemRegistry.getRegisteredItem(BlockRegistry.REGISTRY.getNameForObject(block instanceof BlockDynamicLiquid
	                        		? FluidRegistry.getStaticBlock((BlockDynamicLiquid)block) : block) + 
	            					"_bucket"), 1, 0));
	                    }
                    }
                }
                else
                {
//                    if (this.empty)
//                    {
//                        return new ItemStack(Items.bucket);
//                    }

                    BlockPos blockpos1 = blockpos.offset(movingobjectposition.side);

                    if (!playerIn.canPlayerEdit(blockpos1, movingobjectposition.side, itemStackIn))
                    {
                        return itemStackIn;
                    }

                    if (this.tryPlaceContainedLiquid(worldIn, blockpos1)) // && !playerIn.creative)
                    {
//                        playerIn.triggerAchievement(StatRegistry.objectUseStats[ItemRegistry.getIdFromItem(this)]);
                        if(this.recursive) {
                        	--itemStackIn.stackSize;
                        	return itemStackIn;
                        }
                        return new ItemStack(Items.bucket);
                    }
                }
            }

            return itemStackIn;
        }
    }

    private ItemStack fillBucket(ItemStack emptyBuckets, EntityNPC player, ItemStack fullBucket)
    {
//        if (player.creative)
//        {
//            return emptyBuckets;
//        }
//        else
        if (--emptyBuckets.stackSize <= 0)
        {
            return fullBucket;
        }
        else
        {
            if (!player.inventory.addItemStackToInventory(fullBucket))
            {
                player.dropPlayerItemWithRandomChoice(fullBucket, false);
            }

            return emptyBuckets;
        }
    }

    public boolean tryPlaceContainedLiquid(World worldIn, BlockPos pos)
    {
        if (this.liquid == null)
        {
            return false;
        }
        else
        {
            Material material = worldIn.getState(pos).getBlock().getMaterial();
            boolean flag = !material.isSolid();

            if (!worldIn.isAirBlock(pos) && !flag)
            {
                return false;
            }
            else
            {
                if (worldIn.doesWaterVaporize(pos) && this.liquid.getMaterial() == Material.water)
                {
                    int i = pos.getX();
                    int j = pos.getY();
                    int k = pos.getZ();
                    worldIn.playSound(SoundEvent.FIZZ, (double)((float)i + 0.5F), (double)((float)j + 0.5F), (double)((float)k + 0.5F), 0.5F);

                    for (int l = 0; l < 8; ++l)
                    {
                        worldIn.spawnParticle(ParticleType.SMOKE_LARGE, (double)i + Math.random(), (double)j + Math.random(), (double)k + Math.random(), 0.0D, 0.0D, 0.0D);
                    }
                }
                else
                {
                    if (!worldIn.client && flag && !material.isLiquid())
                    {
                        worldIn.destroyBlock(pos, true);
                    }
                    
                    if(this.recursive) {
                    	if(!worldIn.client)
                			setRecursive((AWorldServer)worldIn, pos, 4, FluidRegistry.getStaticBlock(this.liquid));
                    }
                    else {
                    	worldIn.setState(pos, this.liquid.getState(), 3);
                    }
                }

                return true;
            }
        }
    }
    
//    public void getSubItems(Item itemIn, CreativeTab tab, List<ItemStack> subItems)
//    {
//        if(this.empty) {
//        	super.getSubItems(itemIn, tab, subItems);
//        }
//        else {
//        	for(int z = 0; z < FluidRegistry.getNumFluids(); z++) {
//        		subItems.add(new ItemStack(itemIn, 1, z));
//        	}
//        }
//    }

    public String getDisplay(ItemStack stack)
    {
        String s = super.getDisplay(stack);
    	if(this.liquid == null)
    		return s;
        String s1 = this.liquid.getDisplay(); // FluidRegistry.getStaticBlock(this.liquid).getDisplay();
        if(s1 != null)
            s = s + " mit " + s1; // Strs.get("tile." + s1 + ".name");
        return s;
    }

//    public int getColorFromItemStack(ItemStack stack, int renderPass)
//    {
//        return this.fillBlock == null && renderPass == 1 ? FluidRegistry.getLiquidColor(stack.getMetadata()) : 16777215;
//    }
    
    public boolean isMagnetic() {
    	return true;
    }

    public Model getModel(ModelProvider provider, String name, int meta) {
    	return this.recursive ? provider.getModel(this.getTransform(), name.substring("recursive_".length())) : super.getModel(provider, name, meta);
    }
    
//    public ItemMeshDefinition getMesher() {
//    	return this.fillBlock != null ? null : new ItemMeshDefinition()
//        {
//    		public String getModelLocation(ItemStack stack)
//            {
//                return "item/fluid_bucket#0" + '#' + "inventory";
//            }
//        };
//    }
//    
//    public void getRenderItems(Item itemIn, List<ItemStack> subItems) {
//    	if(this.fillBlock != null)
//    		super.getRenderItems(itemIn, subItems);
//    	else
//    		subItems.add(new ItemStack(itemIn, 1, 0));
//    }

//    public Model getModel(String name, int meta) {
//    	if(this.empty)
//    		return super.getModel(name, meta);
//    	else
//    		return provider.getModel(this.getTransform(), meta < 0 || meta >= FluidRegistry.getNumFluids() ? "bucket" : 
//    			(BlockRegistry.REGISTRY.getNameForObject(FluidRegistry.getStaticBlock(meta)) + "_bucket"));
//    }
}
