package net.glowstone.block.blocktype;

import net.glowstone.block.GlowBlock;
import net.glowstone.block.GlowBlockState;
import net.glowstone.block.entity.BlockEntity;
import net.glowstone.block.entity.ContainerEntity;
import net.glowstone.block.entity.HopperEntity;
import net.glowstone.block.state.GlowHopper;
import net.glowstone.chunk.GlowChunk;
import net.glowstone.entity.GlowPlayer;
import net.glowstone.entity.objects.GlowItem;
import net.glowstone.inventory.MaterialMatcher;
import net.glowstone.inventory.ToolType;
import org.bukkit.Location;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.Sign;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.material.*;
import org.bukkit.util.Vector;

import java.util.HashMap;

public class BlockHopper extends BlockContainer {

    public void setFacingDirection(BlockState bs, BlockFace face) {
        byte data;
        switch (face) {
            case DOWN:
                data = 0;
                break;
            case UP:
                data = 1;
                break;
            case NORTH:
                data = 2;
                break;
            case SOUTH:
                data = 3;
                break;
            case WEST:
                data = 4;
                break;
            case EAST:
            default:
                data = 5;
                break;
        }
        bs.setRawData(data);
    }

    @Override
    public BlockEntity createBlockEntity(GlowChunk chunk, int cx, int cy, int cz) {
        return new HopperEntity(chunk.getBlock(cx, cy, cz));
    }

    @Override
    public void placeBlock(GlowPlayer player, GlowBlockState state, BlockFace face, ItemStack holding, Vector clickedLoc) {
        super.placeBlock(player, state, face, holding, clickedLoc);
        setFacingDirection(state, face.getOppositeFace());
        state.getBlock().getWorld().requestPulse(state.getBlock());
    }

    @Override
    protected MaterialMatcher getNeededMiningTool(GlowBlock block) {
        return ToolType.PICKAXE;
    }

    @Override
    public void receivePulse(GlowBlock block) {
        if (block.getBlockEntity() == null) {
            return;
        }
        HopperEntity hopper = (HopperEntity) block.getBlockEntity();
        if (!((Hopper) block.getState().getData()).isPowered()) {
            pushItems(block, hopper);
        }
        pullItems(block, hopper);
    }

    @Override
    public void onRedstoneUpdate(GlowBlock block) {
        ((Hopper) block.getState().getData()).setActive(!block.isBlockPowered());
    }

    private void pullItems(GlowBlock block, HopperEntity hopper) {
        GlowBlock source = block.getRelative(BlockFace.UP);
        MaterialData data = source.getState().getData();
        if (!source.getType().isSolid() ||
                (data instanceof Step && !((Step) data).isInverted()) ||
                (data instanceof WoodenStep && !((WoodenStep) data).isInverted()) ||
                (data instanceof Sign) ||
                (data instanceof Rails)) {
            GlowItem item = getFirstDroppedItem(source.getLocation());
            if (item == null) {
                return;
            }
            ItemStack stack = item.getItemStack();
            HashMap<Integer, ItemStack> add = hopper.getInventory().addItem(stack);
            if (add.size() > 0) {
                item.setItemStack(add.get(0));
            } else {
                item.remove();
            }
        } else if (source.getBlockEntity() != null && source.getBlockEntity() instanceof ContainerEntity) {
            ContainerEntity sourceContainer = (ContainerEntity) source.getBlockEntity();
            if (sourceContainer.getInventory() == null || sourceContainer.getInventory().getContents().length == 0) {
                return;
            }
            ItemStack item = getFirstItem(sourceContainer);
            if (item == null) {
                return;
            }
            ItemStack clone = item.clone();
            clone.setAmount(1);
            if (hopper.getInventory().addItem(clone).size() > 0) {
                return;
            }
            if (item.getAmount() - 1 == 0) {
                sourceContainer.getInventory().remove(item);
            } else {
                item.setAmount(item.getAmount() - 1);
            }
        }
    }

    private boolean pushItems(GlowBlock block, HopperEntity hopper) {
        if (hopper.getInventory() == null || hopper.getInventory().getContents().length == 0) {
            return false;
        }
        GlowBlock target = block.getRelative(((Hopper) block.getState().getData()).getFacing());
        if (target.getType() != null && target.getBlockEntity() instanceof ContainerEntity) {
            if (target.getState() instanceof GlowHopper) {
                if (((Hopper) block.getState().getData()).getFacing() == BlockFace.DOWN) {
                    // If the hopper is facing downwards, the target hopper can do the pulling task itself
                    return false;
                }
            }
            ItemStack item = getFirstItem(hopper);
            if (item == null) {
                return false;
            }
            ItemStack clone = item.clone();
            clone.setAmount(1);
            if (((ContainerEntity) target.getBlockEntity()).getInventory().addItem(clone).size() > 0) {
                return false;
            }

            if (item.getAmount() - 1 == 0) {
                hopper.getInventory().remove(item);
            } else {
                item.setAmount(item.getAmount() - 1);
            }
            return true;
        }
        return false;
    }

    private GlowItem getFirstDroppedItem(Location location) {
        for (Entity entity : location.getChunk().getEntities()) {
            if (location.getBlockX() != entity.getLocation().getBlockX() || location.getBlockY() != entity.getLocation().getBlockY() || location.getBlockZ() != entity.getLocation().getBlockZ()) {
                continue;
            }
            if (entity.getType() != EntityType.DROPPED_ITEM) {
                continue;
            }
            return ((GlowItem) entity);
        }
        return null;
    }

    private ItemStack getFirstItem(ContainerEntity container) {
        Inventory inventory = container.getInventory();
        for (int i = 0; i < inventory.getSize(); i++) {
            if (inventory.getItem(i) == null || inventory.getItem(i).getType() == null) {
                continue;
            }
            return inventory.getItem(i);
        }
        return null;
    }

    @Override
    public boolean isPulseOnce(GlowBlock block) {
        return false;
    }

    @Override
    public int getPulseTickSpeed(GlowBlock block) {
        return 8;
    }
}

@@ -621,38 +621,8 @@
 te;%0A
-import org.bukkit.block.Sign;%0A
 impo

Check correct Sign class in hopper