package common.block;

import java.util.List;

import common.collect.Lists;
import common.entity.Entity;
import common.entity.npc.EntityNPC;
import common.item.CheatTab;
import common.item.ItemLead;
import common.material.Material;
import common.model.Model;
import common.model.ModelProvider;
import common.model.ModelRotation;
import common.model.Transforms;
import common.properties.IProperty;
import common.properties.PropertyBool;
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;

public class BlockFence extends Block
{
    /** Whether this fence connects in the northern direction */
    public static final PropertyBool NORTH = PropertyBool.create("north");

    /** Whether this fence connects in the eastern direction */
    public static final PropertyBool EAST = PropertyBool.create("east");

    /** Whether this fence connects in the southern direction */
    public static final PropertyBool SOUTH = PropertyBool.create("south");

    /** Whether this fence connects in the western direction */
    public static final PropertyBool WEST = PropertyBool.create("west");
    public static final List<BlockFence> FENCES = Lists.newArrayList();
    
    private final String texture;

    public BlockFence(Material p_i46395_1_, String texture)
    {
        super(p_i46395_1_);
        this.setDefaultState(this.getBaseState().withProperty(NORTH, Boolean.valueOf(false)).withProperty(EAST, Boolean.valueOf(false)).withProperty(SOUTH, Boolean.valueOf(false)).withProperty(WEST, Boolean.valueOf(false)));
        this.setTab(p_i46395_1_ == Material.wood ? CheatTab.tabWood : CheatTab.tabBlocks);
        this.texture = texture;
        FENCES.add(this);
    }

    /**
     * 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)
    {
        boolean flag = this.canConnectTo(worldIn, pos.north());
        boolean flag1 = this.canConnectTo(worldIn, pos.south());
        boolean flag2 = this.canConnectTo(worldIn, pos.west());
        boolean flag3 = this.canConnectTo(worldIn, pos.east());
        float f = 0.375F;
        float f1 = 0.625F;
        float f2 = 0.375F;
        float f3 = 0.625F;

        if (flag)
        {
            f2 = 0.0F;
        }

        if (flag1)
        {
            f3 = 1.0F;
        }

        if (flag || flag1)
        {
            this.setBlockBounds(f, 0.0F, f2, f1, 1.5F, f3);
            super.addCollisionBoxesToList(worldIn, pos, state, mask, list, collidingEntity);
        }

        f2 = 0.375F;
        f3 = 0.625F;

        if (flag2)
        {
            f = 0.0F;
        }

        if (flag3)
        {
            f1 = 1.0F;
        }

        if (flag2 || flag3 || !flag && !flag1)
        {
            this.setBlockBounds(f, 0.0F, f2, f1, 1.5F, f3);
            super.addCollisionBoxesToList(worldIn, pos, state, mask, list, collidingEntity);
        }

        if (flag)
        {
            f2 = 0.0F;
        }

        if (flag1)
        {
            f3 = 1.0F;
        }

        this.setBlockBounds(f, 0.0F, f2, f1, 1.0F, f3);
    }

    public void setBlockBoundsBasedOnState(IWorldAccess worldIn, BlockPos pos)
    {
        boolean flag = this.canConnectTo(worldIn, pos.north());
        boolean flag1 = this.canConnectTo(worldIn, pos.south());
        boolean flag2 = this.canConnectTo(worldIn, pos.west());
        boolean flag3 = this.canConnectTo(worldIn, pos.east());
        float f = 0.375F;
        float f1 = 0.625F;
        float f2 = 0.375F;
        float f3 = 0.625F;

        if (flag)
        {
            f2 = 0.0F;
        }

        if (flag1)
        {
            f3 = 1.0F;
        }

        if (flag2)
        {
            f = 0.0F;
        }

        if (flag3)
        {
            f1 = 1.0F;
        }

        this.setBlockBounds(f, 0.0F, f2, f1, 1.0F, f3);
    }

    /**
     * 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 false;
    }

    public boolean canConnectTo(IBlockAccess worldIn, BlockPos pos)
    {
        Block block = worldIn.getState(pos).getBlock();
        return ((!(block instanceof BlockFence) || block.material != this.material) && !(block instanceof BlockFenceGate) ? (block.material.isOpaque() && block.isFullCube() ? block.material != Material.gourd : false) : true);
    }

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

    public boolean onBlockActivated(World worldIn, BlockPos pos, State state, EntityNPC playerIn, Facing side, float hitX, float hitY, float hitZ)
    {
        return worldIn.client ? true : ItemLead.attachToFence(playerIn, worldIn, pos);
    }

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

    /**
     * Get the actual Block state of this Block at the given position. This applies properties not visible in the
     * metadata, such as fence connections.
     */
    public State getActualState(State state, IWorldAccess worldIn, BlockPos pos)
    {
        return state.withProperty(NORTH, Boolean.valueOf(this.canConnectTo(worldIn, pos.north()))).withProperty(EAST, Boolean.valueOf(this.canConnectTo(worldIn, pos.east()))).withProperty(SOUTH, Boolean.valueOf(this.canConnectTo(worldIn, pos.south()))).withProperty(WEST, Boolean.valueOf(this.canConnectTo(worldIn, pos.west())));
    }

