package net.minecraft.server.management;

import net.minecraft.block.Block;
import net.minecraft.block.BlockChest;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemSword;
import net.minecraft.network.play.server.S23PacketBlockChange;
import net.minecraft.network.play.server.S38PacketPlayerListItem;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityChest;
import net.minecraft.util.BlockPos;
import net.minecraft.util.EnumFacing;
import net.minecraft.world.ILockableContainer;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraft.world.WorldSettings;

public class ItemInWorldManager
{
    /** Forge reach distance */
    private double blockReachDistance = 5.0d;
    /** The world object that this object is connected to. */
    public World theWorld;
    /** The EntityPlayerMP object that this object is connected to. */
    public EntityPlayerMP thisPlayerMP;
    private WorldSettings.GameType gameType;
    /** True if the player is destroying a block */
    private boolean isDestroyingBlock;
    private int initialDamage;
    private BlockPos field_180240_f;
    private int curblockDamage;
    /**
     * Set to true when the "finished destroying block" packet is received but the block wasn't fully damaged yet. The
     * block will not be destroyed while this is false.
     */
    private boolean receivedFinishDiggingPacket;
    private BlockPos field_180241_i;
    private int initialBlockDamage;
    private int durabilityRemainingOnBlock;
    private static final String __OBFID = "CL_00001442";

    public ItemInWorldManager(World worldIn)
    {
        this.gameType = WorldSettings.GameType.NOT_SET;
        this.field_180240_f = BlockPos.ORIGIN;
        this.field_180241_i = BlockPos.ORIGIN;
        this.durabilityRemainingOnBlock = -1;
        this.theWorld = worldIn;
    }

    public void setGameType(WorldSettings.GameType p_73076_1_)
    {
        this.gameType = p_73076_1_;
        p_73076_1_.configurePlayerCapabilities(this.thisPlayerMP.capabilities);
        this.thisPlayerMP.sendPlayerAbilities();
        this.thisPlayerMP.mcServer.getConfigurationManager().sendPacketToAllPlayers(new S38PacketPlayerListItem(S38PacketPlayerListItem.Action.UPDATE_GAME_MODE, new EntityPlayerMP[] {this.thisPlayerMP}));
    }

    public WorldSettings.GameType getGameType()
    {
        return this.gameType;
    }

    public boolean func_180239_c()
    {
        return this.gameType.isSurvivalOrAdventure();
    }

    /**
     * Get if we are in creative game mode.
     */
    public boolean isCreative()
    {
        return this.gameType.isCreative();
    }

    /**
     * if the gameType is currently NOT_SET then change it to par1
     */
    public void initializeGameType(WorldSettings.GameType p_73077_1_)
    {
        if (this.gameType == WorldSettings.GameType.NOT_SET)
        {
            this.gameType = p_73077_1_;
        }

        this.setGameType(this.gameType);
    }

    public void updateBlockRemoving()
    {
        ++this.curblockDamage;
        float f;
        int j;

        if (this.receivedFinishDiggingPacket)
        {
            int i = this.curblockDamage - this.initialBlockDamage;
            Block block = this.theWorld.getBlockState(this.field_180241_i).getBlock();

            if (block.getMaterial() == Material.air)
            {
                this.receivedFinishDiggingPacket = false;
            }
            else
            {
                f = block.getPlayerRelativeBlockHardness(this.thisPlayerMP, this.thisPlayerMP.worldObj, this.field_180241_i) * (float)(i + 1);
                j = (int)(f * 10.0F);

                if (j != this.durabilityRemainingOnBlock)
                {
                    this.theWorld.sendBlockBreakProgress(this.thisPlayerMP.getEntityId(), this.field_180241_i, j);
                    this.durabilityRemainingOnBlock = j;
                }

                if (f >= 1.0F)
                {
                    this.receivedFinishDiggingPacket = false;
                    this.func_180237_b(this.field_180241_i);
                }
            }
        }
        else if (this.isDestroyingBlock)
        {
            Block block1 = this.theWorld.getBlockState(this.field_180240_f).getBlock();

            if (block1.getMaterial() == Material.air)
            {
                this.theWorld.sendBlockBreakProgress(this.thisPlayerMP.getEntityId(), this.field_180240_f, -1);
                this.durabilityRemainingOnBlock = -1;
                this.isDestroyingBlock = false;
            }
            else
            {
                int k = this.curblockDamage - this.initialDamage;
                f = block1.getPlayerRelativeBlockHardness(this.thisPlayerMP, this.thisPlayerMP.worldObj, this.field_180241_i) * (float)(k + 1);
                j = (int)(f * 10.0F);

                if (j != this.durabilityRemainingOnBlock)
                {
                    this.theWorld.sendBlockBreakProgress(this.thisPlayerMP.getEntityId(), this.field_180240_f, j);
                    this.durabilityRemainingOnBlock = j;
                }
            }
        }
    }

