package common.block;

import common.color.Colorizer;
import common.entity.npc.EntityNPC;
import common.entity.types.EntityLiving;
import common.init.Blocks;
import common.init.Config;
import common.item.CheatTab;
import common.item.Item;
import common.item.ItemShears;
import common.item.ItemStack;
import common.material.Material;
import common.model.BlockLayer;
import common.model.Model;
import common.model.ModelProvider;
import common.model.ModelRotation;
import common.properties.IProperty;
import common.properties.PropertyBool;
import common.rng.Random;
import common.tileentity.TileEntity;
import common.util.BlockPos;
import common.util.BoundingBox;
import common.util.Facing;
import common.world.IWorldAccess;
import common.world.State;
import common.world.World;
import common.world.AWorldServer;

public class BlockVine 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 PropertyBool[] ALL_FACES = new PropertyBool[] {UP, NORTH, SOUTH, WEST, EAST};

    public BlockVine()
    {
        super(Material.vine);
        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.setTickRandomly();
        this.setTab(CheatTab.tabPlants);
    }

    /**
     * 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().isBlockNormalCube()));
    }

    /**
     * Sets the block's bounds for rendering it as an item
     */
    public void setBlockBoundsForItemRender()
    {
        this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
    }

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

    public boolean isFullCube()
    {
        return false;
    }

    /**
     * Whether this Block can be replaced directly by other blocks (true for e.g. tall grass)
     */
    public boolean isReplaceable(World worldIn, BlockPos pos)
    {
        return true;
    }

    public void setBlockBoundsBasedOnState(IWorldAccess worldIn, BlockPos pos)
    {
        float f = 0.0625F;
        float f1 = 1.0F;
        float f2 = 1.0F;
        float f3 = 1.0F;
        float f4 = 0.0F;
        float f5 = 0.0F;
        float f6 = 0.0F;
        boolean flag = false;

        if (((Boolean)worldIn.getState(pos).getValue(WEST)).booleanValue())
        {
            f4 = Math.max(f4, 0.0625F);
            f1 = 0.0F;
            f2 = 0.0F;
            f5 = 1.0F;
            f3 = 0.0F;
            f6 = 1.0F;
            flag = true;
        }

        if (((Boolean)worldIn.getState(pos).getValue(EAST)).booleanValue())
        {
            f1 = Math.min(f1, 0.9375F);
            f4 = 1.0F;
            f2 = 0.0F;
            f5 = 1.0F;
            f3 = 0.0F;
            f6 = 1.0F;
            flag = true;
        }

        if (((Boolean)worldIn.getState(pos).getValue(NORTH)).booleanValue())
        {
            f6 = Math.max(f6, 0.0625F);
            f3 = 0.0F;
            f1 = 0.0F;
            f4 = 1.0F;
            f2 = 0.0F;
            f5 = 1.0F;
            flag = true;
        }

        if (((Boolean)worldIn.getState(pos).getValue(SOUTH)).booleanValue())
        {
            f3 = Math.min(f3, 0.9375F);
            f6 = 1.0F;
            f1 = 0.0F;
            f4 = 1.0F;
            f2 = 0.0F;
            f5 = 1.0F;
            flag = true;
        }

        if (!flag && this.canPlaceOn(worldIn.getState(pos.up()).getBlock()))
        {
            f2 = Math.min(f2, 0.9375F);
            f5 = 1.0F;
            f1 = 0.0F;
            f4 = 1.0F;
            f3 = 0.0F;
            f6 = 1.0F;
        }

        this.setBlockBounds(f1, f2, f3, f4, f5, f6);
    }

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

    /**
     * Check whether this Block can be placed on the given side
     */
    public boolean canPlaceBlockOnSide(World worldIn, BlockPos pos, Facing side)
    {
        switch (side)
        {
            case UP:
                return this.canPlaceOn(worldIn.getState(pos.up()).getBlock());

            case NORTH:
            case SOUTH:
            case EAST:
            case WEST:
                return this.canPlaceOn(worldIn.getState(pos.offset(side.getOpposite())).getBlock());

            default:
                return false;
        }
    }

    private boolean canPlaceOn(Block blockIn)
    {
        return blockIn.isFullCube() && blockIn.material.blocksMovement();
    }

    private boolean recheckGrownSides(World worldIn, BlockPos pos, State state)
    {
        State iblockstate = state;

        for (Facing enumfacing : Facing.Plane.HORIZONTAL)
        {
            PropertyBool propertybool = getPropertyFor(enumfacing);

            if (((Boolean)state.getValue(propertybool)).booleanValue() && !this.canPlaceOn(worldIn.getState(pos.offset(enumfacing)).getBlock()))
            {
                State iblockstate1 = worldIn.getState(pos.up());

                if (iblockstate1.getBlock() != this || !((Boolean)iblockstate1.getValue(propertybool)).booleanValue())
                {
                    state = state.withProperty(propertybool, Boolean.valueOf(false));
                }
            }
        }

        if (getNumGrownFaces(state) == 0)
        {
            return false;
        }
        else
        {
            if (iblockstate != state)
            {
                worldIn.setState(pos, state, 2);
            }

            return true;
        }
    }

