package common.block.foliage;

import common.block.Block;
import common.block.DirectionalUp;
import common.init.Blocks;
import common.init.Items;
import common.item.CheatTab;
import common.item.Item;
import common.item.ItemStack;
import common.item.block.ItemSeeds;
import common.model.Model;
import common.model.ModelProvider;
import common.model.ModelRotation;
import common.properties.Property;
import common.properties.PropertyInteger;
import common.rng.Random;
import common.util.BlockPos;
import common.util.Facing;
import common.vars.Vars;
import common.world.IWorldAccess;
import common.world.State;
import common.world.World;
import common.world.AWorldServer;

public class BlockStem extends BlockBush implements DirectionalUp, IGrowable
{
    public static final PropertyInteger AGE = PropertyInteger.create("age", 0, 7);
    
    private final Block crop;
    private final String itemName;

    public BlockStem(Block crop, String itemName)
    {
        this.setDefaultState(this.getBaseState().withProperty(AGE, Integer.valueOf(0)).withProperty(FACING, Facing.UP));
        this.crop = crop;
        this.itemName = itemName;
        this.setTickRandomly();
        float f = 0.125F;
        this.setBlockBounds(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, 0.25F, 0.5F + f);
        this.setTab((CheatTab)null);
    }

    /**
     * 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)
    {
        state = state.withProperty(FACING, Facing.UP);

        for (Facing enumfacing : Facing.Plane.HORIZONTAL)
        {
            if (worldIn.getState(pos.offset(enumfacing)).getBlock() == this.crop)
            {
                state = state.withProperty(FACING, enumfacing);
                break;
            }
        }

        return state;
    }

    /**
     * is the block grass, dirt or farmland
     */
    protected boolean canPlaceBlockOn(Block ground)
    {
        return ground == Blocks.farmland;
    }

    public void updateTick(AWorldServer worldIn, BlockPos pos, State state, Random rand)
    {
        super.updateTick(worldIn, pos, state, rand);

        if (Vars.stemGrowth > 0 && worldIn.getLightFromNeighbors(pos.up()) >= 9)
        {
            float f = BlockCrops.getGrowthChance(this, worldIn, pos);

            if (rand.chance((int)((float)(Vars.stemGrowth - 1) / f) + 1))
            {
                int i = ((Integer)state.getValue(AGE)).intValue();

                if (i < 7)
                {
                    state = state.withProperty(AGE, Integer.valueOf(i + 1));
                    worldIn.setState(pos, state, 2);
                }
                else
                {
                    for (Facing enumfacing : Facing.Plane.HORIZONTAL)
                    {
                        if (worldIn.getState(pos.offset(enumfacing)).getBlock() == this.crop)
                        {
                            return;
                        }
                    }

                    pos = pos.offset(Facing.Plane.HORIZONTAL.random(rand));
                    Block block = worldIn.getState(pos.down()).getBlock();

                    if (worldIn.getState(pos).getBlock() == Blocks.air && (block == Blocks.farmland || block == Blocks.dirt || block == Blocks.grass))
                    {
                        worldIn.setState(pos, this.crop.getState());
                    }
                }
            }
        }
    }

    public void growStem(World worldIn, BlockPos pos, State state)
    {
        int i = ((Integer)state.getValue(AGE)).intValue() + worldIn.rand.range(2, 5);
        worldIn.setState(pos, state.withProperty(AGE, Integer.valueOf(Math.min(7, i))), 2);
    }

    public int getRenderColor(State state)
    {
        if (state.getBlock() != this)
        {
            return super.getRenderColor(state);
        }
        else
        {
            int i = ((Integer)state.getValue(AGE)).intValue();
            int j = i * 32;
            int k = 255 - i * 8;
            int l = i * 4;
            return j << 16 | k << 8 | l;
        }
    }

    public int colorMultiplier(IWorldAccess worldIn, BlockPos pos, int renderPass)
    {
        return this.getRenderColor(worldIn.getState(pos));
    }

    /**
     * Sets the block's bounds for rendering it as an item
     */
    public void setBlockBoundsForItemRender()
    {
        float f = 0.125F;
        this.setBlockBounds(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, 0.25F, 0.5F + f);
    }

