package joshie.harvest.core.handlers;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Lists;
import joshie.harvest.api.HFApi;
import joshie.harvest.core.HFCore;
import joshie.harvest.core.block.BlockStorage;
import joshie.harvest.core.block.BlockStorage.Storage;
import joshie.harvest.core.entity.EntityBasket;
import joshie.harvest.core.item.ItemBlockStorage;
import joshie.harvest.core.network.PacketHandler;
import joshie.harvest.core.network.PacketOpenBasket;
import joshie.harvest.core.tile.TileBasket;
import joshie.harvest.core.util.annotations.HFEvents;
import joshie.harvest.crops.block.BlockHFCrops;
import net.minecraft.block.*;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.event.entity.player.EntityItemPickupEvent;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedOutEvent;
import javax.annotation.Nullable;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
@HFEvents
public class BasketHandler {
public static boolean forbidsDrop(Block block) {
return block instanceof BlockDoor || block instanceof BlockFenceGate || block instanceof BlockTrapDoor
|| block instanceof BlockLever || block instanceof BlockButton || block instanceof BlockHFCrops || block instanceof BlockStorage;
}
@SubscribeEvent //TODO: Check that picking up partial items
public void onItemPickup(EntityItemPickupEvent event) {
ItemStack stack = event.getItem().getEntityItem();
if (HFApi.shipping.getSellValue(stack) > 0) {
List<ItemStack> list = Lists.newArrayList(stack);
if (EntityBasket.findBasketAndShip(event.getEntityPlayer(), list)) {
event.getItem().setDead();
event.setCanceled(true);
}
}
}
private void setBasket(World world, BlockPos pos, @Nullable ItemStack stack) {
world.setBlockState(pos, HFCore.STORAGE.getStateFromEnum(Storage.BASKET));
if (stack != null) {
TileEntity tile = world.getTileEntity(pos);
if (tile instanceof TileBasket) {
((TileBasket)tile).onRightClicked(null, stack);
}
}
}
@SubscribeEvent
public void onPlayerLoggedOut(PlayerLoggedOutEvent event) {
for (Entity entity : event.player.getPassengers()) {
if (entity instanceof EntityBasket) {
EntityPlayer player = event.player;
BlockPos pos = new BlockPos(player);
if (player.worldObj.isAirBlock(pos)) {
setBasket(player.worldObj, pos, ((EntityBasket)entity).getEntityItem());
} else {
boolean placed = false;
int attempts = 0;
while (!placed && attempts < 512) {
BlockPos placing = pos.add(player.worldObj.rand.nextInt(10) - 5, player.worldObj.rand.nextInt(3), player.worldObj.rand.nextInt(10) - 5);
if (player.worldObj.isAirBlock(placing)) {
setBasket(player.worldObj, placing, ((EntityBasket)entity).getEntityItem());
placed = true;
}
attempts++;
}
}
entity.setDead();
}
}
}
private static final Set<Entity> EMPTY = new HashSet<>();
private final Cache<EntityPlayer, Set<Entity>> droppedClient = CacheBuilder.newBuilder().expireAfterWrite(1L, TimeUnit.MINUTES).build();
private final Cache<EntityPlayer, Set<Entity>> droppedServer = CacheBuilder.newBuilder().expireAfterWrite(1L, TimeUnit.MINUTES).build();
private Set<Entity> getSetFromPlayer(EntityPlayer player) {
try {
return player.worldObj.isRemote ? droppedClient.get(player, HashSet::new) : droppedServer.get(player, HashSet::new);
} catch (ExecutionException ex) { return EMPTY; }
}
public static EntityBasket getWearingBasket(EntityPlayer player) {
for (Entity entity: player.getPassengers()) {
if (entity instanceof EntityBasket) return (EntityBasket) entity;
}
return null;
}
@SubscribeEvent
@SuppressWarnings("ConstantConditions")
public void onRightClickEmpty(PlayerInteractEvent.RightClickEmpty event) {
EntityPlayer player = event.getEntityPlayer();
if (player.isSneaking()) {
EntityBasket basket = getWearingBasket(player);
if (basket != null) {
PacketHandler.sendToServer(new PacketOpenBasket());
}
}
}
@SubscribeEvent
public void onRightClickGround(PlayerInteractEvent.RightClickBlock event) {
EntityPlayer player = event.getEntityPlayer();
if (!player.isSneaking() && player.getHeldItemMainhand() == null && player.getHeldItemOffhand() == null
&& !forbidsDrop(event.getWorld().getBlockState(event.getPos()).getBlock())) {
Set<Entity> set = getSetFromPlayer(player);
player.getPassengers().stream().filter(entity -> entity instanceof EntityBasket && !set.contains(entity)).forEach(entity -> {
ItemStack basket = HFCore.STORAGE.getStackFromEnum(Storage.BASKET);
TileEntity tile = (((ItemBlockStorage)basket.getItem()).onBasketUsed(basket, player, player.worldObj, event.getPos(), EnumHand.MAIN_HAND, event.getFace(), 0F, 0F, 0F));
if (tile instanceof TileBasket) {
((TileBasket)tile).setAppearanceAndContents(((EntityBasket)entity).getEntityItem(), ((EntityBasket)entity).handler);
set.add(entity);
entity.setDead();
}
});
} else if (player.isSneaking() && player.worldObj.isRemote) {
EntityBasket basket = getWearingBasket(player);
if (basket != null) {
PacketHandler.sendToServer(new PacketOpenBasket());
}
}
}
}