package common.block.artificial;

import java.util.List;

import common.block.Block;
import common.block.Material;
import common.collect.Lists;
import common.init.Blocks;
import common.item.CheatTab;
import common.item.Item;
import common.item.block.ItemWall;
import common.model.Model;
import common.model.ModelProvider;
import common.model.ModelRotation;
import common.properties.Property;
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 BlockWall extends Block
{
    public static final PropertyBool UP = PropertyBool.create("up");
    public static final PropertyBool NORTH = PropertyBool.create("north");
    public static final PropertyBool EAST = PropertyBool.create("east");
    public static final PropertyBool SOUTH = PropertyBool.create("south");
    public static final PropertyBool WEST = PropertyBool.create("west");
    public static final List<BlockWall> WALLS = Lists.newArrayList();
    
    private final String texture;

    public BlockWall(Block modelBlock, String texture)
    {
        super(modelBlock.getMaterial());
        this.texture = texture;
        this.setDefaultState(this.getBaseState().withProperty(UP, Boolean.valueOf(false)).withProperty(NORTH, Boolean.valueOf(false)).withProperty(EAST, Boolean.valueOf(false)).withProperty(SOUTH, Boolean.valueOf(false)).withProperty(WEST, Boolean.valueOf(false)));
        this.setHardness(modelBlock.getRawHardness());
        this.setResistance(modelBlock.getRawResistance() / 3.0F);
        this.setStepSound(modelBlock.sound);
        this.setTab(CheatTab.BLOCKS);
        WALLS.add(this);
    }
    
    public String getTexture() {
    	return this.texture;
    }

    public boolean isFullCube()
    {
        return false;
    }

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

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

    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.25F;
        float f1 = 0.75F;
        float f2 = 0.25F;
        float f3 = 0.75F;
        float f4 = 1.0F;

        if (flag)
        {
            f2 = 0.0F;
        }

        if (flag1)
        {
            f3 = 1.0F;
        }

        if (flag2)
        {
            f = 0.0F;
        }

        if (flag3)
        {
            f1 = 1.0F;
        }

        if (flag && flag1 && !flag2 && !flag3)
        {
            f4 = 0.8125F;
            f = 0.3125F;
            f1 = 0.6875F;
        }
        else if (!flag && !flag1 && flag2 && flag3)
        {
            f4 = 0.8125F;
            f2 = 0.3125F;
            f3 = 0.6875F;
        }

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

    public BoundingBox getCollisionBoundingBox(World worldIn, BlockPos pos, State state)
    {
        this.setBlockBoundsBasedOnState(worldIn, pos);
        this.maxY = 1.5D;
        return super.getCollisionBoundingBox(worldIn, pos, state);
    }

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

    public boolean shouldSideBeRendered(IWorldAccess worldIn, BlockPos pos, Facing side)
    {
        return side == Facing.DOWN ? super.shouldSideBeRendered(worldIn, pos, side) : true;
    }

    /**
     * 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(UP, Boolean.valueOf(worldIn.getState(pos.up()).getBlock() != Blocks.air)).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())));
    }

	public int getMetaFromState(State state) {
		return 0;
	}

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

    public Model getModel(ModelProvider provider, String name, State state) {
    	String wall = this.texture;
    	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(wall)
    				.add(4, 0, 4, 12, 16, 12)
    					.d().uv(4, 4, 12, 12)
    					.u().uv(4, 4, 12, 12)
    					.n().uv(4, 0, 12, 16).noCull()
    					.s().uv(4, 0, 12, 16).noCull()
    					.w().uv(4, 0, 12, 16).noCull()
    					.e().uv(4, 0, 12, 16).noCull();
        else if(sides == 4)
    		return provider.getModel(wall)
    				.add(4, 0, 4, 12, 16, 12)
    					.d().uv(4, 4, 12, 12)
    					.u().uv(4, 4, 12, 12)
    					.n().uv(4, 0, 12, 16).noCull()
    					.s().uv(4, 0, 12, 16).noCull()
    					.w().uv(4, 0, 12, 16).noCull()
    					.e().uv(4, 0, 12, 16).noCull()
    				.add(5, 0, 0, 11, 13, 4)
    					.d().uv(5, 0, 11, 4)
    					.u().uv(5, 0, 11, 4).noCull()
    					.n().uv(5, 3, 11, 16)
    					.w().uv(0, 3, 4, 16).noCull()
    					.e().uv(0, 3, 4, 16).noCull()
    				.add(5, 0, 12, 11, 13, 16)
    					.d().uv(5, 12, 11, 16)
    					.u().uv(5, 12, 11, 16).noCull()
    					.s().uv(5, 3, 11, 16)
    					.w().uv(12, 3, 16, 16).noCull()
    					.e().uv(12, 3, 16, 16).noCull()
    				.add(12, 0, 5, 16, 13, 11)
    					.d().uv(5, 12, 11, 16).rot(90)
    					.u().uv(5, 12, 11, 16).rot(90).noCull()
    					.n().uv(12, 3, 16, 16).noCull()
    					.s().uv(12, 3, 16, 16).noCull()
    					.e().uv(5, 3, 11, 16)
    				.add(0, 0, 5, 4, 13, 11)
    					.d().uv(5, 0, 11, 4).rot(90)
    					.u().uv(5, 0, 11, 4).rot(90).noCull()
    					.n().uv(0, 3, 4, 16).noCull()
    					.s().uv(0, 3, 4, 16).noCull()
    					.w().uv(5, 3, 11, 16);
    	else if(sides == 1)
    		return provider.getModel(wall).uvLock()
    				.add(4, 0, 4, 12, 16, 12)
    					.d().uv(4, 4, 12, 12)
    					.u().uv(4, 4, 12, 12)
    					.n().uv(4, 0, 12, 16).noCull()
    					.s().uv(4, 0, 12, 16).noCull()
    					.w().uv(4, 0, 12, 16).noCull()
    					.e().uv(4, 0, 12, 16).noCull()
    				.add(5, 0, 0, 11, 13, 4)
    					.d().uv(5, 0, 11, 4)
    					.u().uv(5, 0, 11, 4).noCull()
    					.n().uv(5, 3, 11, 16)
    					.w().uv(0, 3, 4, 16).noCull()
    					.e().uv(0, 3, 4, 16).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(wall).uvLock()
    				.add(4, 0, 4, 12, 16, 12)
    					.d().uv(4, 4, 12, 12)
    					.u().uv(4, 4, 12, 12)
    					.n().uv(4, 0, 12, 16).noCull()
    					.s().uv(4, 0, 12, 16).noCull()
    					.w().uv(4, 0, 12, 16).noCull()
    					.e().uv(4, 0, 12, 16).noCull()
    				.add(5, 0, 0, 11, 13, 4)
    					.d().uv(5, 0, 11, 4)
    					.u().uv(5, 0, 11, 4).noCull()
    					.n().uv(5, 3, 11, 16)
    					.w().uv(0, 3, 4, 16).noCull()
    					.e().uv(0, 3, 4, 16).noCull()
    				.add(12, 0, 5, 16, 13, 11)
    					.d().uv(5, 12, 11, 16).rot(90)
    					.u().uv(5, 12, 11, 16).rot(90).noCull()
    					.n().uv(12, 3, 16, 16).noCull()
    					.s().uv(12, 3, 16, 16).noCull()
    					.e().uv(5, 3, 11, 16)
    	        		.rotate(n && e ? ModelRotation.X0_Y0 : (s && w ? ModelRotation.X0_Y180 : 
    	        			(n && w ? ModelRotation.X0_Y270 : ModelRotation.X0_Y90)));
    	else if(sides == 2 && state.getValue(UP))
    		return provider.getModel(wall).uvLock()
    				.add(4, 0, 4, 12, 16, 12)
    					.d().uv(4, 4, 12, 12)
    					.u().uv(4, 4, 12, 12)
    					.n().uv(4, 0, 12, 16).noCull()
    					.s().uv(4, 0, 12, 16).noCull()
    					.w().uv(4, 0, 12, 16).noCull()
    					.e().uv(4, 0, 12, 16).noCull()
    				.add(5, 0, 0, 11, 13, 16)
    					.d().uv(5, 0, 11, 16)
    					.u().uv(5, 0, 11, 16).noCull()
    					.n().uv(5, 3, 11, 16)
    					.s().uv(5, 3, 11, 16)
    					.w().uv(0, 3, 16, 16).noCull()
    					.e().uv(0, 3, 16, 16).noCull()
        	        	.rotate(n ? ModelRotation.X0_Y0 : ModelRotation.X0_Y90);
        else if(sides == 2)
    		return provider.getModel(wall).uvLock()
    				.add(5, 0, 0, 11, 13, 16)
    					.d().uv(5, 0, 11, 16)
    					.u().uv(5, 0, 11, 16).noCull()
    					.n().uv(5, 3, 11, 16)
    					.s().uv(5, 3, 11, 16)
    					.w().uv(0, 3, 16, 16).noCull()
    					.e().uv(0, 3, 16, 16).noCull()
        	        	.rotate(n ? ModelRotation.X0_Y0 : ModelRotation.X0_Y90);
        else
    		return provider.getModel(wall).uvLock()
    				.add(4, 0, 4, 12, 16, 12)
    					.d().uv(4, 4, 12, 12)
    					.u().uv(4, 4, 12, 12)
    					.n().uv(4, 0, 12, 16).noCull()
    					.s().uv(4, 0, 12, 16).noCull()
    					.w().uv(4, 0, 12, 16).noCull()
    					.e().uv(4, 0, 12, 16).noCull()
    				.add(5, 0, 0, 11, 13, 4)
    					.d().uv(5, 0, 11, 4)
    					.u().uv(5, 0, 11, 4).noCull()
    					.n().uv(5, 3, 11, 16)
    					.w().uv(0, 3, 4, 16).noCull()
    					.e().uv(0, 3, 4, 16).noCull()
    				.add(5, 0, 12, 11, 13, 16)
    					.d().uv(5, 12, 11, 16)
    					.u().uv(5, 12, 11, 16).noCull()
    					.s().uv(5, 3, 11, 16)
    					.w().uv(12, 3, 16, 16).noCull()
    					.e().uv(12, 3, 16, 16).noCull()
    				.add(12, 0, 5, 16, 13, 11)
    					.d().uv(5, 12, 11, 16).rot(90)
    					.u().uv(5, 12, 11, 16).rot(90).noCull()
    					.n().uv(12, 3, 16, 16).noCull()
    					.s().uv(12, 3, 16, 16).noCull()
    					.e().uv(5, 3, 11, 16)
        	        	.rotate(!w ? ModelRotation.X0_Y0 : (!e ? ModelRotation.X0_Y180 : (!s ? ModelRotation.X0_Y270 : ModelRotation.X0_Y90)));
    }
	
	protected Item getItemToRegister() {
		return new ItemWall(this);
	}
}