    public void func_180784_a(BlockPos p_180784_1_, EnumFacing p_180784_2_)
    {
        net.minecraftforge.event.entity.player.PlayerInteractEvent event = net.minecraftforge.event.ForgeEventFactory.onPlayerInteract(thisPlayerMP,
                net.minecraftforge.event.entity.player.PlayerInteractEvent.Action.LEFT_CLICK_BLOCK, theWorld, p_180784_1_, p_180784_2_);
        if (event.isCanceled())
        {
            thisPlayerMP.playerNetServerHandler.sendPacket(new S23PacketBlockChange(theWorld, p_180784_1_));
            return;
        }

        if (this.isCreative())
        {
            if (!this.theWorld.func_175719_a((EntityPlayer)null, p_180784_1_, p_180784_2_))
            {
                this.func_180237_b(p_180784_1_);
            }
        }
        else
        {
            Block block = this.theWorld.getBlockState(p_180784_1_).getBlock();

            if (this.gameType.isAdventure())
            {
                if (this.gameType == WorldSettings.GameType.SPECTATOR)
                {
                    return;
                }

                if (!this.thisPlayerMP.func_175142_cm())
                {
                    ItemStack itemstack = this.thisPlayerMP.getCurrentEquippedItem();

                    if (itemstack == null)
                    {
                        return;
                    }

                    if (!itemstack.canDestroy(block))
                    {
                        return;
                    }
                }
            }

            //
            this.initialDamage = this.curblockDamage;
            float f = 1.0F;

            if (!block.isAir(theWorld, p_180784_1_))
            {
                if (event.useBlock != net.minecraftforge.fml.common.eventhandler.Event.Result.DENY)
                {
                    block.onBlockClicked(this.theWorld, p_180784_1_, this.thisPlayerMP);
                    this.theWorld.func_175719_a((EntityPlayer)null, p_180784_1_, p_180784_2_);
                }
                else
                {
                    thisPlayerMP.playerNetServerHandler.sendPacket(new S23PacketBlockChange(theWorld, p_180784_1_));
                }
                f = block.getPlayerRelativeBlockHardness(this.thisPlayerMP, this.thisPlayerMP.worldObj, p_180784_1_);
            }

            if (event.useItem == net.minecraftforge.fml.common.eventhandler.Event.Result.DENY)
            {
                if (f >= 1.0F)
                {
                    thisPlayerMP.playerNetServerHandler.sendPacket(new S23PacketBlockChange(theWorld, p_180784_1_));
                }
                return;
            }

            if (block.isAir(theWorld, p_180784_1_) && f >= 1.0F)
            {
                this.func_180237_b(p_180784_1_);
            }
            else
            {
                this.isDestroyingBlock = true;
                this.field_180240_f = p_180784_1_;
                int i = (int)(f * 10.0F);
                this.theWorld.sendBlockBreakProgress(this.thisPlayerMP.getEntityId(), p_180784_1_, i);
                this.durabilityRemainingOnBlock = i;
            }
        }
    }

    public void func_180785_a(BlockPos p_180785_1_)
    {
        if (p_180785_1_.equals(this.field_180240_f))
        {
            int i = this.curblockDamage - this.initialDamage;
            Block block = this.theWorld.getBlockState(p_180785_1_).getBlock();

            if (block.isAir(theWorld, p_180785_1_))
            {
                float f = block.getPlayerRelativeBlockHardness(this.thisPlayerMP, this.thisPlayerMP.worldObj, p_180785_1_) * (float)(i + 1);

                if (f >= 0.7F)
                {
                    this.isDestroyingBlock = false;
                    this.theWorld.sendBlockBreakProgress(this.thisPlayerMP.getEntityId(), p_180785_1_, -1);
                    this.func_180237_b(p_180785_1_);
                }
                else if (!this.receivedFinishDiggingPacket)
                {
                    this.isDestroyingBlock = false;
                    this.receivedFinishDiggingPacket = true;
                    this.field_180241_i = p_180785_1_;
                    this.initialBlockDamage = this.initialDamage;
                }
            }
        }
    }

