package leigh.mecha.cli;

import leigh.mecha.log.MechaLogger;
import leigh.mecha.log.MechaLoggerFactory;

import java.util.Arrays;
import java.util.Map;

/**
 * CommandFrame is a base command implementation that in turn offers subcommands. CommandFrames may be nested
 * to provide complex command structures.
 *
 * @author Alex Leigh
 */
public class CommandFrame<T extends CommandState> implements CommandHandler<T> {
    private static final MechaLogger logger = MechaLoggerFactory.getLogger(CommandFrame.class);
    private final CommandRouter<CommandHandler> subcommands = new CommandRouter<>();

    @Override
    /**
     * Attempt to route a subcommand from this command invocation.
     */
    public void handle(String[] cmd, T state) throws Exception {
        // cmd[0] == this
        // cmd[1] == wanted
        // cmd[2...] == args

        // TODO: Check for null

        logger.info("Called: {} {}", cmd.length, Arrays.toString(cmd));

        if (cmd.length < 2) {
            state.sendMessage("Incomplete command.");
            return;
        }

        CommandRoute<CommandHandler> handler = subcommands.route(cmd[1]);

        if (handler == null) {
            state.sendMessage("Unknown command.");
            return;
        }

        Map<String, CommandHandler> cmds = handler.getCommands();
        if (cmds.size() == 0) {
            state.sendMessage("Unknown command.");
            return;
        }
        // TODO: Indicate which commands match to the caller.
        if (cmds.size() > 1) {
            state.sendMessage("Ambiguous commands.");
            return;
        }

        CommandHandler h = (CommandHandler) cmds.values().toArray()[0];
        String[] subCmd = Arrays.copyOfRange(cmd, 1, cmd.length);
        logger.info("Built subcmd: {}", Arrays.toString(subCmd));

        h.handle(subCmd, state);
    }

    @Override
    public String toString() {
        return "CommandFrame{" +
                "subcommands=" + subcommands +
                '}';
    }

    public void putCommand(String name, CommandHandler handler) {
        subcommands.putCommand(name, handler);
    }
}
