package net.glowstone.block.blocktype;

import net.glowstone.EventFactory;
import net.glowstone.GlowWorld;
import net.glowstone.block.GlowBlock;
import net.glowstone.block.GlowBlockState;
import net.glowstone.block.ItemTable;
import net.glowstone.entity.GlowPlayer;
import net.glowstone.generator.objects.FlowerType;
import net.glowstone.generator.populators.overworld.FlowerForestPopulator;
import org.bukkit.GrassSpecies;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.event.block.BlockFadeEvent;
import org.bukkit.event.block.BlockGrowEvent;
import org.bukkit.event.block.BlockSpreadEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.material.LongGrass;

public class BlockGrass extends BlockType implements IBlockGrowable {

    public BlockGrass() {
        setDrops(new ItemStack(Material.DIRT, 1));
    }

    @Override
    public boolean isFertilizable(GlowBlock block) {
        return true;
    }

    @Override
    public boolean canTickRandomly() {
        return true;
    }

    @Override
    public boolean canGrowWithChance(GlowBlock block) {
        return true;
    }

    @Override
    public void grow(GlowPlayer player, GlowBlock block) {
        GlowWorld world = block.getWorld();

        int i = 0;
        do {
            int j = 0;

            while (true) {
                // if there's available space
                if (block.getRelative(BlockFace.UP).getType() == Material.AIR) {
                    GlowBlock b = block.getRelative(BlockFace.UP);
                    GlowBlockState blockState = b.getState();
                    if (random.nextFloat() < 0.125D) {
                        // sometimes grow random flower
                        // would be better to call a method that choose a random
                        // flower depending on the biome
                        FlowerType[] flowers = FlowerForestPopulator.FLOWERS;
                        Material flower = flowers[random.nextInt(flowers.length)].getType();
                        if (ItemTable.instance().getBlock(flower).canPlaceAt(b, BlockFace.DOWN)) {
                            blockState.setType(flower);
                        }
                    } else {
                        Material tallGrass = Material.LONG_GRASS;
                        if (ItemTable.instance().getBlock(tallGrass).canPlaceAt(b, BlockFace.DOWN)) {
                            // grow tall grass if possible
                            blockState.setType(tallGrass);
                            blockState.setData(new LongGrass(GrassSpecies.NORMAL));
                        }
                    }
                    BlockGrowEvent growEvent = new BlockGrowEvent(b, blockState);
                    EventFactory.callEvent(growEvent);
                    if (!growEvent.isCancelled()) {
                        blockState.update(true);
                    }
                } else if (j < i / 16) { // look around for grass block
                    int x = block.getX();
                    int y = block.getY();
                    int z = block.getZ();
                    x += random.nextInt(3) - 1;
                    y += random.nextInt(3) * random.nextInt(3) / 2;
                    z += random.nextInt(3) - 1;
                    if (world.getBlockAt(x, y, z).getType() == Material.GRASS) {
                        j++;
                        continue;
                    }
                }
                i++;
                break;
            }
        } while (i < 128);
    }

    @Override
    public void updateBlock(GlowBlock block) {
        GlowBlock blockAbove = block.getRelative(BlockFace.UP);
        if (blockAbove.getLightLevel() < 4 && blockAbove.getMaterialValues().getLightOpacity() > 2) {
            // grass block turns into dirt block
            GlowBlockState state = block.getState();
            state.setType(Material.DIRT);
            BlockFadeEvent fadeEvent = new BlockFadeEvent(block, state);
            EventFactory.callEvent(fadeEvent);
            if (!fadeEvent.isCancelled()) {
                state.update(true);
            }
        } else if (block.getLightLevel() >= 9) {
            GlowWorld world = block.getWorld();
            int sourceX = block.getX();
            int sourceY = block.getY();
            int sourceZ = block.getZ();

            // grass spread randomly around
            for (int i = 0; i < 4; i++) {
                int x = sourceX + random.nextInt(3) - 1;
                int z = sourceZ + random.nextInt(3) - 1;
                int y = sourceY + random.nextInt(5) - 3;

                GlowBlock targetBlock = world.getBlockAt(x, y, z);
                if (targetBlock.getType() == Material.DIRT &&
                        targetBlock.getData() == 0 && // only spread on normal dirt
                        targetBlock.getRelative(BlockFace.UP).getMaterialValues().getLightOpacity() <= 2 &&
                        targetBlock.getRelative(BlockFace.UP).getLightLevel() >= 4) {
                    GlowBlockState state = targetBlock.getState();
                    state.setType(Material.GRASS);
                    state.setRawData((byte) 0);
                    BlockSpreadEvent spreadEvent = new BlockSpreadEvent(state.getBlock(), block, state);
                    EventFactory.callEvent(spreadEvent);
                    if (!spreadEvent.isCancelled()) {
                        state.update(true);
                    }
                }
            }
        }
    }
}

@@ -4135,24 +4135,29 @@
 se if (block
+Above
 .getLightLev
@@ -4165,24 +4165,24 @@
 l() %3E= 9) %7B%0A
-
             
@@ -4663,16 +4663,95 @@
  y, z);%0A
+                GlowBlock targetAbove = targetBlock.getRelative(BlockFace.UP);%0A
         
@@ -4922,39 +4922,13 @@
 rget
-Block.getRelative(BlockFace.UP)
+Above
 .get
@@ -5004,39 +5004,13 @@
 rget
-Block.getRelative(BlockFace.UP)
+Above
 .get
@@ -5272,22 +5272,19 @@
 ent(
-s
 ta
-te.
+r
 getBlock
 (), 
@@ -5279,18 +5279,16 @@
 getBlock
-()
 , block,

update grass spread