    protected IProperty[] getProperties()
    {
        return new IProperty[] {NORTH, EAST, WEST, SOUTH};
    }

    public Transforms getTransform() {
    	return Transforms.FENCE;
    }
    
    public String getTexture() {
    	return this.texture;
    }

    public Model getModel(ModelProvider provider, String name, State state) {
    	boolean n = state.getValue(NORTH);
    	boolean s = state.getValue(SOUTH);
    	boolean w = state.getValue(WEST);
    	boolean e = state.getValue(EAST);
    	int sides = (n ? 1 : 0) + (s ? 1 : 0) + (w ? 1 : 0) + (e ? 1 : 0);
    	if(sides == 0)
    		return provider.getModel(this.texture)
    				.add(6, 0, 6, 10, 16, 10)
    					.d().uv(6, 6, 10, 10)
    					.u().uv(6, 6, 10, 10)
    					.n().uv(6, 0, 10, 16).noCull()
    					.s().uv(6, 0, 10, 16).noCull()
    					.w().uv(6, 0, 10, 16).noCull()
    					.e().uv(6, 0, 10, 16).noCull();
    	else if(sides == 4)
    		return provider.getModel(this.texture).uvLock()
    				.add(6, 0, 6, 10, 16, 10)
    					.d().uv(6, 6, 10, 10)
    					.u().uv(6, 6, 10, 10)
    					.n().uv(6, 0, 10, 16).noCull()
    					.s().uv(6, 0, 10, 16).noCull()
    					.w().uv(6, 0, 10, 16).noCull()
    					.e().uv(6, 0, 10, 16).noCull()
    				.add(7, 12, 0, 9, 15, 16)
    					.d().uv(7, 0, 9, 16).noCull()
    					.u().uv(7, 0, 9, 16).noCull()
    					.n().uv(7, 1, 9, 4)
    					.s().uv(7, 1, 9, 4)
    					.w().uv(0, 1, 16, 4).noCull()
    					.e().uv(0, 1, 16, 4).noCull()
    				.add(7, 6, 0, 9, 9, 16)
    					.d().uv(7, 0, 9, 16).noCull()
    					.u().uv(7, 0, 9, 16).noCull()
    					.n().uv(7, 7, 9, 10)
    					.s().uv(7, 7, 9, 10)
    					.w().uv(0, 7, 16, 10).noCull()
    					.e().uv(0, 7, 16, 10).noCull()
    				.add(0, 12, 7, 16, 15, 9)
    					.d().uv(0, 7, 16, 9).noCull()
    					.u().uv(0, 7, 16, 9).noCull()
    					.n().uv(0, 1, 16, 4).noCull()
    					.s().uv(0, 1, 16, 4).noCull()
    					.w().uv(7, 1, 9, 4)
    					.e().uv(7, 1, 9, 4)
    				.add(0, 6, 7, 16, 9, 9)
    					.d().uv(0, 7, 16, 9).noCull()
    					.u().uv(0, 7, 16, 9).noCull()
    					.n().uv(0, 7, 16, 10).noCull()
    					.s().uv(0, 7, 16, 10).noCull()
    					.w().uv(7, 7, 9, 10)
    					.e().uv(7, 7, 9, 10);
    	else if(sides == 1)
    		return provider.getModel(this.texture).uvLock()
    				.add(6, 0, 6, 10, 16, 10)
    					.d().uv(6, 6, 10, 10)
    					.u().uv(6, 6, 10, 10)
    					.n().uv(6, 0, 10, 16).noCull()
    					.s().uv(6, 0, 10, 16).noCull()
    					.w().uv(6, 0, 10, 16).noCull()
    					.e().uv(6, 0, 10, 16).noCull()
    				.add(7, 12, 0, 9, 15, 9)
    					.d().uv(7, 0, 9, 9).noCull()
    					.u().uv(7, 0, 9, 9).noCull()
    					.n().uv(7, 1, 9, 4)
    					.w().uv(0, 1, 9, 4).noCull()
    					.e().uv(0, 1, 9, 4).noCull()
    				.add(7, 6, 0, 9, 9, 9)
    					.d().uv(7, 0, 9, 9).noCull()
    					.u().uv(7, 0, 9, 9).noCull()
    					.n().uv(7, 7, 9, 10)
    					.w().uv(0, 7, 9, 10).noCull()
    					.e().uv(0, 7, 9, 10).noCull()
    				.rotate(n ? ModelRotation.X0_Y0 : (s ? ModelRotation.X0_Y180 : (w ? ModelRotation.X0_Y270 : ModelRotation.X0_Y90)));
    	else if(sides == 2 && ((e != w) || (n != s)))
    		return provider.getModel(this.texture).uvLock()
    				.add(6, 0, 6, 10, 16, 10)
    					.d().uv(6, 6, 10, 10)
    					.u().uv(6, 6, 10, 10)
    					.n().uv(6, 0, 10, 16).noCull()
    					.s().uv(6, 0, 10, 16).noCull()
    					.w().uv(6, 0, 10, 16).noCull()
    					.e().uv(6, 0, 10, 16).noCull()
    				.add(7, 12, 0, 9, 15, 9)
    					.d().uv(7, 0, 9, 9).noCull()
    					.u().uv(7, 0, 9, 9).noCull()
    					.n().uv(7, 1, 9, 4)
    					.w().uv(0, 1, 9, 4).noCull()
    					.e().uv(0, 1, 9, 4).noCull()
    				.add(7, 6, 0, 9, 9, 9)
    					.d().uv(7, 0, 9, 9).noCull()
    					.u().uv(7, 0, 9, 9).noCull()
    					.n().uv(7, 7, 9, 10)
    					.w().uv(0, 7, 9, 10).noCull()
    					.e().uv(0, 7, 9, 10).noCull()
    				.add(7, 12, 7, 16, 15, 9)
    					.d().uv(7, 7, 16, 9).noCull()
    					.u().uv(7, 7, 16, 9).noCull()
    					.n().uv(7, 1, 16, 4).noCull()
    					.s().uv(7, 1, 16, 4).noCull()
    					.e().uv(7, 1, 9, 4)
    				.add(7, 6, 7, 16, 9, 9)
    					.d().uv(7, 7, 16, 9).noCull()
    					.u().uv(7, 7, 16, 9).noCull()
    					.n().uv(7, 7, 16, 10).noCull()
    					.s().uv(7, 7, 16, 10).noCull()
    					.e().uv(7, 7, 9, 10)
	        		.rotate(n && e ? ModelRotation.X0_Y0 : (s && w ? ModelRotation.X0_Y180 : 
	        			(n && w ? ModelRotation.X0_Y270 : ModelRotation.X0_Y90)));
    	else if(sides == 2)
    		return provider.getModel(this.texture).uvLock()
    				.add(6, 0, 6, 10, 16, 10)
    					.d().uv(6, 6, 10, 10)
    					.u().uv(6, 6, 10, 10)
    					.n().uv(6, 0, 10, 16).noCull()
    					.s().uv(6, 0, 10, 16).noCull()
    					.w().uv(6, 0, 10, 16).noCull()
    					.e().uv(6, 0, 10, 16).noCull()
    				.add(7, 12, 0, 9, 15, 16)
    					.d().uv(7, 0, 9, 16).noCull()
    					.u().uv(7, 0, 9, 16).noCull()
    					.n().uv(7, 1, 9, 4)
    					.s().uv(7, 1, 9, 4)
    					.w().uv(0, 1, 16, 4).noCull()
    					.e().uv(0, 1, 16, 4).noCull()
    				.add(7, 6, 0, 9, 9, 16)
    					.d().uv(7, 0, 9, 16).noCull()
    					.u().uv(7, 0, 9, 16).noCull()
    					.n().uv(7, 7, 9, 10)
    					.s().uv(7, 7, 9, 10)
    					.w().uv(0, 7, 16, 10).noCull()
    					.e().uv(0, 7, 16, 10).noCull()
    	        	.rotate(n ? ModelRotation.X0_Y0 : ModelRotation.X0_Y90);
    	else
    		return provider.getModel(this.texture).uvLock()
    				.add(6, 0, 6, 10, 16, 10)
    					.d().uv(6, 6, 10, 10)
    					.u().uv(6, 6, 10, 10)
    					.n().uv(6, 0, 10, 16).noCull()
    					.s().uv(6, 0, 10, 16).noCull()
    					.w().uv(6, 0, 10, 16).noCull()
    					.e().uv(6, 0, 10, 16).noCull()
    				.add(7, 12, 0, 9, 15, 16)
    					.d().uv(7, 0, 9, 16).noCull()
    					.u().uv(7, 0, 9, 16).noCull()
    					.n().uv(7, 1, 9, 4)
    					.s().uv(7, 1, 9, 4)
    					.w().uv(0, 1, 16, 4).noCull()
    					.e().uv(0, 1, 16, 4).noCull()
    				.add(7, 6, 0, 9, 9, 16)
    					.d().uv(7, 0, 9, 16).noCull()
    					.u().uv(7, 0, 9, 16).noCull()
    					.n().uv(7, 7, 9, 10)
    					.s().uv(7, 7, 9, 10)
    					.w().uv(0, 7, 16, 10).noCull()
    					.e().uv(0, 7, 16, 10).noCull()
    				.add(7, 12, 7, 16, 15, 9)
    					.d().uv(7, 7, 16, 9).noCull()
    					.u().uv(7, 7, 16, 9).noCull()
    					.n().uv(7, 1, 16, 4).noCull()
    					.s().uv(7, 1, 16, 4).noCull()
    					.e().uv(7, 1, 9, 4)
    				.add(7, 6, 7, 16, 9, 9)
    					.d().uv(7, 7, 16, 9).noCull()
    					.u().uv(7, 7, 16, 9).noCull()
    					.n().uv(7, 7, 16, 10).noCull()
    					.s().uv(7, 7, 16, 10).noCull()
    					.e().uv(7, 7, 9, 10)
    	        	.rotate(!w ? ModelRotation.X0_Y0 : (!e ? ModelRotation.X0_Y180 : (!s ? ModelRotation.X0_Y270 : ModelRotation.X0_Y90)));
    }
}
