package crazypants.enderio.enchantment;

import java.util.ListIterator;
import java.util.Map;

import net.minecraft.enchantment.Enchantment;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.enchantment.EnumEnchantmentType;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemArmor;
import net.minecraft.item.ItemStack;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.event.entity.player.PlayerDropsEvent;
import net.minecraftforge.event.entity.player.PlayerEvent;

import com.enderio.core.api.common.enchant.IAdvancedEnchant;

import cpw.mods.fml.common.Optional.Interface;
import cpw.mods.fml.common.eventhandler.EventPriority;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import crazypants.enderio.EnderIO;
import crazypants.enderio.config.Config;
import crazypants.util.BaublesUtil;

@Interface(iface = "tterrag.core.api.common.enchant.IAdvancedEnchant", modid = "ttCore")
public class EnchantmentSoulBound extends Enchantment implements IAdvancedEnchant {

  public static EnchantmentSoulBound create(int id) {
    EnchantmentSoulBound res = new EnchantmentSoulBound(id);
    MinecraftForge.EVENT_BUS.register(res);
    return res;
  }

  private final int id;

  private EnchantmentSoulBound(int id) {
    super(id, Config.enchantmentSoulBoundWeight, EnumEnchantmentType.all);
    this.id = id;
    setName("enderio.soulBound");
  }

  @Override
  public int getMaxEnchantability(int level) {
    return super.getMaxEnchantability(level) + 30;
  }

  @Override
  public int getMinEnchantability(int level) {
    return super.getMinEnchantability(level);
  }

  @Override
  public int getMaxLevel() {
    return 1;
  }

  /*
   * This is called the moment the player dies and drops is stuff.
   * 
   * We go early, so we can get our items before other mods put them into some
   * grave. Also remove them from the list so they won't get duped. If the
   * inventory overflows, e.g. because everything there and the armor is
   * soulbound, let the remainder be dropped/graved.
   */
  @SubscribeEvent(priority = EventPriority.HIGHEST)
  public void onPlayerDeath(PlayerDropsEvent evt) {
    if (evt.entityPlayer == null || evt.entityPlayer instanceof FakePlayer || evt.isCanceled()) {
      return;
    }
    if(evt.entityPlayer.worldObj.getGameRules().getGameRuleBooleanValue("keepInventory")) {
      return;
    }

    ListIterator<EntityItem> iter = evt.drops.listIterator();
    while (iter.hasNext()) {
      EntityItem ei = iter.next();
      ItemStack item = ei.getEntityItem();
      if(isSoulBound(item)) {
        if (addToPlayerInventory(evt.entityPlayer, item)) {
          iter.remove();
        }
      }
    }

    // Note: Baubles will also add its items to evt.drops, but later. We cannot
    // wait for that because gravestone mods also listen to this event. So we have
    // to fetch Baubles items ourselves here.
    // For the same reason we cannot put the items into Baubles slots.
    IInventory baubles = BaublesUtil.instance().getBaubles(evt.entityPlayer);
    if (baubles != null) {
      for (int i = 0; i < baubles.getSizeInventory(); i++) {
        ItemStack item = baubles.getStackInSlot(i);
        if(isSoulBound(item)) {
          if (addToPlayerInventory(evt.entityPlayer, item)) {
            baubles.setInventorySlotContents(i, null);
          }
        }
      }
    }
    
  }

  /*
   * This is called when the user presses the "respawn" button. The original
   * inventory would be empty, but onPlayerDeath() above placed items in it.
   * 
   * Note: Without other death-modifying mods, the content of the old inventory
   * would always fit into the new one (both being empty but for soulbound items
   * in the old one) and the old one would be discarded just after this method.
   * But better play it safe and assume that an overflow is possible and that
   * another mod may move stuff out of the old inventory, too.
   */
  @SubscribeEvent
  public void onPlayerClone(PlayerEvent.Clone evt) {
    if (!evt.wasDeath || evt.isCanceled()) {
      return;
    }
    if(evt.original == null || evt.entityPlayer == null || evt.entityPlayer instanceof FakePlayer) {
      return;
    }
    if(evt.entityPlayer.worldObj.getGameRules().getGameRuleBooleanValue("keepInventory")) {
      return;
    }
    for (int i = 0; i < evt.original.inventory.mainInventory.length; i++) {
      ItemStack item = evt.original.inventory.mainInventory[i];
      if(isSoulBound(item)) {
        if (addToPlayerInventory(evt.entityPlayer, item)) {
          evt.original.inventory.mainInventory[i] = null;
        }
      }
    }
    for (int i = 0; i < evt.original.inventory.armorInventory.length; i++) {
      ItemStack item = evt.original.inventory.armorInventory[i];
      if(isSoulBound(item)) {
        if (addToPlayerInventory(evt.entityPlayer, item)) {
          evt.original.inventory.armorInventory[i] = null;
        }
      }
    }
  }

  private boolean isSoulBound(ItemStack item) {
    return EnchantmentHelper.getEnchantmentLevel(id, item) > 0;
  }

  private boolean addToPlayerInventory(EntityPlayer entityPlayer, ItemStack item) {
    if(item == null || entityPlayer == null) {
      return false;
    }
    if(item.getItem() instanceof ItemArmor) {
      ItemArmor arm = (ItemArmor) item.getItem();
      int index = 3 - arm.armorType;
      if(entityPlayer.inventory.armorItemInSlot(index) == null) {
        entityPlayer.inventory.armorInventory[index] = item;
        return true;
      }
    }

    InventoryPlayer inv = entityPlayer.inventory;
    for (int i = 0; i < inv.mainInventory.length; i++) {
      if(inv.mainInventory[i] == null) {
        inv.mainInventory[i] = item.copy();
        return true;
      }
    }

    return false;
  }

  @Override
  public String[] getTooltipDetails(ItemStack stack) {
    return new String[] { EnderIO.lang.localizeExact("description.enchantment.enderio.soulBound") };
  }
}

@@ -68,30 +68,8 @@
 tor;
-%0Aimport java.util.Map;
 %0A%0Aim
@@ -770,55 +770,8 @@
 t;%0A%0A
-import cpw.mods.fml.common.Optional.Interface;%0A
 impo
@@ -994,97 +994,8 @@
 l;%0A%0A
-@Interface(iface = %22tterrag.core.api.common.enchant.IAdvancedEnchant%22, modid = %22ttCore%22)%0A
 publ

Remove method stripping on soulbound for a method that is in EnderCore