package com.elmakers.mine.bukkit.entity;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.MemoryConfiguration;
import org.bukkit.entity.Creature;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.inventory.ItemStack;

import com.elmakers.mine.bukkit.api.effect.EffectPlayer;
import com.elmakers.mine.bukkit.api.item.ItemData;
import com.elmakers.mine.bukkit.api.magic.Mage;
import com.elmakers.mine.bukkit.api.magic.MageController;
import com.elmakers.mine.bukkit.magic.MageTrigger;
import com.elmakers.mine.bukkit.magic.MageTrigger.MageTriggerType;

public class EntityMageData {
    // These properties will get copied directly to mage data, as if they were in the "mage" section.
    private static final String[] MAGE_PROPERTIES = {"protection", "weakness", "strength"};

    protected long tickInterval;
    protected Map<MageTriggerType, List<MageTrigger>> triggers;
    protected ConfigurationSection mageProperties;
    protected boolean requiresTarget;
    protected ItemData requiresWand;
    protected boolean aggro;
    protected double trackRadiusSquared;
    protected Collection<EffectPlayer> effects;

    public EntityMageData(@Nonnull MageController controller, @Nonnull ConfigurationSection parameters) {
        requiresWand = controller.getOrCreateItem(parameters.getString("cast_requires_item"));

        mageProperties = parameters.getConfigurationSection("mage");

        for (String mageProperty : MAGE_PROPERTIES) {
            ConfigurationSection mageConfig = parameters.getConfigurationSection(mageProperty);
            if (mageConfig != null) {
                if (mageProperties == null) {
                    mageProperties = new MemoryConfiguration();
                }
                mageProperties.set(mageProperty, mageConfig);
            }
        }

        tickInterval = parameters.getLong("interval", parameters.getLong("cast_interval", 0));
        requiresTarget = parameters.getBoolean("cast_requires_target", true);
        trackRadiusSquared = parameters.getDouble("track_radius", 128);
        trackRadiusSquared = trackRadiusSquared * trackRadiusSquared;

        ConfigurationSection triggerConfig = parameters.getConfigurationSection("triggers");

        // Support legacy "cast" format
        if (parameters.contains("cast")) {
            if (triggerConfig == null) {
                triggerConfig = new MemoryConfiguration();
            }
            ConfigurationSection castSection = triggerConfig.createSection("interval");
            castSection.set("cast", parameters.getConfigurationSection("cast"));
        }

        Set<String> triggerKeys = triggerConfig == null ? null : triggerConfig.getKeys(false);
        if (triggerKeys != null) {
            triggers = new HashMap<>();
            for (String triggerKey : triggerKeys) {
                MageTrigger trigger = new MageTrigger(controller, triggerKey, triggerConfig.getConfigurationSection(triggerKey));
                if (trigger.isValid()) {
                    List<MageTrigger> typeTriggers = triggers.get(trigger.getType());
                    if (typeTriggers == null) {
                        typeTriggers = new ArrayList<>();
                        triggers.put(trigger.getType(), typeTriggers);
                    }
                    typeTriggers.add(trigger);
                }
            }
        }

        // Default to 1-second interval if any interval triggers are set but no interval was specified
        if (triggers != null && tickInterval <= 0 && triggers.containsKey(MageTriggerType.INTERVAL)) {
            tickInterval = 1000;
        }

        if (parameters.contains("effects")) {
            effects = controller.loadEffects(parameters, "effects");
        }

        aggro = parameters.getBoolean("aggro", !isEmpty());
    }

    public boolean isEmpty() {
        boolean hasTriggers = triggers != null;
        boolean hasProperties = mageProperties != null;
        boolean hasEffects = effects != null && !effects.isEmpty();
        return !hasProperties && !hasTriggers && !aggro && !hasEffects;
    }

    @Nullable
    private List<MageTrigger> getTriggers(MageTriggerType type) {
        return triggers == null ? null : triggers.get(type);
    }

    public void onDeath(Mage mage) {
        List<MageTrigger> deathTriggers = getTriggers(MageTriggerType.DEATH);
        if (deathTriggers == null) return;
        for (MageTrigger trigger : deathTriggers) {
            trigger.execute(mage);
        }
    }

    public void onDamage(Mage mage, double damage) {
        List<MageTrigger> damageTriggers = getTriggers(MageTriggerType.DAMAGE);
        if (damageTriggers == null) return;
        for (MageTrigger trigger : damageTriggers) {
            trigger.execute(mage, damage);
        }
    }

    public void onSpawn(Mage mage) {
        List<MageTrigger> spawnTriggers = getTriggers(MageTriggerType.SPAWN);
        if (spawnTriggers != null) {
            for (MageTrigger trigger : spawnTriggers) {
                trigger.execute(mage);
            }
        }

        if (effects != null) {
            for (EffectPlayer player : effects) {
                player.start(mage.getEffectContext());
            }
        }
    }

    public void tick(Mage mage) {
        List<MageTrigger> intervalTriggers = getTriggers(MageTriggerType.INTERVAL);
        if (intervalTriggers == null) return;

        Entity entity = mage.getLivingEntity();
        Creature creature = (entity instanceof Creature) ? (Creature)entity : null;
        if (requiresTarget && (creature == null || creature.getTarget() == null)) return;
        if (requiresWand != null && entity instanceof LivingEntity) {
            LivingEntity li = (LivingEntity)entity;
            ItemStack itemInHand = li.getEquipment().getItemInMainHand();
            if (itemInHand == null || itemInHand.getType() != requiresWand.getType()) return;
        }

        for (MageTrigger trigger : intervalTriggers) {
            trigger.execute(mage);
        }
    }

    public double getTrackRadiusSquared() {
        return trackRadiusSquared;
    }
}

@@ -1099,16 +1099,45 @@
 terval;%0A
+    protected long lifetime;%0A
     prot
@@ -1192,16 +1192,16 @@
 iggers;%0A
-
     prot
@@ -2104,32 +2104,85 @@
    %7D%0A        %7D%0A%0A
+        lifetime = parameters.getInt(%22lifetime%22, 0);%0A
         tickInte
@@ -3960,32 +3960,126 @@
  1000;%0A        %7D
+%0A        if (tickInterval %3C lifetime / 2) %7B%0A            tickInterval = lifetime / 2;%0A        %7D
 %0A%0A        if (pa
@@ -4456,24 +4456,68 @@
 .isEmpty();%0A
+        boolean hasLifetime = lifetime %3E 0;%0A
         retu
@@ -4574,16 +4574,32 @@
 sEffects
+ && !hasLifetime
 ;%0A    %7D%0A
@@ -5730,32 +5730,32 @@
        %7D%0A    %7D%0A%0A
-
     public void 
@@ -5764,32 +5764,222 @@
 ck(Mage mage) %7B%0A
+        if (lifetime %3E 0 && System.currentTimeMillis() %3E mage.getCreatedTime() + lifetime) %7B%0A            onDeath(mage);%0A            mage.getEntity().remove();%0A            return;%0A        %7D%0A%0A
         List%3CMag

Add magic mob lifetime parameter