    public void func_180238_e()
    {
        this.isDestroyingBlock = false;
        this.theWorld.sendBlockBreakProgress(this.thisPlayerMP.getEntityId(), this.field_180240_f, -1);
    }

    private boolean func_180235_c(BlockPos p_180235_1_)
    {
        return removeBlock(p_180235_1_, false);
    }
    private boolean removeBlock(BlockPos p_180235_1_, boolean canHarvest)
    {
        IBlockState iblockstate = this.theWorld.getBlockState(p_180235_1_);
        iblockstate.getBlock().onBlockHarvested(this.theWorld, p_180235_1_, iblockstate, this.thisPlayerMP);
        boolean flag = iblockstate.getBlock().removedByPlayer(theWorld, p_180235_1_, thisPlayerMP, canHarvest);

        if (flag)
        {
            iblockstate.getBlock().onBlockDestroyedByPlayer(this.theWorld, p_180235_1_, iblockstate);
        }

        return flag;
    }

    public boolean func_180237_b(BlockPos p_180237_1_)
    {
        int exp = net.minecraftforge.common.ForgeHooks.onBlockBreakEvent(theWorld, gameType, thisPlayerMP, p_180237_1_);
        if (exp == -1)
        {
            return false;
        }
        else
        {
            IBlockState iblockstate = this.theWorld.getBlockState(p_180237_1_);
            TileEntity tileentity = this.theWorld.getTileEntity(p_180237_1_);

            ItemStack stack = thisPlayerMP.getCurrentEquippedItem();
            if (stack != null && stack.getItem().onBlockStartBreak(stack, p_180237_1_, thisPlayerMP)) return false;

            this.theWorld.playAuxSFXAtEntity(this.thisPlayerMP, 2001, p_180237_1_, Block.getStateId(iblockstate));
            boolean flag1 = false;

            if (this.isCreative())
            {
                flag1 = this.func_180235_c(p_180237_1_);
                this.thisPlayerMP.playerNetServerHandler.sendPacket(new S23PacketBlockChange(this.theWorld, p_180237_1_));
            }
            else
            {
                ItemStack itemstack1 = this.thisPlayerMP.getCurrentEquippedItem();
                boolean flag = iblockstate.getBlock().canHarvestBlock(theWorld, p_180237_1_, thisPlayerMP);

                if (itemstack1 != null)
                {
                    itemstack1.onBlockDestroyed(this.theWorld, iblockstate.getBlock(), p_180237_1_, this.thisPlayerMP);

                    if (itemstack1.stackSize == 0)
                    {
                        this.thisPlayerMP.destroyCurrentEquippedItem();
                    }
                }

                flag1 = this.removeBlock(p_180237_1_, flag);
                if (flag1 && flag)
                {
                    iblockstate.getBlock().harvestBlock(this.theWorld, this.thisPlayerMP, p_180237_1_, iblockstate, tileentity);
                }
            }

            // Drop experiance
            if (!this.isCreative() && flag1 && exp > 0)
            {
                iblockstate.getBlock().dropXpOnBlockBreak(theWorld, p_180237_1_, exp);
            }
            return flag1;
        }
    }

    /**
     * Attempts to right-click use an item by the given EntityPlayer in the given World
     */
    public boolean tryUseItem(EntityPlayer p_73085_1_, World worldIn, ItemStack p_73085_3_)
    {
        if (this.gameType == WorldSettings.GameType.SPECTATOR)
        {
            return false;
        }
        else
        {
            int i = p_73085_3_.stackSize;
            int j = p_73085_3_.getMetadata();
            ItemStack itemstack1 = p_73085_3_.useItemRightClick(worldIn, p_73085_1_);

            if (itemstack1 == p_73085_3_ && (itemstack1 == null || itemstack1.stackSize == i && itemstack1.getMaxItemUseDuration() <= 0 && itemstack1.getMetadata() == j))
            {
                return false;
            }
            else
            {
                p_73085_1_.inventory.mainInventory[p_73085_1_.inventory.currentItem] = itemstack1;

                if (this.isCreative())
                {
                    itemstack1.stackSize = i;

                    if (itemstack1.isItemStackDamageable())
                    {
                        itemstack1.setItemDamage(j);
                    }
                }

                if (itemstack1.stackSize == 0)
                {
                    p_73085_1_.inventory.mainInventory[p_73085_1_.inventory.currentItem] = null;
                    net.minecraftforge.event.ForgeEventFactory.onPlayerDestroyItem(p_73085_1_, itemstack1);
                }

                if (!p_73085_1_.isUsingItem())
                {
                    ((EntityPlayerMP)p_73085_1_).sendContainerToPlayer(p_73085_1_.inventoryContainer);
                }

                return true;
            }
        }
    }

