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

import com.elmakers.mine.bukkit.action.BaseSpellAction;
import com.elmakers.mine.bukkit.api.action.CastContext;
import com.elmakers.mine.bukkit.api.magic.Mage;
import com.elmakers.mine.bukkit.api.magic.MageController;
import com.elmakers.mine.bukkit.api.spell.Spell;
import com.elmakers.mine.bukkit.api.spell.SpellResult;
import com.elmakers.mine.bukkit.spell.BaseSpell;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Entity;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.logging.Level;

/**
 * Can run any Bukkit command as a Spell.
 *
 * This includes running as Console, or opping/deopping the player if needed.
 *
 * This spell can also act as a targeting spell, running commands using the
 * target location or entity.
 *
 * The following parameters will all be substituted in the "command" string
 * if found:
 *
 * @_ - A spell, useful for command-line casting
 * @spell - name of spell being cast
 * @p - mage name
 * @uuid - mage uuid
 * @world, @x, @y, @z - mage location
 *
 * If targeting is used ("target: none" to disable), the following will also be escaped:
 *
 * @t - target mage name
 * @tuuid - target entity uuid
 * @tworld, @tx, @ty, @tz - target location
 */
public class CommandAction extends BaseSpellAction {
    public final static String[] PARAMETERS = {
        "command", "console", "op", "radius", "target_required", "target_entity_required"
    };

    private List<String> commands = new ArrayList<String>();
    private boolean asConsole;
    private boolean opPlayer;
    private boolean requiresTarget;
    private boolean requiresEntityTarget;

    @Override
    public void prepare(CastContext context, ConfigurationSection parameters) {
        super.prepare(context, parameters);
        asConsole = parameters.getBoolean("console", false);
        opPlayer = parameters.getBoolean("op", false);
        requiresTarget = parameters.getBoolean("target_required", false);
        requiresEntityTarget = parameters.getBoolean("target_entity_required", false);
    }

    @Override
    public void initialize(Spell spell, ConfigurationSection parameters) {
        super.initialize(spell, parameters);
        commands.clear();

        if (parameters.contains("command"))
        {
            String command = parameters.getString("command");
            if (command != null && command.length() > 0)
            {
                commands.add(command);
            }
        }
        else
        {
            commands.addAll(parameters.getStringList("commands"));
        }
    }

    protected String parameterize(CastContext context, String command) {
        Location location = context.getLocation();
        Mage mage = context.getMage();
        MageController controller = context.getController();

        command = command
                .replace("@_", " ")
                .replace("@spell", context.getSpell().getName())
                .replace("@pd", mage.getDisplayName())
                .replace("@pn", mage.getName())
                .replace("@uuid", mage.getId());

        if (location != null) {
            command = command
                .replace("@world", location.getWorld().getName())
                .replace("@x", Double.toString(location.getX()))
                .replace("@y", Double.toString(location.getY()))
                .replace("@z", Double.toString(location.getZ()));
        }

        Location targetLocation = context.getTargetLocation();
        if (targetLocation != null) {
            command = command
                .replace("@tworld", targetLocation.getWorld().getName())
                .replace("@tx", Double.toString(targetLocation.getX()))
                .replace("@ty", Double.toString(targetLocation.getY()))
                .replace("@tz", Double.toString(targetLocation.getZ()));
        }

        Entity targetEntity = context.getTargetEntity();
        if (targetEntity != null) {
            if (controller.isMage(targetEntity)) {
                Mage targetMage = controller.getMage(targetEntity);
                command = command
                    .replace("@td", targetMage.getDisplayName())
                    .replace("@tn", targetMage.getName())
                    .replace("@tuuid", targetMage.getId());
            } else {
                command = command
                    .replace("@td", controller.getEntityDisplayName(targetEntity))
                    .replace("@tn", controller.getEntityName(targetEntity))
                    .replace("@tuuid", targetEntity.getUniqueId().toString());
            }
        }

        return ChatColor.translateAlternateColorCodes('&', command);
    }

    @Override
    public SpellResult perform(CastContext context) {
        Mage mage = context.getMage();
        MageController controller = context.getController();
        CommandSender sender = asConsole ? Bukkit.getConsoleSender() : mage.getCommandSender();
        if (sender == null) {
            return SpellResult.FAIL;
        }
        boolean isOp = sender.isOp();
        if (opPlayer && !isOp) {
            sender.setOp(true);
        }
        for (String command : commands) {
            try {
                String converted = parameterize(context, command);
                controller.getPlugin().getServer().dispatchCommand(sender, converted);
            } catch (Exception ex) {
                controller.getLogger().log(Level.WARNING, "Error running command: " + command, ex);
            }
        }
        if (opPlayer && !isOp) {
            sender.setOp(false);
        }
        return SpellResult.CAST;
    }

    @Override
    public void getParameterNames(Spell spell, Collection<String> parameters)
    {
        super.getParameterNames(spell, parameters);
        parameters.addAll(Arrays.asList(PARAMETERS));
    }

    @Override
    public void getParameterOptions(Spell spell, String parameterKey, Collection<String> examples)
    {
        if (parameterKey.equals("command")) {
            examples.add("spawn");
            examples.add("clear");
        } else if (parameterKey.equals("op") || parameterKey.equals("console")) {
            examples.addAll(Arrays.asList(BaseSpell.EXAMPLE_BOOLEANS));
        } else {
            super.getParameterOptions(spell, parameterKey, examples);
        }
    }

    @Override
    public boolean requiresTargetEntity()
    {
        return requiresEntityTarget;
    }

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

@@ -1566,16 +1566,20 @@
         
+    
 %22command
@@ -1610,53 +1610,8 @@
 ius%22
-, %22target_required%22, %22target_entity_required%22
 %0A   
@@ -1740,86 +1740,8 @@
 yer;
-%0A    private boolean requiresTarget;%0A    private boolean requiresEntityTarget;
 %0A%0A  
@@ -1929,32 +1929,32 @@
 nsole%22, false);%0A
+
         opPlayer
@@ -1996,169 +1996,8 @@
 e);%0A
-        requiresTarget = parameters.getBoolean(%22target_required%22, false);%0A        requiresEntityTarget = parameters.getBoolean(%22target_entity_required%22, false);%0A
     
@@ -6263,207 +6263,7 @@
    %7D
-%0A%0A    @Override%0A    public boolean requiresTargetEntity()%0A    %7B%0A        return requiresEntityTarget;%0A    %7D%0A%0A    @Override%0A    public boolean requiresTarget()%0A    %7B%0A        return requiresTarget;%0A    %7D
 %0A%7D%0A

Undo previous commit, redundant base action functionality- oops!