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

package org.jline.console.impl;

import org.jline.reader.Completer;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.HashMap;
import org.jline.reader.impl.completer.SystemCompleter;
import java.util.Set;
import org.jline.console.CommandInput;
import org.jline.console.CommandMethods;
import java.util.Iterator;
import java.util.Map;
import org.jline.console.ArgDesc;
import org.jline.utils.AttributedStringBuilder;
import org.jline.utils.AttributedString;
import java.util.ArrayList;
import org.jline.console.CmdDesc;
import java.util.List;
import org.jline.console.CommandRegistry;

public abstract class AbstractCommandRegistry implements CommandRegistry
{
    private CmdRegistry cmdRegistry;
    private Exception exception;
    
    public CmdDesc doHelpDesc(final String command, final List<String> info, final CmdDesc cmdDesc) {
        final List<AttributedString> mainDesc = new ArrayList<AttributedString>();
        AttributedStringBuilder asb = new AttributedStringBuilder();
        asb.append(command.toLowerCase()).append(" -  ");
        for (final String s : info) {
            if (asb.length() == 0) {
                asb.append("\t");
            }
            asb.append(s);
            mainDesc.add(asb.toAttributedString());
            asb = new AttributedStringBuilder();
            asb.tabs(2);
        }
        asb = new AttributedStringBuilder();
        asb.tabs(7);
        asb.append("Usage:");
        for (final AttributedString as : cmdDesc.getMainDesc()) {
            asb.append("\t");
            asb.append(as);
            mainDesc.add(asb.toAttributedString());
            asb = new AttributedStringBuilder();
            asb.tabs(7);
        }
        return new CmdDesc(mainDesc, new ArrayList<ArgDesc>(), cmdDesc.getOptsDesc());
    }
    
    public <T extends Enum<T>> void registerCommands(final Map<T, String> commandName, final Map<T, CommandMethods> commandExecute) {
        this.cmdRegistry = new EnumCmdRegistry<Object>(commandName, commandExecute);
    }
    
    public void registerCommands(final Map<String, CommandMethods> commandExecute) {
        this.cmdRegistry = new NameCmdRegistry(commandExecute);
    }
    
    @Override
    public Object invoke(final CommandSession session, final String command, final Object... args) throws Exception {
        this.exception = null;
        final CommandMethods methods = this.getCommandMethods(command);
        final Object out = methods.execute().apply(new CommandInput(command, args, session));
        if (this.exception != null) {
            throw this.exception;
        }
        return out;
    }
    
    public void saveException(final Exception exception) {
        this.exception = exception;
    }
    
    @Override
    public boolean hasCommand(final String command) {
        return this.cmdRegistry.hasCommand(command);
    }
    
    @Override
    public Set<String> commandNames() {
        return this.cmdRegistry.commandNames();
    }
    
    @Override
    public Map<String, String> commandAliases() {
        return this.cmdRegistry.commandAliases();
    }
    
    public <V extends Enum<V>> void rename(final V command, final String newName) {
        this.cmdRegistry.rename(command, newName);
    }
    
    public void alias(final String alias, final String command) {
        this.cmdRegistry.alias(alias, command);
    }
    
    @Override
    public SystemCompleter compileCompleters() {
        return this.cmdRegistry.compileCompleters();
    }
    
    public CommandMethods getCommandMethods(final String command) {
        return this.cmdRegistry.getCommandMethods(command);
    }
    
    public Object registeredCommand(final String command) {
        return this.cmdRegistry.command(command);
    }
    
    private static class EnumCmdRegistry<T extends Enum<T>> implements CmdRegistry
    {
        private final Map<T, String> commandName;
        private Map<String, T> nameCommand;
        private final Map<T, CommandMethods> commandExecute;
        private final Map<String, String> aliasCommand;
        
        public EnumCmdRegistry(final Map<T, String> commandName, final Map<T, CommandMethods> commandExecute) {
            this.nameCommand = new HashMap<String, T>();
            this.aliasCommand = new HashMap<String, String>();
            this.commandName = commandName;
            this.commandExecute = commandExecute;
            this.doNameCommand();
        }
        