    public boolean func_180236_a(EntityPlayer p_180236_1_, World worldIn, ItemStack p_180236_3_, BlockPos p_180236_4_, EnumFacing p_180236_5_, float p_180236_6_, float p_180236_7_, float p_180236_8_)
    {
        if (this.gameType == WorldSettings.GameType.SPECTATOR)
        {
            TileEntity tileentity = worldIn.getTileEntity(p_180236_4_);

            if (tileentity instanceof ILockableContainer)
            {
                Block block = worldIn.getBlockState(p_180236_4_).getBlock();
                ILockableContainer ilockablecontainer = (ILockableContainer)tileentity;

                if (ilockablecontainer instanceof TileEntityChest && block instanceof BlockChest)
                {
                    ilockablecontainer = ((BlockChest)block).getLockableContainer(worldIn, p_180236_4_);
                }

                if (ilockablecontainer != null)
                {
                    p_180236_1_.displayGUIChest(ilockablecontainer);
                    return true;
                }
            }
            else if (tileentity instanceof IInventory)
            {
                p_180236_1_.displayGUIChest((IInventory)tileentity);
                return true;
            }

            return false;
        }
        else
        {
            net.minecraftforge.event.entity.player.PlayerInteractEvent event = net.minecraftforge.event.ForgeEventFactory.onPlayerInteract(p_180236_1_,
                    net.minecraftforge.event.entity.player.PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK, worldIn, p_180236_4_, p_180236_5_);
            if (event.isCanceled())
            {
                thisPlayerMP.playerNetServerHandler.sendPacket(new S23PacketBlockChange(theWorld, p_180236_4_));
                return false;
            }

            if (p_180236_3_ != null && p_180236_3_.getItem().onItemUseFirst(p_180236_3_, p_180236_1_, worldIn, p_180236_4_, p_180236_5_, p_180236_6_, p_180236_7_, p_180236_8_))
            {
                if (p_180236_3_.stackSize <= 0) net.minecraftforge.event.ForgeEventFactory.onPlayerDestroyItem(thisPlayerMP, p_180236_3_);
                return true;
            }

            IBlockState iblockstate = worldIn.getBlockState(p_180236_4_);
            boolean isAir = worldIn.isAirBlock(p_180236_4_);
            boolean useBlock = !p_180236_1_.isSneaking() || p_180236_1_.getHeldItem() == null;
            if (!useBlock) useBlock = p_180236_1_.getHeldItem().getItem().doesSneakBypassUse(worldIn, p_180236_4_, p_180236_1_);
            boolean result = false;

            if (useBlock)
            {
                if (event.useBlock != net.minecraftforge.fml.common.eventhandler.Event.Result.DENY)
                {
                    result = iblockstate.getBlock().onBlockActivated(worldIn, p_180236_4_, iblockstate, p_180236_1_, p_180236_5_, p_180236_6_, p_180236_7_, p_180236_8_);
                }
                else
                {
                    thisPlayerMP.playerNetServerHandler.sendPacket(new S23PacketBlockChange(theWorld, p_180236_4_));
                    result = event.useItem != net.minecraftforge.fml.common.eventhandler.Event.Result.ALLOW;
                }
            }
            if (p_180236_3_ != null && !result && event.useItem != net.minecraftforge.fml.common.eventhandler.Event.Result.DENY)
            {
                int meta = p_180236_3_.getMetadata();
                int size = p_180236_3_.stackSize;
                result = p_180236_3_.onItemUse(p_180236_1_, worldIn, p_180236_4_, p_180236_5_, p_180236_6_, p_180236_7_, p_180236_8_);
                if (isCreative())
                {
                    p_180236_3_.setItemDamage(meta);
                    p_180236_3_.stackSize = size;
                }
                if (p_180236_3_.stackSize <= 0) net.minecraftforge.event.ForgeEventFactory.onPlayerDestroyItem(thisPlayerMP, p_180236_3_);
            }
            return result;
        }
    }

    /**
     * Sets the world instance.
     */
    public void setWorld(WorldServer p_73080_1_)
    {
        this.theWorld = p_73080_1_;
    }

    public double getBlockReachDistance()
    {
        return blockReachDistance;
    }
    public void setBlockReachDistance(double distance)
    {
        blockReachDistance = distance;
    }
}