package org.cyclops.everlastingabilities.ability;

import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import org.cyclops.everlastingabilities.EverlastingAbilities;
import org.cyclops.everlastingabilities.api.Ability;
import org.cyclops.everlastingabilities.api.IAbilityType;
import org.cyclops.everlastingabilities.api.capability.IMutableAbilityStore;
import org.cyclops.everlastingabilities.capability.MutableAbilityStoreConfig;
import org.cyclops.everlastingabilities.core.helper.obfuscation.ObfuscationHelpers;
import org.cyclops.everlastingabilities.network.packet.SendPlayerCapabilitiesPacket;

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

/**
 * General ability helpers.
 * @author rubensworks
 */
public class AbilityHelpers {

    public static void sendPlayerUpdateCapabilities(EntityPlayerMP player) {
        EverlastingAbilities._instance.getPacketHandler().sendToPlayer(
                new SendPlayerCapabilitiesPacket(ObfuscationHelpers.getEntityCapabilities(player)), player);
    }

    /**
     * Add the given ability.
     * @param ability The ability.
     * @param doAdd If the addition should actually be done.
     * @return The ability part that was added.
     */
    public static @Nullable Ability addPlayerAbility(EntityPlayer player, Ability ability, boolean doAdd, boolean modifyXp) {
        IMutableAbilityStore abilityStore = player.getCapability(MutableAbilityStoreConfig.CAPABILITY, null);
        Ability result = abilityStore.addAbility(ability, doAdd);
        int currentXp = player.experienceTotal;
        if (result != null && modifyXp && getExperience(result) > currentXp) {
            int maxLevels = player.experienceTotal / result.getAbilityType().getBaseXpPerLevel();
            if (maxLevels == 0) {
                result = null;
            } else {
                result = new Ability(result.getAbilityType(), maxLevels);
            }
        }
        if (doAdd && result != null) {
            player.addExperience(-getExperience(result));
        }
        if (player instanceof EntityPlayerMP) {
            sendPlayerUpdateCapabilities((EntityPlayerMP) player);
        }
        return result;
    }

    /**
     * Remove the given ability.
     * @param ability The ability.
     * @param doRemove If the removal should actually be done.
     * @return The ability part that was removed.
     */
    public static @Nullable Ability removePlayerAbility(EntityPlayer player, Ability ability, boolean doRemove, boolean modifyXp) {
        IMutableAbilityStore abilityStore = player.getCapability(MutableAbilityStoreConfig.CAPABILITY, null);
        Ability result = abilityStore.removeAbility(ability, doRemove);
        if (modifyXp && result != null) {
            player.addExperience(getExperience(result));
        }
        if (player instanceof EntityPlayerMP) {
            sendPlayerUpdateCapabilities((EntityPlayerMP) player);
        }
        return result;
    }

    public static int getExperience(Ability ability) {
        if (ability == null) {
            return 0;
        }
        return ability.getAbilityType().getBaseXpPerLevel() * ability.getLevel();
    }

    public static void setPlayerAbilities(EntityPlayerMP player, Map<IAbilityType, Integer> abilityTypes) {
        IMutableAbilityStore abilityStore = player.getCapability(MutableAbilityStoreConfig.CAPABILITY, null);
        abilityStore.setAbilities(abilityTypes);
    }

    public static boolean canInsert(Ability ability, IMutableAbilityStore mutableAbilityStore) {
        Ability added = mutableAbilityStore.addAbility(ability, false);
        return added != null && added.getLevel() == ability.getLevel();
    }

    public static boolean canExtract(Ability ability, IMutableAbilityStore mutableAbilityStore) {
        Ability added = mutableAbilityStore.removeAbility(ability, false);
        return added != null && added.getLevel() == ability.getLevel();
    }

    public static boolean canInsertToPlayer(Ability ability, EntityPlayer player) {
        Ability added = addPlayerAbility(player, ability, false, true);
        return added != null && added.getLevel() == ability.getLevel();
    }

    public static Ability insert(Ability ability, IMutableAbilityStore mutableAbilityStore) {
        return mutableAbilityStore.addAbility(ability, true);
    }

    public static Ability extract(Ability ability, IMutableAbilityStore mutableAbilityStore) {
        return mutableAbilityStore.removeAbility(ability, true);
    }

}

@@ -738,61 +738,719 @@
 %0A * 
-@author rubensworks%0A */%0Apublic class AbilityHelpers %7B
+XP-related methods inspired by Ender IO's XpUtil for compatibility%0A * @author rubensworks%0A */%0Apublic class AbilityHelpers %7B%0A%0A    public static int getExperienceForLevel(int level) %7B%0A        if (level == 0) %7B return 0; %7D%0A        if (level %3E 0 && level %3C 16) %7B%0A            return level * 17;%0A        %7D else if (level %3E 15 && level %3C 31) %7B%0A            return (int)(1.5 * Math.pow(level, 2) - 29.5 * level + 360);%0A        %7D else %7B%0A            return (int)(3.5 * Math.pow(level, 2) - 151.5 * level + 2220);%0A        %7D%0A    %7D%0A%0A    public static int getLevelForExperience(int experience) %7B%0A        int i = 0;%0A        while (getExperienceForLevel(i) %3C= experience) %7B%0A            i++;%0A        %7D%0A        return i - 1;%0A    %7D
 %0A%0A  
@@ -2663,36 +2663,33 @@
          player.
-addE
+e
 xperience(-getEx
@@ -2685,10 +2685,17 @@
 ence
-(-
+Total -= 
 getE
@@ -2703,32 +2703,322 @@
 perience(result)
+;%0A            // Fix xp bar%0A            player.experienceLevel = getLevelForExperience(player.experienceTotal);%0A            int xpForLevel = getExperienceForLevel(player.experienceLevel);%0A            player.experience = (float)(player.experienceTotal - xpForLevel) / (float)player.xpBarCap(
 );%0A        %7D%0A   

Fix xp bar when moving abilities