package com.elmakers.mine.bukkit.action.builtin;

import com.elmakers.mine.bukkit.action.ActionHandler;
import com.elmakers.mine.bukkit.api.action.CastContext;
import com.elmakers.mine.bukkit.api.magic.Mage;
import com.elmakers.mine.bukkit.api.spell.Spell;
import com.elmakers.mine.bukkit.api.spell.SpellResult;
import com.elmakers.mine.bukkit.spell.BaseSpell;
import com.elmakers.mine.bukkit.action.CompoundAction;
import com.elmakers.mine.bukkit.utility.CompatibilityUtils;
import com.elmakers.mine.bukkit.utility.Target;
import org.bukkit.Location;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Entity;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

public class AreaOfEffectAction extends CompoundAction
{
    private int radius;
    private boolean targetSelf;
    private int targetCount;
    private List<WeakReference<Entity>> entities = new ArrayList<WeakReference<Entity>>();
    private int currentEntity = 0;
    private CastContext actionContext;

    @Override
    public void prepare(CastContext context, ConfigurationSection parameters)
    {
        super.prepare(context, parameters);
        radius = parameters.getInt("radius", 8);
        targetSelf = parameters.getBoolean("target_self", false);
        targetCount = parameters.getInt("target_count", -1);

        Mage mage = context.getMage();
        if (mage != null)
        {
            radius = (int)(mage.getRadiusMultiplier() * radius);
        }

        entities.clear();
        Entity sourceEntity = context.getEntity();
        Location sourceLocation = context.getTargetLocation();
        List<Entity> candidates = CompatibilityUtils.getNearbyEntities(sourceLocation, radius, radius, radius);
        if (targetCount > 0)
        {
            List<Target> targets = new ArrayList<Target>();
            for (Entity entity : candidates)
            {
                if ((targetSelf || entity != sourceEntity) && context.canTarget(entity))
                {
                    targets.add(new Target(sourceLocation, entity, radius));
                }
            }
            Collections.sort(targets);
            for (int i = 0; i < targetCount && i < targets.size(); i++)
            {
                Target target = targets.get(i);
                entities.add(new WeakReference<Entity>(target.getEntity()));
            }
        }
        else
        {
            for (Entity entity : candidates)
            {
                if ((targetSelf || entity != sourceEntity) && context.canTarget(entity))
                {
                    entities.add(new WeakReference<Entity>(entity));
                }
            }
        }

    }

    @Override
    public void reset(CastContext context)
    {
        super.reset(context);
        actionContext = createContext(context);
        currentEntity = 0;
    }

	@Override
    public SpellResult perform(CastContext context)
	{
        SpellResult result = SpellResult.NO_TARGET;
        while (currentEntity < entities.size())
        {
            Entity entity = entities.get(currentEntity).get();
            if (entity == null)
            {
                skippedActions(context);
                continue;
            }
            actionContext.setTargetEntity(entity);
            actionContext.setTargetLocation(entity.getLocation());
            SpellResult entityResult = performActions(actionContext);
            result = result.min(entityResult);
            if (entityResult == SpellResult.PENDING) {
                break;
            }
            currentEntity++;
            if (currentEntity < entities.size())
            {
                super.reset(context);
            }
        }

		return result;
	}

    @Override
    public void getParameterNames(Collection<String> parameters) {
        super.getParameterNames(parameters);
        parameters.add("radius");
        parameters.add("target_count");
        parameters.add("target_self");
    }

    @Override
    public void getParameterOptions(Collection<String> examples, String parameterKey) {
        if (parameterKey.equals("target_self")) {
            examples.addAll(Arrays.asList((BaseSpell.EXAMPLE_BOOLEANS)));
        } else if (parameterKey.equals("target_count") || parameterKey.equals("radius")) {
            examples.addAll(Arrays.asList((BaseSpell.EXAMPLE_SIZES)));
        } else {
            super.getParameterOptions(examples, parameterKey);
        }
    }