//    public int getBlockColor()
//    {
//        return ColorizerFoliage.getFoliageColorBasic();
//    }

    public int getRenderColor(State state)
    {
        return Colorizer.BASIC.getColor();
    }

    public int colorMultiplier(IWorldAccess worldIn, BlockPos pos, int renderPass)
    {
        return worldIn.getBiomeGenForCoords(pos).getFoliageColorAtPos(pos);
    }

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

    public void updateTick(AWorldServer worldIn, BlockPos pos, State state, Random rand)
    {
        if(Config.vineDry && worldIn.getTemperatureC(pos) >= 50.0f)
        {
        	worldIn.setBlockToAir(pos);
        	return;
        }
//        if (!worldIn.client)
//        {
        if (Config.vineGrowth > 0 && worldIn.rand.chance(Config.vineGrowth))
        {
            int i = 4;
            int j = 5;
            boolean flag = false;
            label62:

            for (int k = -i; k <= i; ++k)
            {
                for (int l = -i; l <= i; ++l)
                {
                    for (int i1 = -1; i1 <= 1; ++i1)
                    {
                        if (worldIn.getState(pos.add(k, i1, l)).getBlock() == this)
                        {
                            --j;

                            if (j <= 0)
                            {
                                flag = true;
                                break label62;
                            }
                        }
                    }
                }
            }

            Facing enumfacing1 = Facing.random(rand);
            BlockPos blockpos1 = pos.up();

            if (enumfacing1 == Facing.UP && pos.getY() < 511 && worldIn.isAirBlock(blockpos1))
            {
                if (!flag)
                {
                    State iblockstate2 = state;

                    for (Facing enumfacing3 : Facing.Plane.HORIZONTAL)
                    {
                        if (rand.chance() || !this.canPlaceOn(worldIn.getState(blockpos1.offset(enumfacing3)).getBlock()))
                        {
                            iblockstate2 = iblockstate2.withProperty(getPropertyFor(enumfacing3), Boolean.valueOf(false));
                        }
                    }

                    if (((Boolean)iblockstate2.getValue(NORTH)).booleanValue() || ((Boolean)iblockstate2.getValue(EAST)).booleanValue() || ((Boolean)iblockstate2.getValue(SOUTH)).booleanValue() || ((Boolean)iblockstate2.getValue(WEST)).booleanValue())
                    {
                        worldIn.setState(blockpos1, iblockstate2, 2);
                    }
                }
            }
            else if (enumfacing1.getAxis().isHorizontal() && !((Boolean)state.getValue(getPropertyFor(enumfacing1))).booleanValue())
            {
                if (!flag)
                {
                    BlockPos blockpos3 = pos.offset(enumfacing1);
                    Block block1 = worldIn.getState(blockpos3).getBlock();

                    if (block1.material == Material.air)
                    {
                        Facing enumfacing2 = enumfacing1.rotateY();
                        Facing enumfacing4 = enumfacing1.rotateYCCW();
                        boolean flag1 = ((Boolean)state.getValue(getPropertyFor(enumfacing2))).booleanValue();
                        boolean flag2 = ((Boolean)state.getValue(getPropertyFor(enumfacing4))).booleanValue();
                        BlockPos blockpos4 = blockpos3.offset(enumfacing2);
                        BlockPos blockpos = blockpos3.offset(enumfacing4);

                        if (flag1 && this.canPlaceOn(worldIn.getState(blockpos4).getBlock()))
                        {
                            worldIn.setState(blockpos3, this.getState().withProperty(getPropertyFor(enumfacing2), Boolean.valueOf(true)), 2);
                        }
                        else if (flag2 && this.canPlaceOn(worldIn.getState(blockpos).getBlock()))
                        {
                            worldIn.setState(blockpos3, this.getState().withProperty(getPropertyFor(enumfacing4), Boolean.valueOf(true)), 2);
                        }
                        else if (flag1 && worldIn.isAirBlock(blockpos4) && this.canPlaceOn(worldIn.getState(pos.offset(enumfacing2)).getBlock()))
                        {
                            worldIn.setState(blockpos4, this.getState().withProperty(getPropertyFor(enumfacing1.getOpposite()), Boolean.valueOf(true)), 2);
                        }
                        else if (flag2 && worldIn.isAirBlock(blockpos) && this.canPlaceOn(worldIn.getState(pos.offset(enumfacing4)).getBlock()))
                        {
                            worldIn.setState(blockpos, this.getState().withProperty(getPropertyFor(enumfacing1.getOpposite()), Boolean.valueOf(true)), 2);
                        }
                        else if (this.canPlaceOn(worldIn.getState(blockpos3.up()).getBlock()))
                        {
                            worldIn.setState(blockpos3, this.getState(), 2);
                        }
                    }
                    else if (block1.material.isOpaque() && block1.isFullCube())
                    {
                        worldIn.setState(pos, state.withProperty(getPropertyFor(enumfacing1), Boolean.valueOf(true)), 2);
                    }
                }
            }
            else
            {
                if (pos.getY() > 1)
                {
                    BlockPos blockpos2 = pos.down();
                    State iblockstate = worldIn.getState(blockpos2);
                    Block block = iblockstate.getBlock();

                    if (block.material == Material.air)
                    {
                        State iblockstate1 = state;

                        for (Facing enumfacing : Facing.Plane.HORIZONTAL)
                        {
                            if (rand.chance())
                            {
                                iblockstate1 = iblockstate1.withProperty(getPropertyFor(enumfacing), Boolean.valueOf(false));
                            }
                        }

                        if (((Boolean)iblockstate1.getValue(NORTH)).booleanValue() || ((Boolean)iblockstate1.getValue(EAST)).booleanValue() || ((Boolean)iblockstate1.getValue(SOUTH)).booleanValue() || ((Boolean)iblockstate1.getValue(WEST)).booleanValue())
                        {
                            worldIn.setState(blockpos2, iblockstate1, 2);
                        }
                    }
                    else if (block == this)
                    {
                        State iblockstate3 = iblockstate;

                        for (Facing enumfacing5 : Facing.Plane.HORIZONTAL)
                        {
                            PropertyBool propertybool = getPropertyFor(enumfacing5);

                            if (rand.chance() && ((Boolean)state.getValue(propertybool)).booleanValue())
                            {
                                iblockstate3 = iblockstate3.withProperty(propertybool, Boolean.valueOf(true));
                            }
                        }

                        if (((Boolean)iblockstate3.getValue(NORTH)).booleanValue() || ((Boolean)iblockstate3.getValue(EAST)).booleanValue() || ((Boolean)iblockstate3.getValue(SOUTH)).booleanValue() || ((Boolean)iblockstate3.getValue(WEST)).booleanValue())
                        {
                            worldIn.setState(blockpos2, iblockstate3, 2);
                        }
                    }
                }
            }
        }
//        }
    }

    /**
     * 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, int meta, EntityLiving placer)
    {
        State iblockstate = this.getState().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));
        return facing.getAxis().isHorizontal() ? iblockstate.withProperty(getPropertyFor(facing.getOpposite()), Boolean.valueOf(true)) : iblockstate;
    }

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

    /**
     * Returns the quantity of items to drop on block destruction.
     */
    public int quantityDropped(Random random)
    {
        return 0;
    }

    public void harvestBlock(World worldIn, EntityNPC player, BlockPos pos, State state, TileEntity te)
    {
        if (!worldIn.client && player.getCurrentEquippedItem() != null && player.getCurrentEquippedItem().getItem() instanceof ItemShears)
        {
//            player.triggerAchievement(StatRegistry.mineBlockStatArray[BlockRegistry.getIdFromBlock(this)]);
            spawnAsEntity(worldIn, pos, new ItemStack(Blocks.vine, 1, 0));
        }
        else
        {
            super.harvestBlock(worldIn, player, pos, state, te);
        }
    }

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

    /**
     * Convert the given metadata into a BlockState for this Block
     */
    public State getStateFromMeta(int meta)
    {
        return this.getState().withProperty(SOUTH, Boolean.valueOf((meta & 1) > 0)).withProperty(WEST, Boolean.valueOf((meta & 2) > 0)).withProperty(NORTH, Boolean.valueOf((meta & 4) > 0)).withProperty(EAST, Boolean.valueOf((meta & 8) > 0));
    }

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

        if (((Boolean)state.getValue(SOUTH)).booleanValue())
        {
            i |= 1;
        }

        if (((Boolean)state.getValue(WEST)).booleanValue())
        {
            i |= 2;
        }

        if (((Boolean)state.getValue(NORTH)).booleanValue())
        {
            i |= 4;
        }

        if (((Boolean)state.getValue(EAST)).booleanValue())
        {
            i |= 8;
        }

        return i;
    }

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

    public static PropertyBool getPropertyFor(Facing side)
    {
        switch (side)
        {
            case UP:
                return UP;

            case NORTH:
                return NORTH;

            case SOUTH:
                return SOUTH;

            case EAST:
                return EAST;

            case WEST:
                return WEST;

            default:
                throw new IllegalArgumentException(side + " is an invalid choice");
        }
    }

    public static int getNumGrownFaces(State state)
    {
        int i = 0;

        for (PropertyBool propertybool : ALL_FACES)
        {
            if (((Boolean)state.getValue(propertybool)).booleanValue())
            {
                ++i;
            }
        }

        return i;
    }

    public Model getModel(ModelProvider provider, String name, State state) {
    	Model model = provider.getModel("vine").noOcclude();
    	if(state.getValue(UP))
    		model.add(0, 15.2f, 0, 16, 15.2f, 16).noShade()
				.d().uv(0, 0, 16, 16).tint().noCull()
				.u().uv(0, 0, 16, 16).tint().noCull();
    	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 && !state.getValue(UP)) {
    		sides = 1;
    		s = true;
    	}
    	if(sides == 4) {
    		return model.add(0.8f, 0, 0, 0.8f, 16, 16).noShade()
    				.w().uv(0, 0, 16, 16).tint().noCull()
    				.e().uv(0, 0, 16, 16).tint().noCull()
    			.add(15.2f, 0, 0, 15.2f, 16, 16).noShade()
    				.w().uv(0, 0, 16, 16).tint().noCull()
    				.e().uv(0, 0, 16, 16).tint().noCull()
    			.add(0, 0, 15.2f, 16, 16, 15.2f).noShade()
    				.n().uv(0, 0, 16, 16).tint().noCull()
    				.s().uv(0, 0, 16, 16).tint().noCull()
    			.add(0, 0, 0.8f, 16, 16, 0.8f).noShade()
    				.n().uv(0, 0, 16, 16).tint().noCull()
    				.s().uv(0, 0, 16, 16).tint().noCull();
    	}
    	else if(sides == 1) {
    		return model.add(0, 0, 15.2f, 16, 16, 15.2f).noShade()
    				.n().uv(0, 0, 16, 16).tint().noCull()
    				.s().uv(0, 0, 16, 16).tint().noCull()
    				.rotate(s ? ModelRotation.X0_Y0 : (n ? ModelRotation.X0_Y180 : (e ? ModelRotation.X0_Y270 : ModelRotation.X0_Y90)));
    	}
    	else if(sides == 2 && ((e != w) || (n != s))) {
    		return model.add(0, 0, 0.8f, 16, 16, 0.8f).noShade()
    				.n().uv(0, 0, 16, 16).tint().noCull()
    				.s().uv(0, 0, 16, 16).tint().noCull()
    			.add(15.2f, 0, 0, 15.2f, 16, 16).noShade()
    				.w().uv(0, 0, 16, 16).tint().noCull()
    				.e().uv(0, 0, 16, 16).tint().noCull()
    				.rotate(n && e ? ModelRotation.X0_Y0 : (s && w ? ModelRotation.X0_Y180 : 
    					(n && w ? ModelRotation.X0_Y270 : ModelRotation.X0_Y90)));
    	}
    	else if(sides == 2) {
    		return model.add(15.2f, 0, 0, 15.2f, 16, 16).noShade()
    				.w().uv(0, 0, 16, 16).tint().noCull()
    				.e().uv(0, 0, 16, 16).tint().noCull()
    			.add(0.8f, 0, 0, 0.8f, 16, 16).noShade()
    				.w().uv(0, 0, 16, 16).tint().noCull()
    				.e().uv(0, 0, 16, 16).tint().noCull()
    				.rotate(e ? ModelRotation.X0_Y0 : ModelRotation.X0_Y90);
    	}
    	else if(sides == 3) {
    		return model.add(15.2f, 0, 0, 15.2f, 16, 16).noShade()
    				.w().uv(0, 0, 16, 16).tint().noCull()
    				.e().uv(0, 0, 16, 16).tint().noCull()
    			.add(0, 0, 15.2f, 16, 16, 15.2f).noShade()
    				.n().uv(0, 0, 16, 16).tint().noCull()
    				.s().uv(0, 0, 16, 16).tint().noCull()
    			.add(0, 0, 0.8f, 16, 16, 0.8f).noShade()
    				.n().uv(0, 0, 16, 16).tint().noCull()
    				.s().uv(0, 0, 16, 16).tint().noCull()
    				.rotate(!w ? ModelRotation.X0_Y0 : (!e ? ModelRotation.X0_Y180 : (!s ? ModelRotation.X0_Y270 : ModelRotation.X0_Y90)));
    	}
    	else {
    		return model;
    	}
    }
}
