package common.block.tech;

import java.util.List;
import common.block.Block;
import common.block.BlockContainer;
import common.block.DirectionalDown;
import common.block.Material;
import common.entity.Entity;
import common.entity.npc.EntityNPC;
import common.entity.types.EntityLiving;
import common.inventory.Container;
import common.inventory.InventoryHelper;
import common.item.CheatTab;
import common.item.Item;
import common.item.ItemStack;
import common.item.block.ItemBlock;
import common.model.BlockLayer;
import common.model.Model;
import common.model.ModelProvider;
import common.model.ModelRotation;
import common.properties.Property;
import common.properties.PropertyBool;
import common.tileentity.TileEntity;
import common.tileentity.TileEntityHopper;
import common.util.BlockPos;
import common.util.BoundingBox;
import common.util.Facing;
import common.world.IWorldAccess;
import common.world.State;
import common.world.World;
import common.world.AWorldServer;

public class BlockHopper extends BlockContainer implements DirectionalDown
{
	private static final Model hopper_down = ModelProvider.getModelProvider().getModel("hopper_outside")
			.add(0, 10, 0, 16, 11, 16)
				.d().uv(0, 0, 16, 16).noCull()
				.u("hopper_inside").uv(0, 0, 16, 16).noCull()
				.n().uv(0, 5, 16, 6).noCull()
				.s().uv(0, 5, 16, 6).noCull()
				.w().uv(0, 5, 16, 6).noCull()
				.e().uv(0, 5, 16, 6).noCull()
			.add(0, 11, 0, 2, 16, 16)
				.d().uv(0, 0, 2, 16).noCull()
				.u("hopper_top").uv(0, 0, 2, 16).noCull()
				.n().uv(0, 0, 2, 5).noCull()
				.s().uv(0, 0, 2, 5).noCull()
				.w().uv(0, 0, 16, 5).noCull()
				.e().uv(0, 0, 16, 5).noCull()
			.add(14, 11, 0, 16, 16, 16)
				.d().uv(14, 0, 16, 16).noCull()
				.u("hopper_top").uv(14, 0, 16, 16).noCull()
				.n().uv(14, 0, 16, 5).noCull()
				.s().uv(14, 0, 16, 5).noCull()
				.w().uv(0, 0, 16, 5).noCull()
				.e().uv(0, 0, 16, 5).noCull()
			.add(2, 11, 0, 14, 16, 2)
				.d().uv(2, 0, 14, 2).noCull()
				.u("hopper_top").uv(2, 0, 14, 2).noCull()
				.n().uv(2, 0, 14, 5).noCull()
				.s().uv(2, 0, 14, 5).noCull()
				.w().uv(0, 0, 2, 5).noCull()
				.e().uv(0, 0, 2, 5).noCull()
			.add(2, 11, 14, 14, 16, 16)
				.d().uv(2, 14, 14, 16).noCull()
				.u("hopper_top").uv(2, 14, 14, 16).noCull()
				.n().uv(2, 0, 14, 5).noCull()
				.s().uv(2, 0, 14, 5).noCull()
				.w().uv(14, 0, 16, 5).noCull()
				.e().uv(14, 0, 16, 5).noCull()
			.add(4, 4, 4, 12, 10, 12)
				.d().uv(4, 4, 12, 12).noCull()
				.u().uv(4, 4, 12, 12).noCull()
				.n().uv(4, 6, 12, 12).noCull()
				.s().uv(4, 6, 12, 12).noCull()
				.w().uv(4, 6, 12, 12).noCull()
				.e().uv(4, 6, 12, 12).noCull()
			.add(6, 0, 6, 10, 4, 10)
				.d().uv(6, 6, 10, 10).noCull()
				.u().uv(6, 6, 10, 10).noCull()
				.n().uv(6, 12, 10, 16).noCull()
				.s().uv(6, 12, 10, 16).noCull()
				.w().uv(6, 12, 10, 16).noCull()
				.e().uv(6, 12, 10, 16).noCull()
	;
	
    public static final PropertyBool ENABLED = PropertyBool.create("enabled");

    public BlockHopper()
    {
        super(Material.SOLID);
        this.setDefaultState(this.getBaseState().withProperty(FACING, Facing.DOWN).withProperty(ENABLED, Boolean.valueOf(true)));
        this.setTab(CheatTab.TECHNOLOGY);
        this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
    }

    public void setBlockBoundsBasedOnState(IWorldAccess worldIn, BlockPos pos)
    {
        this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
    }

