/**
   * Tag creepers hurt by players.
   *
   * <p>Only those creepers hurt recently by players will have special drops.
   */
  @EventHandler(ignoreCancelled = true)
  public void onCreeperDamage(EntityDamageByEntityEvent event) {
    if (!CONFIG.isAffectedWorld(event)) {
      return;
    }

    if (event.getEntityType() == EntityType.CREEPER) {
      boolean isPlayerAttack = false;
      if (event.getDamager() instanceof Player) {
        isPlayerAttack = true;
      } else if (event.getDamager() instanceof Projectile) {
        Projectile projectile = (Projectile) event.getDamager();
        if (projectile.getShooter() instanceof Player) {
          isPlayerAttack = true;
        }
      }

      // Tag creepers hurt by players with the damage time stamp.
      if (isPlayerAttack) {
        Entity creeper = event.getEntity();
        creeper.setMetadata(
            PLAYER_DAMAGE_TIME_KEY,
            new FixedMetadataValue(this, new Long(creeper.getWorld().getFullTime())));
      }
    }
  }
  @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
  public void onEntityShootBow(EntityShootBowEvent event) {
    Entity projectile = event.getProjectile();

    if (!(projectile instanceof Arrow)) {
      return;
    }

    ItemStack bow = event.getBow();

    if (bow != null && bow.containsEnchantment(Enchantment.ARROW_INFINITE)) {
      projectile.setMetadata(mcMMO.infiniteArrowKey, mcMMO.metadataValue);
    }

    projectile.setMetadata(
        mcMMO.bowForceKey,
        new FixedMetadataValue(
            plugin,
            Math.min(event.getForce() * AdvancedConfig.getInstance().getForceMultiplier(), 1.0)));
    projectile.setMetadata(
        mcMMO.arrowDistanceKey,
        new FixedMetadataValue(plugin, Archery.locationToString(projectile.getLocation())));
  }
  /**
   * Monitor EntityChangeBlock events.
   *
   * @param event The event to watch
   */
  @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
  public void onEntityChangeBlock(EntityChangeBlockEvent event) {
    Entity entity = event.getEntity();

    if (!(entity instanceof FallingBlock)) {
      return;
    }

    Block block = event.getBlock();
    boolean isTracked = entity.hasMetadata(mcMMO.entityMetadataKey);

    if (mcMMO.getPlaceStore().isTrue(block) && !isTracked) {
      mcMMO.getPlaceStore().setFalse(block);
      entity.setMetadata(mcMMO.entityMetadataKey, mcMMO.metadataValue);
    } else if (isTracked) {
      mcMMO.getPlaceStore().setTrue(block);
    }
  }
  /**
   * Monitor CreatureSpawn events.
   *
   * @param event The event to watch
   */
  @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
  public void onCreatureSpawn(CreatureSpawnEvent event) {
    switch (event.getSpawnReason()) {
      case SPAWNER:
      case SPAWNER_EGG:
        LivingEntity entity = event.getEntity();
        Entity passenger = entity.getPassenger();

        entity.setMetadata(mcMMO.entityMetadataKey, mcMMO.metadataValue);

        if (passenger != null) {
          passenger.setMetadata(mcMMO.entityMetadataKey, mcMMO.metadataValue);
        }
        return;

      default:
        return;
    }
  }
  protected Entity setEntity(MageController controller, Entity entity) {
    this.entity = entity;
    if (noTarget) {
      entity.setMetadata("notarget", new FixedMetadataValue(controller.getPlugin(), true));
    }
    if (customName != null) {
      entity.setCustomName(customName);
      entity.setCustomNameVisible(true);
    }

    if (entity instanceof LivingEntity) {
      ((LivingEntity) entity).setMaxHealth(1000.0);
      ((LivingEntity) entity).setHealth(1000.0);
    }
    if (entity instanceof Slime) {
      ((Slime) entity).setSize(1);
    }

    if (entity instanceof Ageable) {
      if (isBaby) {
        ((Ageable) entity).setBaby();
      } else {
        ((Ageable) entity).setAdult();
      }
    } else if (entity instanceof Zombie) {
      ((Zombie) entity).setBaby(isBaby);
    } else if (entity instanceof PigZombie) {
      ((PigZombie) entity).setBaby(isBaby);
    } else if (entity instanceof Slime && isBaby) {
      Slime slime = (Slime) entity;
      slime.setSize(0);
    }

    if (entity instanceof Horse) {
      Horse.Variant variant = Horse.Variant.UNDEAD_HORSE;
      if (variantName != null) {
        try {
          variant = Horse.Variant.valueOf(variantName.toUpperCase());
        } catch (Exception ex) {
        }
      } else {
        variant = Horse.Variant.UNDEAD_HORSE;
      }

      ((Horse) entity).setVariant(variant);
    }

    if (entity instanceof Ocelot) {
      Ocelot ocelot = (Ocelot) entity;
      Ocelot.Type variant = Ocelot.Type.WILD_OCELOT;
      if (variantName != null) {
        try {
          variant = Ocelot.Type.valueOf(variantName.toUpperCase());
        } catch (Exception ex) {
        }
      } else {
        variant = Ocelot.Type.WILD_OCELOT;
      }

      ocelot.setCatType(variant);
    }
    if (entity instanceof Sheep) {
      Sheep sheep = (Sheep) entity;
      DyeColor color = DyeColor.WHITE;
      if (variantName != null) {
        try {
          color = DyeColor.valueOf(variantName.toUpperCase());
        } catch (Exception ex) {

        }
      }
      sheep.setColor(color);
    }
    if (entity instanceof Wolf) {
      Wolf wolf = (Wolf) entity;
      if (variantName != null) {
        // Only set collar color if a variant is set..
        // this makes it a dog, versus a wolf. Technically.
        DyeColor color = DyeColor.RED;
        try {
          color = DyeColor.valueOf(variantName.toUpperCase());
          wolf.setTamed(true);
        } catch (Exception ex) {

        }
        wolf.setCollarColor(color);
      }
    }
    targeting.ignoreEntity(entity);
    return entity;
  }
  @EventHandler
  public void poll(EffectPollingEvent event) {
    Player p = event.getPlayer();
    // System.out.println(Hand.toString());
    ItemStack[] Armors = p.getEquipment().getArmorContents();
    // for(ItemStack i:Armors)
    // System.out.println(i.toString());
    ArrayList<ItemStack> stuff = new ArrayList<>();

    for (ItemStack a : Armors) {
      if (a != null && a.getItemMeta() != null) {
        stuff.add(a); // Keep only the non null armor objects
      }
    }

    if (!stuff.isEmpty()) {
      for (ItemStack a : stuff) {
        // TODO Constant Effects go here
        HashMap<String, Integer> effects = EffectAPI.getEffectsFromItem(a);
        for (Entry<String, Integer> effect : effects.entrySet()) {
          switch (effect.getKey()) {
            case "Velocity":
              p.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, 666, effect.getValue()));
              break;
            case "Vaulting":
              p.addPotionEffect(new PotionEffect(PotionEffectType.JUMP, 666, effect.getValue()));
              break;
            case "Healing":
              for (Entity e :
                  p.getNearbyEntities(effect.getValue(), effect.getValue(), effect.getValue()))
                if (e.getType().equals(EntityType.PLAYER))
                  ((Player) e)
                      .addPotionEffect(new PotionEffect(PotionEffectType.REGENERATION, 666, 1));
                else if (e.getType().equals(EntityType.WOLF) && ((Wolf) e).isTamed())
                  ((Wolf) e)
                      .addPotionEffect(new PotionEffect(PotionEffectType.REGENERATION, 666, 1));
              break;
            case "Damage":
              for (Entity e :
                  p.getNearbyEntities(effect.getValue(), effect.getValue(), effect.getValue()))
                if (e.getType().equals(EntityType.PLAYER))
                  ((Player) e)
                      .addPotionEffect(new PotionEffect(PotionEffectType.INCREASE_DAMAGE, 666, 1));
                else if (e.getType().equals(EntityType.WOLF) && ((Wolf) e).isTamed())
                  ((Wolf) e)
                      .addPotionEffect(new PotionEffect(PotionEffectType.INCREASE_DAMAGE, 666, 1));

              break;
            case "Resistance":
              for (Entity e :
                  p.getNearbyEntities(effect.getValue(), effect.getValue(), effect.getValue()))
                if (e.getType().equals(EntityType.PLAYER))
                  ((Player) e)
                      .addPotionEffect(
                          new PotionEffect(PotionEffectType.DAMAGE_RESISTANCE, 666, 1));
                else if (e.getType().equals(EntityType.WOLF) && ((Wolf) e).isTamed())
                  ((Wolf) e)
                      .addPotionEffect(
                          new PotionEffect(PotionEffectType.DAMAGE_RESISTANCE, 666, 1));
              break;
            case "Speed":
              for (Entity e :
                  p.getNearbyEntities(effect.getValue(), effect.getValue(), effect.getValue()))
                if (e.getType().equals(EntityType.PLAYER))
                  ((Player) e).addPotionEffect(new PotionEffect(PotionEffectType.SPEED, 666, 1));
                else if (e.getType().equals(EntityType.WOLF) && ((Wolf) e).isTamed())
                  ((Wolf) e).addPotionEffect(new PotionEffect(PotionEffectType.SPEED, 666, 1));
              break;
            case "Taunting":
              for (Entity e :
                  p.getNearbyEntities(
                      effect.getValue() * 2.5 + 5.0,
                      effect.getValue() * 2.5 + 5.0,
                      effect.getValue() * 2.5 + 5.0))
                if (Hostiles.contains(e.getType())) {
                  e.setMetadata("Targeting", (MetadataValue) p);
                }
              break;
          }
        }
      }
    }
    /*if (p.getInventory().getItem(event.getPreviousSlot()).getItemMeta().getLore().get(1).equals("Strength")) {
    	System.out.println("Removing effect");

    	p.removePotionEffect(PotionEffectType.INCREASE_DAMAGE);
    }*/

  }
  @Override
  public SpellResult perform(CastContext context) {
    Block targetBlock = context.getTargetBlock();
    Entity currentEntity = current == null ? null : current.get();
    current = null;
    if (currentEntity != null) {
      currentEntity.remove();
    }

    targetBlock = targetBlock.getRelative(BlockFace.UP);

    Location spawnLocation = targetBlock.getLocation();
    Location sourceLocation = context.getLocation();
    spawnLocation.setPitch(sourceLocation.getPitch());
    spawnLocation.setYaw(sourceLocation.getYaw());

    MageController controller = context.getController();
    if (entityData == null) {
      String randomType = RandomUtils.weightedRandom(entityTypeProbability);
      try {
        entityData = controller.getMob(randomType);
        if (entityData == null) {
          entityData =
              new com.elmakers.mine.bukkit.entity.EntityData(
                  EntityType.valueOf(randomType.toUpperCase()));
        }
      } catch (Throwable ex) {
        entityData = null;
      }
    }
    if (entityData == null) {
      return SpellResult.FAIL;
    }

    if (force) {
      controller.setForceSpawn(true);
    }
    Entity spawnedEntity = null;
    try {
      spawnedEntity = entityData.spawn(context.getController(), spawnLocation, spawnReason);
    } catch (Exception ex) {
      ex.printStackTrace();
    }

    if (force) {
      controller.setForceSpawn(false);
    }

    if (spawnedEntity == null) {
      return SpellResult.FAIL;
    }

    if (!loot) {
      spawnedEntity.setMetadata("nodrops", new FixedMetadataValue(controller.getPlugin(), true));
    }
    if (speed > 0) {
      Vector motion = direction;
      if (motion == null) {
        motion = context.getDirection();
      } else {
        motion = motion.clone();
      }

      if (dyOffset != 0) {
        motion.setY(motion.getY() + dyOffset);
      }
      motion.normalize();
      motion.multiply(speed);
      CompatibilityUtils.setEntityMotion(spawnedEntity, motion);
    }

    Collection<EffectPlayer> projectileEffects = context.getEffects("spawned");
    for (EffectPlayer effectPlayer : projectileEffects) {
      effectPlayer.start(spawnedEntity.getLocation(), spawnedEntity, null, null);
    }
    context.registerForUndo(spawnedEntity);

    if (track) {
      current = new WeakReference<Entity>(spawnedEntity);
    }
    if (setTarget) {
      context.setTargetEntity(spawnedEntity);
    }
    return SpellResult.CAST;
  }