    public void setBlockBoundsBasedOnState(IWorldAccess worldIn, BlockPos pos)
    {
        this.maxY = (double)((float)(((Integer)worldIn.getState(pos).getValue(AGE)).intValue() * 2 + 2) / 16.0F);
        float f = 0.125F;
        this.setBlockBounds(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, (float)this.maxY, 0.5F + f);
    }

    /**
     * Spawns this Block's drops into the World as EntityItems.
     */
    public void dropBlockAsItemWithChance(World worldIn, BlockPos pos, State state, float chance, int fortune)
    {
        super.dropBlockAsItemWithChance(worldIn, pos, state, chance, fortune);

        if (!worldIn.client)
        {
            Item item = this.getSeedItem();

            if (item != null)
            {
                int i = ((Integer)state.getValue(AGE)).intValue();

                for (int j = 0; j < 3; ++j)
                {
                    if (worldIn.rand.zrange(15) <= i)
                    {
                        spawnAsEntity(worldIn, pos, new ItemStack(item));
                    }
                }
            }
        }
    }

    protected Item getSeedItem()
    {
        return this.crop == Blocks.pumpkin ? Items.pumpkin_stem : (this.crop == Blocks.melon_block ? Items.melon_stem : null);
    }

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

    public Item getItem(World worldIn, BlockPos pos)
    {
        Item item = this.getSeedItem();
        return item != null ? item : null;
    }

    /**
     * Whether this IGrowable can grow
     */
    public boolean canGrow(World worldIn, BlockPos pos, State state, boolean isClient)
    {
        return ((Integer)state.getValue(AGE)).intValue() != 7;
    }

    public boolean canUseBonemeal(World worldIn, Random rand, BlockPos pos, State state)
    {
        return true;
    }

    public void grow(AWorldServer worldIn, Random rand, BlockPos pos, State state)
    {
        this.growStem(worldIn, pos, state);
    }

    /**
     * Convert the given metadata into a BlockState for this Block
     */
    public State getStateFromMeta(int meta)
    {
        return this.getState().withProperty(AGE, Integer.valueOf(meta > 7 ? 0 : meta));
    }

    /**
     * Convert the BlockState into the correct metadata value
     */
    public int getMetaFromState(State state)
    {
        return ((Integer)state.getValue(AGE)).intValue();
    }

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

