// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.builtin.commandmacro;

import java.util.concurrent.CompletionStage;
import java.util.Iterator;
import com.hypixel.hytale.server.core.command.system.CommandManager;
import com.hypixel.hytale.server.core.command.system.arguments.system.DefaultArg;
import com.hypixel.hytale.server.core.command.system.arguments.system.AbstractOptionalArg;
import java.util.concurrent.CompletableFuture;
import com.hypixel.hytale.server.core.command.system.CommandContext;
import java.util.logging.Level;
import com.hypixel.hytale.server.core.command.system.arguments.types.ArgumentType;
import java.util.regex.Matcher;
import com.hypixel.hytale.server.core.command.system.CommandSender;
import com.hypixel.hytale.server.core.console.ConsoleSender;
import com.hypixel.hytale.server.core.command.system.ParseResult;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import javax.annotation.Nullable;
import javax.annotation.Nonnull;
import it.unimi.dsi.fastutil.Pair;
import java.util.List;
import com.hypixel.hytale.server.core.command.system.arguments.system.Argument;
import java.util.Map;
import java.util.regex.Pattern;
import com.hypixel.hytale.logger.HytaleLogger;
import com.hypixel.hytale.server.core.command.system.basecommands.AbstractAsyncCommand;

public class MacroCommandBase extends AbstractAsyncCommand
{
    public static final HytaleLogger LOGGER;
    private static final Pattern regexBracketPattern;
    private final Map<String, Argument<?, ?>> arguments;
    private final List<Pair<String, List<MacroCommandReplacement>>> commandReplacements;
    private final Map<String, String> defaultValueStrings;
    
    public MacroCommandBase(@Nonnull final String name, @Nullable final String[] aliases, @Nonnull final String description, @Nullable final MacroCommandParameter[] parameters, @Nonnull final String[] commands) {
        super(name, description);
        this.arguments = new Object2ObjectOpenHashMap<String, Argument<?, ?>>();
        this.commandReplacements = new ObjectArrayList<Pair<String, List<MacroCommandReplacement>>>();
        this.defaultValueStrings = new Object2ObjectOpenHashMap<String, String>();
        if (aliases != null) {
            this.addAliases(aliases);
        }
        if (parameters != null) {
            final ParseResult parseResult = new ParseResult();
            for (final MacroCommandParameter parameter : parameters) {
                Argument<?, ?> argument = null;
                switch (parameter.getRequirement()) {
                    case REQUIRED: {
                        argument = this.withRequiredArg(parameter.getName(), parameter.getDescription(), parameter.getArgumentType().getArgumentType());
                        break;
                    }
                    case OPTIONAL: {
                        argument = this.withOptionalArg(parameter.getName(), parameter.getDescription(), parameter.getArgumentType().getArgumentType());
                        break;
                    }
                    case FLAG: {
                        argument = this.withFlagArg(parameter.getName(), parameter.getDescription());
                        break;
                    }
                    case DEFAULT: {
                        argument = this.withDefaultArg(parameter.getName(), parameter.getDescription(), parameter.getArgumentType().getArgumentType(), parameter.getDefaultValue(), parameter.getDefaultValueDescription(), parseResult);
                        break;
                    }
                    default: {
                        throw new IllegalStateException("Unexpected value for Requirement: " + String.valueOf(parameter.getRequirement()));
                    }
                }
                this.arguments.put(parameter.getName(), argument);
            }
            if (parseResult.failed()) {
                parseResult.sendMessages(ConsoleSender.INSTANCE);
                return;
            }
        }
        final Matcher matcher = MacroCommandBase.regexBracketPattern.matcher("");
        for (int i = 0; i < commands.length; ++i) {
            String command = commands[i];
            final ObjectArrayList<MacroCommandReplacement> replacements = new ObjectArrayList<MacroCommandReplacement>();
            final Matcher reset = matcher.reset(command);
            while (reset.find()) {
                final String result = reset.group(1);
                final String[] splitByColons = result.split(":");
                if (command.charAt(matcher.start(1) - 2) == '\\') {
                    continue;
                }
                final String replacementSubstring = command.substring(matcher.start(1) - 1, matcher.end(1) + 1);
                MacroCommandReplacement replacement = null;
                switch (splitByColons.length) {
                    case 1: {
                        replacement = new MacroCommandReplacement(result, replacementSubstring);
                        break;
                    }
                    case 2: {
                        replacement = new MacroCommandReplacement(splitByColons[1], replacementSubstring, splitByColons[0]);
                        break;
                    }
                    default: {
                        throw new IllegalArgumentException("Cannot have more than one colon in a macro command parameter: '" + result);
                    }
                }
                if (!this.arguments.containsKey(replacement.getNameOfReplacingArg())) {
                    throw new IllegalArgumentException("Cannot define command with replacement token that does not refer to an argument: " + replacement.getNameOfReplacingArg());
                }
                replacements.add(replacement);
            }
            command = command.replaceAll("\\\\\\{", "{");
            commands[i] = command;
            this.commandReplacements.add((Pair<String, List<MacroCommandReplacement>>)Pair.of(command, replacements));
        }
    }
    
