public void del(final UUID playerUUID, String effectName) {
    OfflinePlayer player = getPlayer(playerUUID, false);
    AbstractEffect effect = getEffect(playerUUID, effectName);
    if (effect == null) {
      throw new IllegalArgumentException(
          "The effect"
              + effectName
              + " were not associated to the player "
              + player.getName()
              + ".");
    }
    for (Class<? extends AbstractEventListener<?>> eventListenerClass : effect.getNeededEvents()) {
      AbstractEventListener<?> eventListener = null;
      try {
        eventListener = EventListenerManager.getInstance().getEventListener(eventListenerClass);
        if (eventListener == null) {
          throw new IllegalArgumentException("An error occured during the EventListener removal.");
        }
      } catch (InstantiationException
          | IllegalAccessException
          | InvocationTargetException
          | SecurityException e) {
        e.printStackTrace();
        throw new IllegalArgumentException(
            "An error occured during the EventListener removal: " + e.getClass().toString() + ".");
      }
      eventListener.deleteObserver(effect);
      if (eventListener.countObservers() == 0) {
        try {
          EventListenerManager.getInstance().removeIfNeeded(eventListener);
        } catch (IllegalAccessException e) {
          e.printStackTrace();
          throw new IllegalArgumentException(
              "An error occured during the EventListener removal: "
                  + e.getClass().toString()
                  + ".");
        }
      }
    }
    effect.onDisable();
    final AbstractEffect effectToDelete = effect;
    int disableDelay = effect.getDisableDelay();
    if (disableDelay > 0) {
      runTaskLater(
          new Runnable() {

            @Override
            public void run() {
              EffectManagerPlugin.getPlugin(EffectManagerPlugin.class)
                  .getPlayerEffectManager()
                  .getEffectsForPlayer(playerUUID)
                  .remove(effectToDelete);
            }
          },
          effect.getDisableDelay());
    } else {
      this.playersEffects.get(playerUUID).remove(effect);
    }
  }
 public void callEffectsForPlayer(UUID playerUUID, List<AbstractEffect> effects) {
   getPlayer(playerUUID, true);
   if (effects == null || effects.size() == 0) {
     throw new IllegalArgumentException("No effect to call");
   }
   for (AbstractEffect effect : effects) {
     effect.call();
   }
 }
 public AbstractEffect getEffect(UUID playerUUID, String effectName) {
   if (!this.playersEffects.containsKey(playerUUID)) {
     return null;
   }
   List<AbstractEffect> effects = this.playersEffects.get(playerUUID);
   for (AbstractEffect effect : effects) {
     if (effect.getName().equals(effectName)) {
       return effect;
     }
   }
   return null;
 }
 public void callEffectForPlayer(UUID playerUUID, String effectName) {
   OfflinePlayer player = getPlayer(playerUUID, true);
   checkEffect(effectName);
   AbstractEffect effect = getEffect(playerUUID, effectName);
   if (effect == null) {
     throw new IllegalArgumentException(
         "The effect "
             + effectName
             + " is not associated to the player "
             + player.getName()
             + " so it cannot be executed.");
   }
   effect.call();
 }
  private void del(UUID playerUUID, AbstractEffect effect) {
    try {
      for (Class<? extends AbstractEventListener<?>> eventListenerClass :
          effect.getNeededEvents()) {
        AbstractEventListener<?> eventListener;

        eventListener = EventListenerManager.getInstance().getEventListener(eventListenerClass);
        EntityDamageEvent.getHandlerList();
        eventListener.deleteObserver(effect);
        if (eventListener.countObservers() == 0) {
          Class<?> eventClass = eventListener.getObservedEvent();
          Method method = eventClass.getMethod("getHandlerList");
          HandlerList hl = (HandlerList) method.invoke(null);
          hl.unregister(plugin);
        }
      }
    } catch (NoSuchMethodException
        | InstantiationException
        | IllegalAccessException
        | InvocationTargetException
        | SecurityException e) {
      e.printStackTrace();
      throw new IllegalArgumentException(
          "An error occured during the effect deletion: " + e.getClass().toString() + ".", e);
    }
    getEffectsForPlayer(playerUUID).remove(effect);
    ;
  }
 @Override
 public Map<String, Object> serialize() {
   Map<String, Object> map = new TreeMap<String, Object>();
   for (UUID playerUUID : this.playersEffects.keySet()) {
     StringBuilder sb = new StringBuilder();
     List<AbstractEffect> playerEffects = this.playersEffects.get(playerUUID);
     for (int i = 0; i < playerEffects.size(); i++) {
       AbstractEffect effect = playerEffects.get(i);
       sb.append(effect.getName());
       if (i + 1 < playerEffects.size()) {
         sb.append(";");
       }
     }
     if (playerEffects.size() > 0) {
       map.put(playerUUID.toString(), sb.toString());
     }
   }
   return map;
 }
  public void add(UUID playerUUID, String effectName, Boolean checkIfPlayerIsConnected)
      throws IllegalArgumentException {
    OfflinePlayer player = getPlayer(playerUUID, true);
    checkEffect(effectName);
    // verifie que ce type d'effet n'est pas deja attribue au joueur.
    AbstractEffect effect = (AbstractEffect) plugin.getEffectManager().get(effectName);
    checkEffectTypeDuplication(player.getPlayer(), effect, false);
    // recupere et si necessaire cree le(s) eventListener(s) appropries
    try {
      effect = effect.applyToPlayer(playerUUID);
    } catch (CloneNotSupportedException e) {
      throw new IllegalArgumentException(
          "An error occured during the player's effect creation " + e.getClass().toString() + ".");
    }
    for (Class<? extends AbstractEventListener<?>> eventListenerClass : effect.getNeededEvents()) {
      AbstractEventListener<?> eventListener = null;
      try {
        eventListener = EventListenerManager.getInstance().getEventListener(eventListenerClass);
        if (eventListener == null) {
          throw new IllegalArgumentException("An error occured during the EventListener creation.");
        }
      } catch (InstantiationException
          | IllegalAccessException
          | InvocationTargetException
          | SecurityException e) {
        e.printStackTrace();
        throw new IllegalArgumentException(
            "An error occured during the EventListener creation: " + e.getClass().toString() + ".");
      }

      // associe le(s) eventListener(s) approprie(s) a l effet
      eventListener.addObserver(effect);
    }

    // On rempli la map des effets du joueur avec le nouvel effet.
    if (this.playersEffects.get(playerUUID) == null) {
      this.playersEffects.put(playerUUID, new ArrayList<AbstractEffect>());
    }
    this.playersEffects.get(playerUUID).add(effect);
    effect.onEnable();
  }
 private void checkEffectTypeDuplication(
     Player player, AbstractEffect effect, boolean checkIfPlayerExists) {
   if (!playersEffects.containsKey(player.getUniqueId())) {
     return;
   }
   List<AbstractEffect> effects = playersEffects.get(player.getUniqueId());
   if (effects == null) {
     return;
   }
   for (AbstractEffect cEffect : effects) {
     if ((cEffect.getType().equals(effect.getType()) && !effect.getType().isStackable())) {
       throw new IllegalArgumentException(
           "The effect "
               + cEffect.getName()
               + " of the same type ("
               + effect.getType().getName()
               + ") is already associated to the player "
               + player.getName()
               + ".");
     }
   }
 }