    /**
     * Add all collision boxes of this Block to the list that intersect with the given mask.
     */
    public void addCollisionBoxesToList(World worldIn, BlockPos pos, State state, BoundingBox mask, List<BoundingBox> list, Entity collidingEntity)
    {
        this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.625F, 1.0F);
        super.addCollisionBoxesToList(worldIn, pos, state, mask, list, collidingEntity);
        float f = 0.125F;
        this.setBlockBounds(0.0F, 0.0F, 0.0F, f, 1.0F, 1.0F);
        super.addCollisionBoxesToList(worldIn, pos, state, mask, list, collidingEntity);
        this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, f);
        super.addCollisionBoxesToList(worldIn, pos, state, mask, list, collidingEntity);
        this.setBlockBounds(1.0F - f, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
        super.addCollisionBoxesToList(worldIn, pos, state, mask, list, collidingEntity);
        this.setBlockBounds(0.0F, 0.0F, 1.0F - f, 1.0F, 1.0F, 1.0F);
        super.addCollisionBoxesToList(worldIn, pos, state, mask, list, collidingEntity);
        this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
    }

    /**
     * Called by ItemBlocks just before a block is actually set in the world, to allow for adjustments to the
     * IBlockstate
     */
    public State onBlockPlaced(World worldIn, BlockPos pos, Facing facing, float hitX, float hitY, float hitZ, EntityLiving placer)
    {
        Facing enumfacing = facing.getOpposite();

        if (enumfacing == Facing.UP)
        {
            enumfacing = Facing.DOWN;
        }

        return this.getState().withProperty(FACING, enumfacing).withProperty(ENABLED, Boolean.valueOf(true));
    }

    /**
     * Returns a new instance of a block's tile entity class. Called on placing the block.
     */
    public TileEntity createNewTileEntity(World worldIn)
    {
        return new TileEntityHopper();
    }

    /**
     * Called by ItemBlocks after a block is set in the world, to allow post-place logic
     */
    public void onBlockPlacedBy(World worldIn, BlockPos pos, State state, EntityLiving placer, ItemStack stack)
    {
        super.onBlockPlacedBy(worldIn, pos, state, placer, stack);

        if (stack.hasDisplayName())
        {
            TileEntity tileentity = worldIn.getTileEntity(pos);

            if (tileentity instanceof TileEntityHopper)
            {
                ((TileEntityHopper)tileentity).setCustomName(stack.getDisplayName());
            }
        }
    }

    public void onBlockAdded(AWorldServer worldIn, BlockPos pos, State state)
    {
        this.updateState(worldIn, pos, state);
    }

    public boolean onBlockActivated(World worldIn, BlockPos pos, State state, EntityNPC playerIn, Facing side, float hitX, float hitY, float hitZ)
    {
        if (worldIn.client)
        {
            return true;
        }
        else
        {
            TileEntity tileentity = worldIn.getTileEntity(pos);

            if (tileentity instanceof TileEntityHopper)
            {
                playerIn.displayGUIChest((TileEntityHopper)tileentity);
//                playerIn.triggerAchievement(StatRegistry.hopperStat);
            }

            return true;
        }
    }

    /**
     * Called when a neighboring block changes.
     */
    public void onNeighborBlockChange(World worldIn, BlockPos pos, State state, Block neighborBlock)
    {
        this.updateState(worldIn, pos, state);
    }

    private void updateState(World worldIn, BlockPos pos, State state)
    {
        boolean flag = !worldIn.isBlockPowered(pos);

        if (flag != ((Boolean)state.getValue(ENABLED)).booleanValue())
        {
            worldIn.setState(pos, state.withProperty(ENABLED, Boolean.valueOf(flag)), 4);
        }
    }

    public void onBlockRemoved(AWorldServer worldIn, BlockPos pos, State state)
    {
        TileEntity tileentity = worldIn.getTileEntity(pos);

        if (tileentity instanceof TileEntityHopper)
        {
            InventoryHelper.dropInventoryItems(worldIn, pos, (TileEntityHopper)tileentity);
            worldIn.updateComparatorOutputLevel(pos, this);
        }

        super.onBlockRemoved(worldIn, pos, state);
    }

    /**
     * The type of render function called. 3 for standard block models, 2 for TESR's, 1 for liquids, -1 is no render
     */
    public int getRenderType()
    {
        return 3;
    }

    public boolean isFullCube()
    {
        return false;
    }

    /**
     * Used to determine ambient occlusion and culling when rebuilding chunks for render
     */
    public boolean isOpaqueCube()
    {
        return false;
    }

    public boolean shouldSideBeRendered(IWorldAccess worldIn, BlockPos pos, Facing side)
    {
        return true;
    }

    public static Facing getFacing(int meta)
    {
        return Facing.getFront(meta & 7);
    }

    /**
     * Get's the hopper's active status from the 8-bit of the metadata. Note that the metadata stores whether the block
     * is powered, so this returns true when that bit is 0.
     */
    public static boolean isEnabled(int meta)
    {
        return (meta & 8) != 8;
    }

    public boolean hasComparatorInputOverride()
    {
        return true;
    }

    public int getComparatorInputOverride(World worldIn, BlockPos pos)
    {
        return Container.calcRedstone(worldIn.getTileEntity(pos));
    }

    public BlockLayer getBlockLayer()
    {
        return BlockLayer.CUTOUT_MIPPED;
    }

    /**
     * Convert the given metadata into a BlockState for this Block
     */
    public State getStateFromMeta(int meta)
    {
        return this.getState().withProperty(FACING, getFacing(((meta & 7) == 1 || (meta & 7) > 5) ? 0 : meta)).withProperty(ENABLED, Boolean.valueOf(isEnabled(meta)));
    }

    /**
     * Convert the BlockState into the correct metadata value
     */
    public int getMetaFromState(State state)
    {
        int i = 0;
        i = i | ((Facing)state.getValue(FACING)).getIndex();

        if (!((Boolean)state.getValue(ENABLED)).booleanValue())
        {
            i |= 8;
        }

        return i;
    }

    protected Property[] getProperties()
    {
        return new Property[] {FACING, ENABLED};
    }
    
    public boolean isMagnetic() {
    	return true;
    }

    public Model getModel(ModelProvider provider, String name, State state) {
    	return state.getValue(FACING) == Facing.DOWN ? hopper_down : provider.getModel("hopper_outside")
			.add(0, 10, 0, 16, 11, 16)
				.d().uv(0, 0, 16, 16).noCull()
				.u("hopper_inside").uv(0, 0, 16, 16).noCull()
				.n().uv(0, 5, 16, 6).noCull()
				.s().uv(0, 5, 16, 6).noCull()
				.w().uv(0, 5, 16, 6).noCull()
				.e().uv(0, 5, 16, 6).noCull()
			.add(0, 11, 0, 2, 16, 16)
				.d().uv(0, 0, 2, 16).noCull()
				.u("hopper_top").uv(0, 0, 2, 16).noCull()
				.n().uv(0, 0, 2, 5).noCull()
				.s().uv(0, 0, 2, 5).noCull()
				.w().uv(0, 0, 16, 5).noCull()
				.e().uv(0, 0, 16, 5).noCull()
			.add(14, 11, 0, 16, 16, 16)
				.d().uv(14, 0, 16, 16).noCull()
				.u("hopper_top").uv(14, 0, 16, 16).noCull()
				.n().uv(14, 0, 16, 5).noCull()
				.s().uv(14, 0, 16, 5).noCull()
				.w().uv(0, 0, 16, 5).noCull()
				.e().uv(0, 0, 16, 5).noCull()
			.add(2, 11, 0, 14, 16, 2)
				.d().uv(2, 0, 14, 2).noCull()
				.u("hopper_top").uv(2, 0, 14, 2).noCull()
				.n().uv(2, 0, 14, 5).noCull()
				.s().uv(2, 0, 14, 5).noCull()
				.w().uv(0, 0, 2, 5).noCull()
				.e().uv(0, 0, 2, 5).noCull()
			.add(2, 11, 14, 14, 16, 16)
				.d().uv(2, 14, 14, 16).noCull()
				.u("hopper_top").uv(2, 14, 14, 16).noCull()
				.n().uv(2, 0, 14, 5).noCull()
				.s().uv(2, 0, 14, 5).noCull()
				.w().uv(14, 0, 16, 5).noCull()
				.e().uv(14, 0, 16, 5).noCull()
			.add(4, 4, 4, 12, 10, 12)
				.d().uv(4, 4, 12, 12).noCull()
				.u().uv(4, 4, 12, 12).noCull()
				.n().uv(4, 6, 12, 12).noCull()
				.s().uv(4, 6, 12, 12).noCull()
				.w().uv(4, 6, 12, 12).noCull()
				.e().uv(4, 6, 12, 12).noCull()
			.add(6, 4, 0, 10, 8, 4)
				.d().uv(6, 0, 10, 4).noCull()
				.u().uv(6, 0, 10, 4).noCull()
				.n().uv(6, 8, 10, 12).noCull()
				.s().uv(6, 8, 10, 12).noCull()
				.w().uv(0, 8, 4, 12).noCull()
				.e().uv(0, 8, 4, 12).noCull()
				.rotate(ModelRotation.getNorthRot(state.getValue(FACING)));
    }

    public Property<?>[] getIgnoredProperties() {
    	return new Property[] {ENABLED};
    }
	
	protected Item getItemToRegister() {
		return new ItemBlock(this, "hopper", true);
	}
}
