package net.glowstone.generator.objects;

import com.google.common.collect.ImmutableSortedSet;
import java.util.Random;
import java.util.SortedSet;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.material.DoublePlant;
import org.bukkit.material.MaterialData;
import org.bukkit.material.types.DoublePlantSpecies;

// TODO: Use this interface to reduce duplicate code in BlockPopulator subclasses.
// TODO: Refactor GenericTree to implement this class.

/**
 * A terrain feature that can randomly generate itself at specified locations, replacing blocks.
 */
@FunctionalInterface
public interface TerrainObject {
    /**
     * Plant block types.
     */
    SortedSet<Material> PLANT_TYPES = ImmutableSortedSet
            .of(Material.LONG_GRASS, Material.YELLOW_FLOWER, Material.RED_ROSE,
                    Material.DOUBLE_PLANT, Material.BROWN_MUSHROOM, Material.RED_MUSHROOM);

    /**
     * Removes the grass, shrub, flower or mushroom directly above the given block, if present. Does
     * not drop an item.
     *
     * @param block the block to update
     * @return true if a plant was removed; false if none was present
     */
    static boolean killPlantAbove(Block block) {
        Block blockAbove = block.getRelative(BlockFace.UP);
        Material mat = blockAbove.getType();
        if (PLANT_TYPES.contains(mat)) {
            if (mat == Material.DOUBLE_PLANT) {
                MaterialData dataAbove = blockAbove.getState().getData();
                if (dataAbove instanceof DoublePlant
                        && ((DoublePlant) dataAbove).getSpecies()
                        == DoublePlantSpecies.PLANT_APEX) {
                    blockAbove.getRelative(BlockFace.UP)
                            .setType(Material.AIR);
                }
            }
            blockAbove.setType(Material.AIR);
            return true;
        }
        return false;
    }

    /**
     * Generates this feature.
     *
     * @param world the world to generate in
     * @param random the PRNG that will choose the size and a few details of the shape
     * @param sourceX the base X coordinate
     * @param sourceY the base Y coordinate
     * @param sourceZ the base Z coordinate
     * @return true if successfully generated
     */
    boolean generate(World world, Random random, int sourceX, int sourceY, int sourceZ);
}

@@ -282,122 +282,67 @@
 kit.
-material.DoublePlant;%0Aimport org.bukkit.material.MaterialData;%0Aimport org.bukkit.material.types.DoublePlantSpecies
+block.data.Bisected;%0Aimport org.bukkit.block.data.BlockData
 ;%0A%0A/
@@ -736,16 +736,20 @@
 ortedSet
+.of(
 %0A       
@@ -757,165 +757,609 @@
     
-.of(Material.LONG_GRASS, Material.YELLOW_FLOWER, Material.RED_ROSE,%0A                    Material.DOUBLE_PLANT, Material.BROWN_MUSHROOM, Material.RED_MUSHROOM
+// Flowers%0A            Material.DANDELION,%0A            Material.POPPY,%0A            Material.BLUE_ORCHID,%0A            Material.ALLIUM,%0A            Material.AZURE_BLUET,%0A            Material.RED_TULIP,%0A            Material.ORANGE_TULIP,%0A            Material.WHITE_TULIP,%0A            Material.PINK_TULIP,%0A            Material.OXEYE_DAISY,%0A            Material.SUNFLOWER,%0A            Material.LILAC,%0A            Material.ROSE_BUSH,%0A            Material.PEONY,%0A            // Grass%0A            Material.GRASS,%0A            Material.FERN,%0A            Material.TALL_GRASS,%0A            Material.LARGE_FERN%0A    
 );%0A%0A
@@ -1726,16 +1726,78 @@
 ce.UP);%0A
+        BlockData blockAboveData = blockAbove.getBlockData();%0A
         
@@ -1825,16 +1825,24 @@
 bove
-.getType
+Data.getMaterial
 ();%0A
@@ -1902,378 +1902,448 @@
 if (
-mat == Material.DOUBLE_PLANT) %7B%0A                MaterialData dataAbove = blockAbove.getState().getData();%0A                if (dataAbove instanceof DoublePlant%0A                        && ((DoublePlant) dataAbove).getSpecies()%0A                        == DoublePlantSpecies.PLANT_APEX) %7B%0A                    blockAbove.getRelative(BlockFace.UP)%0A                            
+blockAboveData instanceof Bisected && ((Bisected) blockAboveData).getHalf() == Bisected.Half.BOTTOM) %7B%0A                // Large plant%0A                Block plantTop = blockAbove.getRelative(BlockFace.UP);%0A                BlockData plantTopData = plantTop.getBlockData();%0A                if (plantTopData.getMaterial() == mat &&%0A                        ((Bisected) plantTopData).getHalf() == Bisected.Half.TOP) %7B%0A                    plantTop
 .set
@@ -2570,16 +2570,18 @@
 m world 
+  
 the worl
@@ -2618,16 +2618,17 @@
  random 
+ 
 the PRNG

Update TerrainObject for 1.13