        private void doNameCommand() {
            this.nameCommand = this.commandName.entrySet().stream().collect(Collectors.toMap((Function<? super Object, ? extends String>)Map.Entry::getValue, (Function<? super Object, ? extends T>)Map.Entry::getKey));
        }
        
        @Override
        public Set<String> commandNames() {
            return this.nameCommand.keySet();
        }
        
        @Override
        public Map<String, String> commandAliases() {
            return this.aliasCommand;
        }
        
        @Override
        public <V extends Enum<V>> void rename(final V command, final String newName) {
            if (this.nameCommand.containsKey(newName)) {
                throw new IllegalArgumentException("Duplicate command name '" + command + "'!");
            }
            if (!this.commandName.containsKey(command)) {
                throw new IllegalArgumentException("Command '" + command + "' does not exists!");
            }
            this.commandName.put((T)command, newName);
            this.doNameCommand();
        }
        
        @Override
        public void alias(final String alias, final String command) {
            if (!this.nameCommand.containsKey(command)) {
                throw new IllegalArgumentException("Command '" + command + "' does not exists!");
            }
            this.aliasCommand.put(alias, command);
        }
        
        @Override
        public boolean hasCommand(final String name) {
            return this.nameCommand.containsKey(name) || this.aliasCommand.containsKey(name);
        }
        
        @Override
        public SystemCompleter compileCompleters() {
            final SystemCompleter out = new SystemCompleter();
            for (final Map.Entry<T, String> entry : this.commandName.entrySet()) {
                out.add(entry.getValue(), this.commandExecute.get(entry.getKey()).compileCompleter().apply(entry.getValue()));
            }
            out.addAliases(this.aliasCommand);
            return out;
        }
        
        @Override
        public T command(String name) {
            name = this.aliasCommand.getOrDefault(name, name);
            if (this.nameCommand.containsKey(name)) {
                final T out = this.nameCommand.get(name);
                return out;
            }
            throw new IllegalArgumentException("Command '" + name + "' does not exists!");
        }
        
        @Override
        public CommandMethods getCommandMethods(final String command) {
            return this.commandExecute.get(this.command(command));
        }
    }
    
    private static class NameCmdRegistry implements CmdRegistry
    {
        private final Map<String, CommandMethods> commandExecute;
        private final Map<String, String> aliasCommand;
        
        public NameCmdRegistry(final Map<String, CommandMethods> commandExecute) {
            this.aliasCommand = new HashMap<String, String>();
            this.commandExecute = commandExecute;
        }
        
        @Override
        public Set<String> commandNames() {
            return this.commandExecute.keySet();
        }
        
        @Override
        public Map<String, String> commandAliases() {
            return this.aliasCommand;
        }
        
        @Override
        public <V extends Enum<V>> void rename(final V command, final String newName) {
            throw new IllegalArgumentException();
        }
        
        @Override
        public void alias(final String alias, final String command) {
            if (!this.commandExecute.containsKey(command)) {
                throw new IllegalArgumentException("Command '" + command + "' does not exists!");
            }
            this.aliasCommand.put(alias, command);
        }
        
        @Override
        public boolean hasCommand(final String name) {
            return this.commandExecute.containsKey(name) || this.aliasCommand.containsKey(name);
        }
        
        @Override
        public SystemCompleter compileCompleters() {
            final SystemCompleter out = new SystemCompleter();
            for (final String c : this.commandExecute.keySet()) {
                out.add(c, this.commandExecute.get(c).compileCompleter().apply(c));
            }
            out.addAliases(this.aliasCommand);
            return out;
        }
        
        @Override
        public String command(final String name) {
            if (this.commandExecute.containsKey(name)) {
                return name;
            }
            return this.aliasCommand.get(name);
        }
        
        @Override
        public CommandMethods getCommandMethods(final String command) {
            return this.commandExecute.get(this.command(command));
        }
    }
    
    private interface CmdRegistry
    {
        boolean hasCommand(final String p0);
        
        Set<String> commandNames();
        
        Map<String, String> commandAliases();
        
        Object command(final String p0);
        
         <V extends Enum<V>> void rename(final V p0, final String p1);
        
        void alias(final String p0, final String p1);
        
        SystemCompleter compileCompleters();
        
        CommandMethods getCommandMethods(final String p0);
    }
}
