package common.block.tech;

import common.block.Block;
import common.block.BlockContainer;
import common.block.Material;
import common.entity.npc.EntityNPC;
import common.init.Blocks;
import common.item.Item;
import common.properties.Property;
import common.properties.PropertyEnum;
import common.rng.Random;
import common.tileentity.TileEntity;
import common.tileentity.TileEntityPiston;
import common.util.BlockPos;
import common.util.BoundingBox;
import common.util.Facing;
import common.util.HitPosition;
import common.util.Vec3;
import common.world.IWorldAccess;
import common.world.State;
import common.world.World;
import common.world.AWorldServer;

public class BlockPistonMoving extends BlockContainer
{
    public static final PropertyEnum<Facing> FACING = BlockPistonHead.FACING;
    public static final PropertyEnum<BlockPistonHead.EnumPistonType> TYPE = BlockPistonHead.TYPE;

    public BlockPistonMoving()
    {
        super(Material.PISTON);
        this.setDefaultState(this.getBaseState().withProperty(FACING, Facing.NORTH).withProperty(TYPE, BlockPistonHead.EnumPistonType.DEFAULT));
        this.setHardness(-1.0F);
    }

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

    public static TileEntity newTileEntity(State state, Facing facing, boolean extending, boolean renderHead)
    {
        return new TileEntityPiston(state, facing, extending, renderHead);
    }

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

