package common.block.tech;

import common.block.Block;
import common.block.Material;
import common.block.artificial.BlockFence;
import common.entity.Entity;
import common.init.SoundEvent;
import common.item.CheatTab;
import common.item.Item;
import common.item.block.ItemPressurePlate;
import common.model.Model;
import common.model.ModelProvider;
import common.rng.Random;
import common.util.BlockPos;
import common.util.BoundingBox;
import common.util.Facing;
import common.world.IBlockAccess;
import common.world.IWorldAccess;
import common.world.State;
import common.world.World;
import common.world.AWorldServer;

public abstract class BlockBasePressurePlate extends Block
{
	public BlockBasePressurePlate(Material p_i46401_1_)
    {
        super(p_i46401_1_);
        this.setTab(CheatTab.TECHNOLOGY);
//        this.setTickRandomly(true);
    }

    public void setBlockBoundsBasedOnState(IWorldAccess worldIn, BlockPos pos)
    {
        this.setBlockBoundsBasedOnState0(worldIn.getState(pos));
    }

    protected void setBlockBoundsBasedOnState0(State state)
    {
        boolean flag = this.getRedstoneStrength(state) > 0;
        float f = 0.0625F;

        if (flag)
        {
            this.setBlockBounds(0.0625F, 0.0F, 0.0625F, 0.9375F, 0.03125F, 0.9375F);
        }
        else
        {
            this.setBlockBounds(0.0625F, 0.0F, 0.0625F, 0.9375F, 0.0625F, 0.9375F);
        }
    }

    /**
     * How many world ticks before ticking
     */
    public int tickRate(World worldIn, BlockPos pos)
    {
        return 20;
    }

    public BoundingBox getCollisionBoundingBox(World worldIn, BlockPos pos, State state)
    {
        return null;
    }

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

    public boolean isFullCube()
    {
        return false;
    }

    public boolean isPassable(IBlockAccess worldIn, BlockPos pos)
    {
        return true;
    }

    /**
     * Return true if an entity can be spawned inside the block (used to get the player's bed spawn location)
     */
    public boolean canSpawnInBlock()
    {
        return true;
    }

    public boolean canPlaceBlockAt(World worldIn, BlockPos pos)
    {
        return this.canBePlacedOn(worldIn, pos.down());
    }

    /**
     * Called when a neighboring block changes.
     */
    public void onNeighborBlockChange(World worldIn, BlockPos pos, State state, Block neighborBlock)
    {
        if (!this.canBePlacedOn(worldIn, pos.down()))
        {
            this.dropBlockAsItem(worldIn, pos, state, 0);
            worldIn.setBlockToAir(pos);
        }
    }

    private boolean canBePlacedOn(World worldIn, BlockPos pos)
    {
        return worldIn.isBlockSolid(pos) || worldIn.getState(pos).getBlock() instanceof BlockFence;
    }

    /**
     * Called randomly when setTickRandomly is set to true (used by e.g. crops to grow, etc.)
     */
    public void randomTick(AWorldServer worldIn, BlockPos pos, State state, Random random)
    {
    }

    public void updateTick(AWorldServer worldIn, BlockPos pos, State state, Random rand)
    {
//        if (!worldIn.client)
//        {
        int i = this.getRedstoneStrength(state);

        if (i > 0)
        {
            this.updateState(worldIn, pos, state, i);
        }
//        }
    }

    /**
     * Called When an Entity Collided with the Block
     */
    public void onEntityCollidedWithBlock(World worldIn, BlockPos pos, State state, Entity entityIn)
    {
        if (!worldIn.client)
        {
            int i = this.getRedstoneStrength(state);

            if (i == 0)
            {
                this.updateState(worldIn, pos, state, i);
            }
        }
    }

