package common.block.tech;

import common.block.Block;
import common.block.DirectionalUp;
import common.block.Material;
import common.block.artificial.BlockFence;
import common.block.artificial.BlockStainedGlass;
import common.entity.types.EntityLiving;
import common.init.Blocks;
import common.item.CheatTab;
import common.model.BlockLayer;
import common.model.Model;
import common.model.ModelProvider;
import common.model.ModelRotation;
import common.model.ParticleType;
import common.properties.Property;
import common.rng.Random;
import common.util.BlockPos;
import common.util.BoundingBox;
import common.util.Facing;
import common.util.HitPosition;
import common.util.Vec3;
import common.world.AWorldClient;
import common.world.State;
import common.world.World;
import common.world.AWorldServer;

public class BlockTorch extends Block implements DirectionalUp
{
	private static boolean isBlockNormalCube(World world, BlockPos pos, boolean def) {
		if(!World.isValid(pos) || (world.client && !world.isBlockLoaded(pos, false)))
			return def;
		Block block = world.getState(pos).getBlock();
		return block.getMaterial().isOpaque() && block.isFullCube();
	}

    public BlockTorch()
    {
        super(Material.SMALL);
        this.setDefaultState(this.getBaseState().withProperty(FACING, Facing.UP));
//        this.setTickRandomly(true);
        this.setTab(CheatTab.TECHNOLOGY);
        this.setFlatItemTexture();
    }

    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;
    }

    private boolean canPlaceOn(World worldIn, BlockPos pos)
    {
        if (worldIn.isBlockSolid(pos))
        {
            return true;
        }
        else
        {
            Block block = worldIn.getState(pos).getBlock();
            return block instanceof BlockFence || block == Blocks.glass || block == Blocks.cobblestone_wall || block instanceof BlockStainedGlass;
        }
    }

    public boolean canPlaceBlockAt(World worldIn, BlockPos pos)
    {
        for (Facing enumfacing : FACING.getStates())
        {
            if (this.canPlaceAt(worldIn, pos, enumfacing))
            {
                return true;
            }
        }

        return false;
    }

    private boolean canPlaceAt(World worldIn, BlockPos pos, Facing facing)
    {
        BlockPos blockpos = pos.offset(facing.getOpposite());
        boolean flag = facing.getAxis().isHorizontal();
        return flag && isBlockNormalCube(worldIn, blockpos, true) || facing.equals(Facing.UP) && this.canPlaceOn(worldIn, blockpos);
    }

    /**
     * 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)
    {
        if (this.canPlaceAt(worldIn, pos, facing))
        {
            return this.getState().withProperty(FACING, facing);
        }
        else
        {
            for (Facing enumfacing : Facing.Plane.HORIZONTAL)
            {
                if (isBlockNormalCube(worldIn, pos.offset(enumfacing.getOpposite()), true))
                {
                    return this.getState().withProperty(FACING, enumfacing);
                }
            }

            return this.getState();
        }
    }

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

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

    protected boolean onNeighborChangeInternal(World worldIn, BlockPos pos, State state)
    {
        if (!this.checkForDrop(worldIn, pos, state))
        {
            return true;
        }
        else
        {
            Facing enumfacing = (Facing)state.getValue(FACING);
            Facing.Axis enumfacing$axis = enumfacing.getAxis();
            Facing enumfacing1 = enumfacing.getOpposite();
            boolean flag = false;

            if (enumfacing$axis.isHorizontal() && !isBlockNormalCube(worldIn, pos.offset(enumfacing1), true))
            {
                flag = true;
            }
            else if (enumfacing$axis.isVertical() && !this.canPlaceOn(worldIn, pos.offset(enumfacing1)))
            {
                flag = true;
            }

            if (flag)
            {
                this.dropBlockAsItem(worldIn, pos, state, 0);
                worldIn.setBlockToAir(pos);
                return true;
            }
            else
            {
                return false;
            }
        }
    }

    protected boolean checkForDrop(World worldIn, BlockPos pos, State state)
    {
        if (state.getBlock() == this && this.canPlaceAt(worldIn, pos, (Facing)state.getValue(FACING)))
        {
            return true;
        }
        else
        {
            if (worldIn.getState(pos).getBlock() == this)
            {
                this.dropBlockAsItem(worldIn, pos, state, 0);
                worldIn.setBlockToAir(pos);
            }

            return false;
        }
    }

    /**
     * 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)
    {
        Facing enumfacing = (Facing)worldIn.getState(pos).getValue(FACING);
        float f = 0.15F;

        if (enumfacing == Facing.EAST)
        {
            this.setBlockBounds(0.0F, 0.2F, 0.5F - f, f * 2.0F, 0.8F, 0.5F + f);
        }
        else if (enumfacing == Facing.WEST)
        {
            this.setBlockBounds(1.0F - f * 2.0F, 0.2F, 0.5F - f, 1.0F, 0.8F, 0.5F + f);
        }
        else if (enumfacing == Facing.SOUTH)
        {
            this.setBlockBounds(0.5F - f, 0.2F, 0.0F, 0.5F + f, 0.8F, f * 2.0F);
        }
        else if (enumfacing == Facing.NORTH)
        {
            this.setBlockBounds(0.5F - f, 0.2F, 1.0F - f * 2.0F, 0.5F + f, 0.8F, 1.0F);
        }
        else
        {
            f = 0.1F;
            this.setBlockBounds(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, 0.6F, 0.5F + f);
        }

        return super.collisionRayTrace(worldIn, pos, start, end);
    }

    public void randomDisplayTick(AWorldClient worldIn, BlockPos pos, State state, Random rand)
    {
        Facing enumfacing = (Facing)state.getValue(FACING);
        double d0 = (double)pos.getX() + 0.5D;
        double d1 = (double)pos.getY() + 0.7D;
        double d2 = (double)pos.getZ() + 0.5D;
        double d3 = 0.22D;
        double d4 = 0.27D;

        if (enumfacing.getAxis().isHorizontal())
        {
            Facing enumfacing1 = enumfacing.getOpposite();
            worldIn.spawnParticle(ParticleType.SMOKE_NORMAL, d0 + d4 * (double)enumfacing1.getFrontOffsetX(), d1 + d3, d2 + d4 * (double)enumfacing1.getFrontOffsetZ(), 0.0D, 0.0D, 0.0D);
            worldIn.spawnParticle(ParticleType.FLAME, d0 + d4 * (double)enumfacing1.getFrontOffsetX(), d1 + d3, d2 + d4 * (double)enumfacing1.getFrontOffsetZ(), 0.0D, 0.0D, 0.0D);
        }
        else
        {
            worldIn.spawnParticle(ParticleType.SMOKE_NORMAL, d0, d1, d2, 0.0D, 0.0D, 0.0D);
            worldIn.spawnParticle(ParticleType.FLAME, d0, d1, d2, 0.0D, 0.0D, 0.0D);
        }
    }

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

    /**
     * Convert the given metadata into a BlockState for this Block
     */
    public State getStateFromMeta(int meta)
    {
        State iblockstate = this.getState();

        switch (meta)
        {
            case 1:
                iblockstate = iblockstate.withProperty(FACING, Facing.EAST);
                break;

            case 2:
                iblockstate = iblockstate.withProperty(FACING, Facing.WEST);
                break;

            case 3:
                iblockstate = iblockstate.withProperty(FACING, Facing.SOUTH);
                break;

            case 4:
                iblockstate = iblockstate.withProperty(FACING, Facing.NORTH);
                break;

            case 5:
            default:
                iblockstate = iblockstate.withProperty(FACING, Facing.UP);
        }

        return iblockstate;
    }

    /**
     * Convert the BlockState into the correct metadata value
     */
    public int getMetaFromState(State state)
    {
        int i = 0;

        switch ((Facing)state.getValue(FACING))
        {
            case EAST:
                i = i | 1;
                break;

            case WEST:
                i = i | 2;
                break;

            case SOUTH:
                i = i | 3;
                break;

            case NORTH:
                i = i | 4;
                break;

            case DOWN:
            case UP:
            default:
                i = i | 5;
        }

        return i;
    }

    protected Property[] getProperties()
    {
        return new Property[] {FACING};
    }

    public Model getModel(ModelProvider provider, String name, State state) {
    	if(state.getValue(FACING) == Facing.UP)
    		return provider.getModel(name)
    				.add(7, 0, 7, 9, 10, 9).noShade()
    					.d().uv(7, 13, 9, 15).noCull()
    					.u().uv(7, 6, 9, 8).noCull()
    				.add(7, 0, 0, 9, 16, 16).noShade()
    					.w().uv(0, 0, 16, 16).noCull()
    					.e().uv(0, 0, 16, 16).noCull()
    				.add(0, 0, 7, 16, 16, 9).noShade()
    					.n().uv(0, 0, 16, 16).noCull()
    					.s().uv(0, 0, 16, 16).noCull();
    	else
    		return provider.getModel(name)
    			.add(-1, 3.5f, 7, 1, 13.5f, 9).noShade().rotate(0, 3.5f, 8, Facing.Axis.Z, -22.5f, false)
    				.d().uv(7, 13, 9, 15).noCull()
    				.u().uv(7, 6, 9, 8).noCull()
    			.add(-1, 3.5f, 0, 1, 19.5f, 16).noShade().rotate(0, 3.5f, 8, Facing.Axis.Z, -22.5f, false)
    				.w().uv(0, 0, 16, 16).noCull()
    				.e().uv(0, 0, 16, 16).noCull()
    			.add(-8, 3.5f, 7, 8, 19.5f, 9).noShade().rotate(0, 3.5f, 8, Facing.Axis.Z, -22.5f, false)
    				.n().uv(0, 0, 16, 16).noCull()
    				.s().uv(0, 0, 16, 16).noCull()
    				.rotate(ModelRotation.getEastRot(state.getValue(FACING), false));
    }
}
