package crazypants.enderio.base.xp;

import javax.annotation.Nonnull;

import net.minecraft.entity.player.EntityPlayer;

/**
 * Values taken from OpenMods EnchantmentUtils to ensure consistent behavior
 * @see {@link https://github.com/OpenMods/OpenModsLib/blob/master/src/main/java/openmods/utils/EnchantmentUtils.java}
 *
 */
public class XpUtil {

  // Values taken from OpenBlocks to ensure compatibility

  public static final int XP_PER_BOTTLE = 8;
  public static final int RATIO = 20;
  public static final int LIQUID_PER_XP_BOTTLE = XP_PER_BOTTLE * RATIO;

  
  public static int liquidToExperience(int liquid) {
    return liquid / RATIO;
  }

  public static int experienceToLiquid(int xp) {
    return xp * RATIO;
  }

  public static int getLiquidForLevel(int level) {
    return experienceToLiquid(getExperienceForLevel(level));
  }

  private static final int[] xpmap = new int[256];

  public static int getExperienceForLevel(int level) {
    if (level >= 0 && level < xpmap.length) {
      if (xpmap[level] <= 0) {
        xpmap[level] = getExperienceForLevelImpl(level);
      }
      return xpmap[level];
    }
    if (level >= 21863) {
      return Integer.MAX_VALUE;
    }
    return getExperienceForLevelImpl(level);
  }

  private static int getExperienceForLevelImpl(int level) {
    int res = 0;
    for (int i = 0; i < level; i++) {
      res += getXpBarCapacity(i);
      if (res < 0) {
        return Integer.MAX_VALUE;
      }
    }
    return res;
  }

  public static int getXpBarCapacity(int level) {
    if (level >= 30) {
      return 112 + (level - 30) * 9;
    } else if (level >= 15) {
      return 37 + (level - 15) * 5;
    }
    return 7 + level * 2;
  }

  public static int getLevelForExperience(int experience) {
    int i = 1;
    while (getExperienceForLevel(i) <= experience) {
      i++;
    }
    return i - 1;
  }

  public static int getPlayerXP(@Nonnull EntityPlayer player) {
    return (int) (getExperienceForLevel(player.experienceLevel) + (player.experience * player.xpBarCap()));
  }

  public static void addPlayerXP(@Nonnull EntityPlayer player, int amount) {
    int experience = Math.max(0, getPlayerXP(player) + amount);
    player.experienceTotal = experience;
    player.experienceLevel = getLevelForExperience(experience);
    int expForLevel = getExperienceForLevel(player.experienceLevel);
    player.experience = (float) (experience - expForLevel) / (float) player.xpBarCap();
  }

}

@@ -891,10 +891,12 @@
 nt%5B2
-56
+1863
 %5D;%0A%0A
@@ -968,161 +968,30 @@
 vel 
-%3E= 0 && level %3C xpmap.length) %7B%0A      if (xpmap%5Blevel%5D %3C= 0) %7B%0A        xpmap%5Blevel%5D = getExperienceForLevelImpl(level);%0A      %7D%0A      return xpmap%5Blevel%5D
+%3C= 0) %7B%0A      return 0
 ;%0A  
@@ -1073,40 +1073,20 @@
 urn 
-getExperienceForLevelImpl(
+xpmap%5B
 level
-)
+%5D
 ;%0A  
@@ -1094,63 +1094,14 @@
 %0A%0A  
-private static int getExperienceForLevelImpl(int level)
+static
  %7B%0A 
@@ -1140,21 +1140,21 @@
  0; i %3C 
-level
+21863
 ; i++) %7B
@@ -1211,36 +1211,35 @@
  0) %7B%0A        re
-turn
+s =
  Integer.MAX_VAL
@@ -1258,25 +1258,31 @@
     
-%7D%0A    return res;
+  xpmap%5Bi%5D = res;%0A    %7D
 %0A  %7D
@@ -1556,24 +1556,29 @@
 ence) %7B%0A    
+for (
 int i = 1;%0A 
@@ -1579,47 +1579,54 @@
 = 1;
-%0A    while (getExperienceForLevel(i) %3C=
+ i %3C xpmap.length; i++) %7B%0A      if (xpmap%5Bi%5D %3E
  exp
@@ -1646,12 +1646,31 @@
     
+ 
-i++;
+ return i - 1;%0A      %7D
 %0A   
@@ -1679,29 +1679,36 @@
 %0A    return 
-i - 1
+xpmap.length
 ;%0A  %7D%0A%0A  pub

Fix XP calculations being somewhat O(wait 20 minutes)