        if (tileentity instanceof TileEntityPiston)
        {
            ((TileEntityPiston)tileentity).clearPistonTileEntity();
        }
        else
        {
            super.onBlockRemoved(worldIn, pos, state);
        }
    }

    public boolean canPlaceBlockAt(World worldIn, BlockPos pos)
    {
        return false;
    }

    /**
     * Check whether this Block can be placed on the given side
     */
    public boolean canPlaceBlockOnSide(World worldIn, BlockPos pos, Facing side)
    {
        return false;
    }

    /**
     * Called when a player destroys this Block
     */
    public void onBlockDestroyedByPlayer(World worldIn, BlockPos pos, State state)
    {
        BlockPos blockpos = pos.offset(((Facing)state.getValue(FACING)).getOpposite());
        State iblockstate = worldIn.getState(blockpos);

        if (iblockstate.getBlock() instanceof BlockPistonBase && ((Boolean)iblockstate.getValue(BlockPistonBase.EXTENDED)).booleanValue())
        {
            worldIn.setBlockToAir(blockpos);
        }
    }

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

    public boolean isFullCube()
    {
        return false;
    }

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

    /**
     * Get the Item that this Block should drop when harvested.
     */
    public Item getItemDropped(State state, Random rand, int fortune)
    {
        return null;
    }

    /**
     * Spawns this Block's drops into the World as EntityItems.
     */
    public void dropBlockAsItemWithChance(World worldIn, BlockPos pos, State state, float chance, int fortune)
    {
        if (!worldIn.client)
        {
            TileEntityPiston tileentitypiston = this.getTileEntity(worldIn, pos);

            if (tileentitypiston != null)
            {
                State iblockstate = tileentitypiston.getPistonState();
                iblockstate.getBlock().dropBlockAsItem(worldIn, pos, iblockstate, 0);
            }
        }
    }

    /**
     * Ray traces through the blocks collision from start vector to end vector returning a ray trace hit.
     */
    public HitPosition collisionRayTrace(World worldIn, BlockPos pos, Vec3 start, Vec3 end)
    {
        return null;
    }

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

    public BoundingBox getCollisionBoundingBox(World worldIn, BlockPos pos, State state)
    {
        TileEntityPiston tileentitypiston = this.getTileEntity(worldIn, pos);

        if (tileentitypiston == null)
        {
            return null;
        }
        else
        {
            float f = tileentitypiston.getProgress(0.0F);

            if (tileentitypiston.isExtending())
            {
                f = 1.0F - f;
            }

            return this.getBoundingBox(worldIn, pos, tileentitypiston.getPistonState(), f, tileentitypiston.getFacing());
        }
    }

    public void setBlockBoundsBasedOnState(IWorldAccess worldIn, BlockPos pos)
    {
        TileEntityPiston tileentitypiston = this.getTileEntity(worldIn, pos);

        if (tileentitypiston != null)
        {
            State iblockstate = tileentitypiston.getPistonState();
            Block block = iblockstate.getBlock();

            if (block == this || block == Blocks.air)
            {
                return;
            }

            float f = tileentitypiston.getProgress(0.0F);

            if (tileentitypiston.isExtending())
            {
                f = 1.0F - f;
            }

            block.setBlockBoundsBasedOnState(worldIn, pos);

            if (block == Blocks.piston || block == Blocks.sticky_piston)
            {
                f = 0.0F;
            }

            Facing enumfacing = tileentitypiston.getFacing();
            this.minX = block.getBlockBoundsMinX() - (double)((float)enumfacing.getFrontOffsetX() * f);
            this.minY = block.getBlockBoundsMinY() - (double)((float)enumfacing.getFrontOffsetY() * f);
            this.minZ = block.getBlockBoundsMinZ() - (double)((float)enumfacing.getFrontOffsetZ() * f);
            this.maxX = block.getBlockBoundsMaxX() - (double)((float)enumfacing.getFrontOffsetX() * f);
            this.maxY = block.getBlockBoundsMaxY() - (double)((float)enumfacing.getFrontOffsetY() * f);
            this.maxZ = block.getBlockBoundsMaxZ() - (double)((float)enumfacing.getFrontOffsetZ() * f);
        }
    }

    public BoundingBox getBoundingBox(World worldIn, BlockPos pos, State extendingBlock, float progress, Facing direction)
    {
        if (extendingBlock.getBlock() != this && extendingBlock.getBlock() != Blocks.air)
        {
            BoundingBox axisalignedbb = extendingBlock.getBlock().getCollisionBoundingBox(worldIn, pos, extendingBlock);

            if (axisalignedbb == null)
            {
                return null;
            }
            else
            {
                double d0 = axisalignedbb.minX;
                double d1 = axisalignedbb.minY;
                double d2 = axisalignedbb.minZ;
                double d3 = axisalignedbb.maxX;
                double d4 = axisalignedbb.maxY;
                double d5 = axisalignedbb.maxZ;

                if (direction.getFrontOffsetX() < 0)
                {
                    d0 -= (double)((float)direction.getFrontOffsetX() * progress);
                }
                else
                {
                    d3 -= (double)((float)direction.getFrontOffsetX() * progress);
                }

                if (direction.getFrontOffsetY() < 0)
                {
                    d1 -= (double)((float)direction.getFrontOffsetY() * progress);
                }
                else
                {
                    d4 -= (double)((float)direction.getFrontOffsetY() * progress);
                }

                if (direction.getFrontOffsetZ() < 0)
                {
                    d2 -= (double)((float)direction.getFrontOffsetZ() * progress);
                }
                else
                {
                    d5 -= (double)((float)direction.getFrontOffsetZ() * progress);
                }

                return new BoundingBox(d0, d1, d2, d3, d4, d5);
            }
        }
        else
        {
            return null;
        }
    }

    private TileEntityPiston getTileEntity(IWorldAccess worldIn, BlockPos pos)
    {
        TileEntity tileentity = worldIn.getTileEntity(pos);
        return tileentity instanceof TileEntityPiston ? (TileEntityPiston)tileentity : null;
    }

    public Item getItem(World worldIn, BlockPos pos)
    {
        return null;
    }

    /**
     * Convert the given metadata into a BlockState for this Block
     */
    public State getStateFromMeta(int meta)
    {
        return this.getState().withProperty(FACING, BlockPistonHead.getFacing(meta)).withProperty(TYPE, (meta & 8) > 0 ? BlockPistonHead.EnumPistonType.STICKY : BlockPistonHead.EnumPistonType.DEFAULT);
    }

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

        if (state.getValue(TYPE) == BlockPistonHead.EnumPistonType.STICKY)
        {
            i |= 8;
        }

        return i;
    }

    protected Property[] getProperties()
    {
        return new Property[] {FACING, TYPE};
    }
	
	protected Item getItemToRegister() {
		return null;
	}
}
