package org.cyclops.structuredcrafting.craft.provider;

import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.core.Direction;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import org.cyclops.cyclopscore.helper.ItemStackHelpers;
import org.cyclops.cyclopscore.helper.BlockEntityHelpers;
import org.cyclops.structuredcrafting.block.BlockStructuredCrafterConfig;

/**
 * World that can provide an itemstack.
 * @author rubensworks
 */
public class WorldItemStackProvider implements IItemStackProvider {
    @Override
    public boolean canProvideInput() {
        return BlockStructuredCrafterConfig.canTakeInputsFromWorld;
    }

    @Override
    public boolean canHandleOutput() {
        return BlockStructuredCrafterConfig.canPlaceOutputsIntoWorld;
    }

    @Override
    public boolean isValidForResults(Level world, BlockPos pos, Direction side) {
        return world.isEmptyBlock(pos);
    }

    protected boolean hasEmptyItemHandler(Level world, BlockPos pos, Direction side) {
        IItemHandler itemHandler = BlockEntityHelpers.getCapability(world, pos, side, CapabilityItemHandler.ITEM_HANDLER_CAPABILITY).orElse(null);
        boolean emptyItemHandler = true;
        if (itemHandler != null) {
            for (int i = 0; i < itemHandler.getSlots(); i++) {
                if (!itemHandler.extractItem(i, 1, true).isEmpty()) {
                    emptyItemHandler = false;
                    break;
                }
            }
        }
        return emptyItemHandler;
    }

    @Override
    public boolean hasItemStack(Level world, BlockPos pos, Direction side) {
        return !world.isEmptyBlock(pos) && hasEmptyItemHandler(world, pos, side);
    }

    @Override
    public ItemStack getItemStack(Level world, BlockPos pos, Direction side) {
        BlockState blockState = world.getBlockState(pos);

        ItemStack itemStack = ItemStack.EMPTY;
        if(blockState != null) {
            Item item = Item.byBlock(blockState.getBlock());
            if(item != null && hasEmptyItemHandler(world, pos, side)) {
                itemStack = new ItemStack(item, 1);
            }
        }
        return itemStack;
    }

    @Override
    public void reduceItemStack(Level world, BlockPos pos, Direction side, boolean simulate) {
        if(!simulate) {
            world.removeBlock(pos, false);
        }
    }

    @Override
    public boolean addItemStack(Level world, BlockPos pos, Direction side, ItemStack itemStack, boolean simulate) {
        return setItemStack(world, pos, side, itemStack, simulate);
    }

    @Override
    public boolean setItemStack(Level world, BlockPos pos, Direction side, ItemStack itemStack, boolean simulate) {
        if(!simulate && itemStack.getItem() instanceof BlockItem) {
            world.setBlockAndUpdate(pos, ((BlockItem) itemStack.getItem()).getBlock().defaultBlockState());
            itemStack.shrink(1);
        }
        if(!simulate && itemStack.getCount() > 0) {
            ItemStackHelpers.spawnItemStack(world, pos, itemStack);
        }
        return true;
    }
}

@@ -49,16 +49,55 @@
 vider;%0A%0A
+import com.mojang.authlib.GameProfile;%0A
 import n
@@ -113,42 +113,105 @@
 aft.
-world.level.block.state.BlockState
+core.BlockPos;%0Aimport net.minecraft.core.Direction;%0Aimport net.minecraft.server.level.ServerLevel
 ;%0Aim
@@ -255,46 +255,8 @@
 em;%0A
-import net.minecraft.world.item.Item;%0A
 impo
@@ -311,38 +311,98 @@
 t.minecraft.
-core.Direction
+world.level.Level;%0Aimport net.minecraft.world.level.block.state.BlockState
 ;%0Aimport net
@@ -408,37 +408,49 @@
 t.minecraft.
-core.BlockPos
+world.phys.BlockHitResult
 ;%0Aimport net
@@ -462,35 +462,83 @@
 craft.world.
-level.Level
+phys.Vec3;%0Aimport net.minecraftforge.common.util.FakePlayer
 ;%0Aimport net
@@ -666,25 +666,27 @@
 .helper.
-ItemStack
+BlockEntity
 Helpers;
@@ -720,35 +720,33 @@
 core.helper.
-BlockEntity
+ItemStack
 Helpers;%0Aimp
@@ -817,16 +817,92 @@
 onfig;%0A%0A
+import java.util.Map;%0Aimport java.util.UUID;%0Aimport java.util.WeakHashMap;%0A%0A
 /**%0A * W
@@ -1032,16 +1032,575 @@
 vider %7B%0A
+%0A    private static GameProfile PROFILE = new GameProfile(UUID.fromString(%2241C82C87-7AfB-4024-BB57-13D2C99CAE78%22), %22%5BStructuredCrafting%5D%22);%0A    private static final Map%3CServerLevel, FakePlayer%3E FAKE_PLAYERS = new WeakHashMap%3CServerLevel, FakePlayer%3E();%0A%0A    public static FakePlayer getFakePlayer(ServerLevel world) %7B%0A        FakePlayer fakePlayer = FAKE_PLAYERS.get(world);%0A        if (fakePlayer == null) %7B%0A            fakePlayer = new FakePlayer(world, PROFILE);%0A            FAKE_PLAYERS.put(world, fakePlayer);%0A        %7D%0A        return fakePlayer;%0A    %7D%0A%0A
     @Ove
@@ -2925,169 +2925,29 @@
 s);%0A
-%0A        ItemStack itemStack = ItemStack.EMPTY;%0A        if(blockState != null) %7B%0A            Item item = Item.byBlock(blockState.getBlock());%0A            if(item
+        if(blockState
  != 
@@ -3011,61 +3011,149 @@
     
-    itemStack = new ItemStack(item, 1);%0A            %7D
+return blockState.getCloneItemStack(new BlockHitResult(new Vec3(0, 0, 0), side, pos, false), world, pos, getFakePlayer((ServerLevel) world));
 %0A   
@@ -3174,25 +3174,25 @@
  return 
-i
+I
 temStack
 ;%0A    %7D%0A
@@ -3183,16 +3183,22 @@
 temStack
+.EMPTY
 ;%0A    %7D%0A

Fix world-based crafting recipes not keeping NBT data, Closes #29