    public Model getModel(ModelProvider provider, String name, State state) {
    	String stem = name;
    	String upperstem = name + "_connected";
    	if(state.getValue(FACING) == Facing.UP) {
    		switch(state.getValue(AGE)) {
    		case 0:
    			return provider.getModel(stem)
    					.add(0, -1, 8, 16, 1, 8).rotate(8, 8, 8, Facing.Axis.Y, 45, true)
    						.n().uv(0, 0, 16, 2).tint().noCull()
    						.s().uv(16, 0, 0, 2).tint().noCull()
    					.add(8, -1, 0, 8, 1, 16).rotate(8, 8, 8, Facing.Axis.Y, 45, true)
    						.w().uv(0, 0, 16, 2).tint().noCull()
    						.e().uv(16, 0, 0, 2).tint().noCull();
    		case 1:
    			return provider.getModel(stem)
    					.add(0, -1, 8, 16, 3, 8).rotate(8, 8, 8, Facing.Axis.Y, 45, true)
    						.n().uv(0, 0, 16, 4).tint().noCull()
    						.s().uv(16, 0, 0, 4).tint().noCull()
    					.add(8, -1, 0, 8, 3, 16).rotate(8, 8, 8, Facing.Axis.Y, 45, true)
    						.w().uv(0, 0, 16, 4).tint().noCull()
    						.e().uv(16, 0, 0, 4).tint().noCull();
    		case 2:
    			return provider.getModel(stem)
    					.add(0, -1, 8, 16, 5, 8).rotate(8, 8, 8, Facing.Axis.Y, 45, true)
    						.n().uv(0, 0, 16, 6).tint().noCull()
    						.s().uv(16, 0, 0, 6).tint().noCull()
    					.add(8, -1, 0, 8, 5, 16).rotate(8, 8, 8, Facing.Axis.Y, 45, true)
    						.w().uv(0, 0, 16, 6).tint().noCull()
    						.e().uv(16, 0, 0, 6).tint().noCull();
    		case 3:
    			return provider.getModel(stem)
    					.add(0, -1, 8, 16, 7, 8).rotate(8, 8, 8, Facing.Axis.Y, 45, true)
    						.n().uv(0, 0, 16, 8).tint().noCull()
    						.s().uv(16, 0, 0, 8).tint().noCull()
    					.add(8, -1, 0, 8, 7, 16).rotate(8, 8, 8, Facing.Axis.Y, 45, true)
    						.w().uv(0, 0, 16, 8).tint().noCull()
    						.e().uv(16, 0, 0, 8).tint().noCull();
    		case 4:
    			return provider.getModel(stem)
    					.add(0, -1, 8, 16, 9, 8).rotate(8, 8, 8, Facing.Axis.Y, 45, true)
    						.n().uv(0, 0, 16, 10).tint().noCull()
    						.s().uv(16, 0, 0, 10).tint().noCull()
    					.add(8, -1, 0, 8, 9, 16).rotate(8, 8, 8, Facing.Axis.Y, 45, true)
    						.w().uv(0, 0, 16, 10).tint().noCull()
    						.e().uv(16, 0, 0, 10).tint().noCull();
    		case 5:
    			return provider.getModel(stem)
    					.add(0, -1, 8, 16, 11, 8).rotate(8, 8, 8, Facing.Axis.Y, 45, true)
    						.n().uv(0, 0, 16, 12).tint().noCull()
    						.s().uv(16, 0, 0, 12).tint().noCull()
    					.add(8, -1, 0, 8, 11, 16).rotate(8, 8, 8, Facing.Axis.Y, 45, true)
    						.w().uv(0, 0, 16, 12).tint().noCull()
    						.e().uv(16, 0, 0, 12).tint().noCull();
    		case 6:
    			return provider.getModel(stem)
    					.add(0, -1, 8, 16, 13, 8).rotate(8, 8, 8, Facing.Axis.Y, 45, true)
    						.n().uv(0, 0, 16, 14).tint().noCull()
    						.s().uv(16, 0, 0, 14).tint().noCull()
    					.add(8, -1, 0, 8, 13, 16).rotate(8, 8, 8, Facing.Axis.Y, 45, true)
    						.w().uv(0, 0, 16, 14).tint().noCull()
    						.e().uv(16, 0, 0, 14).tint().noCull();
    		case 7:
    		default:
    			return provider.getModel(stem)
    					.add(0, -1, 8, 16, 15, 8).rotate(8, 8, 8, Facing.Axis.Y, 45, true)
    						.n().uv(0, 0, 16, 16).tint().noCull()
    						.s().uv(16, 0, 0, 16).tint().noCull()
    					.add(8, -1, 0, 8, 15, 16).rotate(8, 8, 8, Facing.Axis.Y, 45, true)
    						.w().uv(0, 0, 16, 16).tint().noCull()
    						.e().uv(16, 0, 0, 16).tint().noCull();
    		}
    	}
    	else {
    		return provider.getModel(stem)
    			.add(0, -1, 8, 16, 7, 8).rotate(8, 8, 8, Facing.Axis.Y, 45, true)
    				.n().uv(0, 0, 16, 8).tint().noCull()
    				.s().uv(16, 0, 0, 8).tint().noCull()
    			.add(8, -1, 0, 8, 7, 16).rotate(8, 8, 8, Facing.Axis.Y, 45, true)
    				.w().uv(0, 0, 16, 8).tint().noCull()
    				.e().uv(16, 0, 0, 8).tint().noCull()
    			.add(0, 0, 8, 9, 16, 8)
    				.n(upperstem).uv(9, 0, 0, 16).tint().noCull()
    				.s(upperstem).uv(0, 0, 9, 16).tint().noCull()
    				.rotate(ModelRotation.getEastRot(state.getValue(FACING).getOpposite(), false));
    	}
    }
	
	protected Item getItemToRegister() {
		return new ItemSeeds(this, Blocks.farmland).setDisplay(this.itemName).setMaxAmount(256);
	}
}