    @Nullable
    private <D> Argument<?, ?> withDefaultArg(final String name, final String description, @Nonnull final ArgumentType<D> argumentType, @Nonnull final String defaultValue, final String defaultValueDescription, @Nonnull final ParseResult parseResult) {
        final D parsedData = argumentType.parse(defaultValue.split(" "), parseResult);
        if (parseResult.failed()) {
            MacroCommandBase.LOGGER.at(Level.WARNING).log("Could not parse default argument value for argument: '" + name + "' on Macro Command: '" + this.getName() + "'.");
            parseResult.sendMessages(ConsoleSender.INSTANCE);
            return null;
        }
        this.defaultValueStrings.put(name, defaultValue);
        return this.withDefaultArg(name, description, argumentType, parsedData, defaultValueDescription);
    }
    
    @Nonnull
    @Override
    protected CompletableFuture<Void> executeAsync(@Nonnull final CommandContext context) {
        final List<String> commandsToExecute = new ObjectArrayList<String>();
        final CommandSender commandSender = context.sender();
        final String macro = context.getCalledCommand().getName();
        MacroCommandBase.LOGGER.at(Level.INFO).log("%s expanding command macro: %s", commandSender.getDisplayName(), macro);
        for (Pair<String, List<MacroCommandReplacement>> stringListPair : this.commandReplacements) {
            String command = stringListPair.key();
            final List<MacroCommandReplacement> replacements = stringListPair.value();
            for (MacroCommandReplacement replacement : replacements) {
                String stringToInject = "";
                boolean shouldInject = true;
                final Argument<? extends Argument<?, ?>, ?> argument = this.arguments.get(replacement.getNameOfReplacingArg());
                if (argument instanceof AbstractOptionalArg && !context.provided(argument)) {
                    if (argument instanceof DefaultArg) {
                        stringToInject = this.defaultValueStrings.get(argument.getName());
                    }
                    else {
                        shouldInject = false;
                    }
                }
                else {
                    stringToInject = String.join(" ", (CharSequence[])context.getInput(this.arguments.get(replacement.getNameOfReplacingArg())));
                }
                if (shouldInject && replacement.getOptionalArgumentKey() != null) {
                    stringToInject = replacement.getOptionalArgumentKey() + stringToInject;
                }
                command = command.replace(replacement.getStringToReplaceWithValue(), shouldInject ? stringToInject : "");
            }
            commandsToExecute.add(command);
        }
        CompletableFuture<Void> completableFuture = CompletableFuture.completedFuture((Void)null);
        final Iterator<String> iterator3 = commandsToExecute.iterator();
        while (iterator3.hasNext()) {
            final String command = iterator3.next();
            completableFuture = completableFuture.thenCompose(VOID -> CommandManager.get().handleCommand(commandSender, command));
        }
        return completableFuture;
    }
    
    static {
        LOGGER = HytaleLogger.forEnclosingClass();
        regexBracketPattern = Pattern.compile("\\{(.*?)}");
    }
}
