package org.cyclops.cyclopscore.helper;

import net.minecraft.block.Block;
import net.minecraft.block.properties.IProperty;
import net.minecraft.block.state.IBlockState;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.common.property.IExtendedBlockState;
import net.minecraftforge.common.property.IUnlistedProperty;
import org.apache.commons.lang3.tuple.Pair;

import javax.annotation.Nullable;
import java.util.List;

/**
 * Contains helper methods for various block specific things.
 * @author rubensworks
 */
public final class BlockHelpers {

    /**
     * Safely get a block state property for a nullable state and value that may not have been set yet.
     * @param state The block state.
     * @param property The property to get the value for.
     * @param fallback The fallback value when something has failed.
     * @param <T> The type of value to fetch.
     * @return The value.
     */
    @SuppressWarnings("unchecked")
    public static <T> T getSafeBlockStateProperty(@Nullable IBlockState state, IProperty property, T fallback) {
        if(state == null) {
            return fallback;
        }
        Comparable value = state.getValue(property);
        if(value == null) {
            return fallback;
        }
        return (T) value;
    }

    /**
     * Safely get an extended block state property for a nullable state and value that may not have been set yet.
     * @param state The block state.
     * @param property The property to get the value for.
     * @param fallback The fallback value when something has failed.
     * @param <T> The type of value to fetch.
     * @return The value.
     */
    public static <T> T getSafeBlockStateProperty(@Nullable IExtendedBlockState state, IUnlistedProperty<T> property,
                                                  T fallback) {
        if(state == null) {
            return fallback;
        }
        T value = state.getValue(property);
        if(value == null) {
            return fallback;
        }
        return value;
    }

    /**
     * Convert the given blockstate to a pair of blockname string and meta value.
     * @param blockState The blockstate to serialize.
     * @return The pair of the blockname and meta value.
     */
    public static Pair<String, Integer> serializeBlockState(IBlockState blockState) {
        String blockName = Block.blockRegistry.getNameForObject(blockState.getBlock()).toString();
        int meta = blockState.getBlock().getMetaFromState(blockState);
        return Pair.of(blockName, meta);
    }

    /**
     * Convert the given serialized blockstate to a blockstate instance.
     * @param serializedBlockState The pair of the blockname and meta value.
     * @return The resulting blockstate. Can be null if the referred block does not exist.
     */
    public static IBlockState deserializeBlockState(Pair<String, Integer> serializedBlockState) {
        Block block = Block.getBlockFromName(serializedBlockState.getLeft());
        if(block != null) {
            return block.getStateFromMeta(serializedBlockState.getRight());
        }
        return null;
    }

    /**
     * Get the blockstate from the given itemstack
     * @param itemStack The itemstack
     * @return The blockstate
     */
    public static IBlockState getBlockStateFromItemStack(ItemStack itemStack) {
        Block block = ((ItemBlock) itemStack.getItem()).getBlock();
        return block.getStateFromMeta(itemStack.getMetadata());
    }

    /**
     * Get the itemstack from the given blockstate
     * @param blockState The blockstate
     * @return The itemstack
     */
    public static ItemStack getItemStackFromBlockState(IBlockState blockState) {
        Item item = Item.getItemFromBlock(blockState.getBlock());
        if(item == null) {
            return null;
        }
        return new ItemStack(item, 1, blockState.getBlock().getMetaFromState(blockState));
    }

    /**
     * Trigger a block update.
     * @param world The world.
     * @param pos The pos.
     */
    public static void markForUpdate(World world, BlockPos pos) {
        IBlockState blockState = world.getBlockState(pos);
        world.notifyBlockUpdate(pos, blockState, blockState, MinecraftHelpers.BLOCK_NOTIFY | MinecraftHelpers.BLOCK_NOTIFY_CLIENT);
    }

    /**
     * Add a collision box to the given list if it intersects with a box.
     * @param pos The block position the collision is happening in.
     * @param collidingBox The box that is colliding with the block, absolute coordinates.
     * @param collisions The list fo add the box to.
     * @param addingBox The box to add to the lost, relative coordinates.
     */
    public static void addCollisionBoxToList(BlockPos pos, AxisAlignedBB collidingBox, List<AxisAlignedBB> collisions, AxisAlignedBB addingBox) {
        if (addingBox != null) {
            AxisAlignedBB axisalignedbb = addingBox.offset(pos);
            if (collidingBox.intersectsWith(axisalignedbb)) {
                collisions.add(axisalignedbb);
            }
        }
    }

    /**
     * If the given block has a solid top surface.
     * @param world The world.
     * @param blockPos The block to check the top of.
     * @return If it has a solid top surface.
     */
    public static boolean doesBlockHaveSolidTopSurface(IBlockAccess world, BlockPos blockPos) {
        blockPos = blockPos.add(0, -1, 0);
        return world.getBlockState(blockPos).getBlock().isAir(world.getBlockState(blockPos), world, blockPos)
                && world.getBlockState(blockPos).isOpaqueCube();
    }

}

@@ -5585,200 +5585,57 @@
     
-blockPos = blockPos.add(0, -1, 0);%0A        return world.getBlockState(blockPos).getBlock().isAir(world.getBlockState(blockPos), world, blockPos)%0A                && world.getBlockState(blockPos
+return world.getBlockState(blockPos.add(0, -1, 0)
 ).is

Fix doesBlockHaveSolidTopSurface