    /**
     * Updates the pressure plate when stepped on
     */
    protected void updateState(World worldIn, BlockPos pos, State state, int oldRedstoneStrength)
    {
        int i = this.computeRedstoneStrength(worldIn, pos);
        boolean flag = oldRedstoneStrength > 0;
        boolean flag1 = i > 0;

        if (oldRedstoneStrength != i)
        {
            state = this.setRedstoneStrength(state, i);
            worldIn.setState(pos, state, 2);
            this.updateNeighbors(worldIn, pos);
            worldIn.markBlockRangeForRenderUpdate(pos, pos);
        }

        if (!flag1 && flag)
        {
            worldIn.playSound(SoundEvent.CLICK, (double)pos.getX() + 0.5D, (double)pos.getY() + 0.1D, (double)pos.getZ() + 0.5D, 0.3F);
        }
        else if (flag1 && !flag)
        {
            worldIn.playSound(SoundEvent.CLICK, (double)pos.getX() + 0.5D, (double)pos.getY() + 0.1D, (double)pos.getZ() + 0.5D, 0.3F);
        }

        if (flag1)
        {
            worldIn.scheduleUpdate(pos, this, this.tickRate(worldIn, pos));
        }
    }

    /**
     * Returns the cubic AABB inset by 1/8 on all sides
     */
    protected BoundingBox getSensitiveAABB(BlockPos pos)
    {
        float f = 0.125F;
        return new BoundingBox((double)((float)pos.getX() + 0.125F), (double)pos.getY(), (double)((float)pos.getZ() + 0.125F), (double)((float)(pos.getX() + 1) - 0.125F), (double)pos.getY() + 0.25D, (double)((float)(pos.getZ() + 1) - 0.125F));
    }

    public void onBlockRemoved(AWorldServer worldIn, BlockPos pos, State state)
    {
        if (this.getRedstoneStrength(state) > 0)
        {
            this.updateNeighbors(worldIn, pos);
        }

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

    /**
     * Notify block and block below of changes
     */
    protected void updateNeighbors(World worldIn, BlockPos pos)
    {
        worldIn.notifyNeighborsOfStateChange(pos, this);
        worldIn.notifyNeighborsOfStateChange(pos.down(), this);
    }

    public int getWeakPower(IWorldAccess worldIn, BlockPos pos, State state, Facing side)
    {
        return this.getRedstoneStrength(state);
    }

    public int getStrongPower(IWorldAccess worldIn, BlockPos pos, State state, Facing side)
    {
        return side == Facing.UP ? this.getRedstoneStrength(state) : 0;
    }

    /**
     * Can this block provide power. Only wire currently seems to have this change based on its state.
     */
    public boolean canProvidePower()
    {
        return true;
    }

    /**
     * Sets the block's bounds for rendering it as an item
     */
    public void setBlockBoundsForItemRender()
    {
        float f = 0.5F;
        float f1 = 0.125F;
        float f2 = 0.5F;
        this.setBlockBounds(0.0F, 0.375F, 0.0F, 1.0F, 0.625F, 1.0F);
    }

    public int getMobilityFlag()
    {
        return 1;
    }

    public Model getModel(ModelProvider provider, String name, State state) {
    	if(this.getRedstoneStrength(state) > 0)
    		return provider.getModel(this.getTexture())
    				.add(1, 0, 1, 15, 0.5f, 15)
    					.d().uv(1, 1, 15, 15)
    					.u().uv(1, 1, 15, 15).noCull()
    					.n().uv(1, 15.5f, 15, 16).noCull()
    					.s().uv(1, 15.5f, 15, 16).noCull()
    					.w().uv(1, 15.5f, 15, 16).noCull()
    					.e().uv(1, 15.5f, 15, 16).noCull();
    	else
    		return provider.getModel(this.getTexture())
    				.add(1, 0, 1, 15, 1, 15)
    					.d().uv(1, 1, 15, 15)
    					.u().uv(1, 1, 15, 15).noCull()
    					.n().uv(1, 15, 15, 16).noCull()
    					.s().uv(1, 15, 15, 16).noCull()
    					.w().uv(1, 15, 15, 16).noCull()
    					.e().uv(1, 15, 15, 16).noCull();
    }
	
	protected Item getItemToRegister() {
		return new ItemPressurePlate(this);
	}
    
    public abstract String getTexture();

    protected abstract int computeRedstoneStrength(World worldIn, BlockPos pos);

    protected abstract int getRedstoneStrength(State state);

    protected abstract State setRedstoneStrength(State state, int strength);
}