    @Override
    public boolean requiresTarget() {
        return true;
    }

    @Override
    public Object clone()
    {
        AreaOfEffectAction action = (AreaOfEffectAction)super.clone();
        if (action != null) {
            action.entities = new ArrayList<WeakReference<Entity>>(this.entities);
        }
        return action;
    }
}

@@ -86,21 +86,28 @@
 ion.
-ActionHandler
+CompoundEntityAction
 ;%0Aim
@@ -244,182 +244,23 @@
 kit.
-api.spell.Spell;%0Aimport com.elmakers.mine.bukkit.api.spell.SpellResult;%0Aimport com.elmakers.mine.bukkit.spell.BaseSpell;%0Aimport com.elmakers.mine.bukkit.action.CompoundAction
+spell.BaseSpell
 ;%0Aim
@@ -701,16 +701,22 @@
 Compound
+Entity
 Action%0A%7B
@@ -756,219 +756,22 @@
 ate 
-boolean targetSelf;%0A    private int targetCount;%0A    private List%3CWeakReference%3CEntity%3E%3E entities = new ArrayList%3CWeakReference%3CEntity%3E%3E();%0A    private int currentEntity = 0;%0A    private CastContext actionContex
+int targetCoun
 t;%0A%0A
@@ -872,52 +872,8 @@
   %7B%0A
-        super.prepare(context, parameters);%0A
     
@@ -921,74 +921,8 @@
 8);%0A
-        targetSelf = parameters.getBoolean(%22target_self%22, false);%0A
     
@@ -1142,25 +1142,194 @@
     
-entities.clear();
+super.prepare(context, parameters);%0A    %7D%0A%0A    @Override%0A    public void prepareEntities(CastContext context, ConfigurationSection parameters, List%3CWeakReference%3CEntity%3E%3E entities)%0A    %7B
 %0A   
@@ -2503,1060 +2503,15 @@
   %7D%0A
-%0A
     %7D%0A%0A
-    @Override%0A    public void reset(CastContext context)%0A    %7B%0A        super.reset(context);%0A        actionContext = createContext(context);%0A        currentEntity = 0;%0A    %7D%0A%0A%09@Override%0A    public SpellResult perform(CastContext context)%0A%09%7B%0A        SpellResult result = SpellResult.NO_TARGET;%0A        while (currentEntity %3C entities.size())%0A        %7B%0A            Entity entity = entities.get(currentEntity).get();%0A            if (entity == null)%0A            %7B%0A                skippedActions(context);%0A                continue;%0A            %7D%0A            actionContext.setTargetEntity(entity);%0A            actionContext.setTargetLocation(entity.getLocation());%0A            SpellResult entityResult = performActions(actionContext);%0A            result = result.min(entityResult);%0A            if (entityResult == SpellResult.PENDING) %7B%0A                break;%0A            %7D%0A            currentEntity++;%0A            if (currentEntity %3C entities.size())%0A            %7B%0A                super.reset(context);%0A            %7D%0A        %7D%0A%0A%09%09return result;%0A%09%7D%0A%0A
     
@@ -2710,47 +2710,8 @@
 %22);%0A
-        parameters.add(%22target_self%22);%0A
     
@@ -2830,139 +2830,8 @@
  if 
-(parameterKey.equals(%22target_self%22)) %7B%0A            examples.addAll(Arrays.asList((BaseSpell.EXAMPLE_BOOLEANS)));%0A        %7D else if 
 (par
@@ -3149,277 +3149,7 @@
    %7D
-%0A%0A    @Override%0A    public Object clone()%0A    %7B%0A        AreaOfEffectAction action = (AreaOfEffectAction)super.clone();%0A        if (action != null) %7B%0A            action.entities = new ArrayList%3CWeakReference%3CEntity%3E%3E(this.entities);%0A        %7D%0A        return action;%0A    %7D
 %0A%7D%0A

Add CompoundEntity base action