package stream.flarebot.flarebot.util;

import stream.flarebot.flarebot.FlareBot;
import stream.flarebot.flarebot.commands.Command;
import stream.flarebot.flarebot.commands.general.CommandUsageCommand;
import stream.flarebot.flarebot.commands.general.TagsCommand;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class UsageParser {

    public static void test(String... ss) {
        for (String s : matchUsage(new CommandUsageCommand(), ss)) {
            FlareBot.getInstance().getImportantLogChannel().sendMessage(s).queue();
        }
    }

    public static List<String> matchUsage(Command c, String[] args) {
        List<String> strings = new ArrayList<>();
        if (args.length == 0) {
            Collections.addAll(strings, c.getUsage().split("\n"));
            return strings;
        }
        for (String usage : c.getUsage().split("\n")) {
            Pattern p = Pattern.compile("`.+`");
            String symbols = usage.replace("{%}" + c.getCommand(), "").trim(); // Strip command out
            Matcher m = p.matcher(symbols);
            if (m.find()) {
                symbols = m.group().replace("`", "").trim();
            } else {
                continue;
            }
            Map<Integer, Pair<Symbol, String>> map = findSymbols(symbols);
            boolean applicable = false;
            if (args.length > map.size()) { // If there are more args than symbols it wouldn't be applicable
                continue;
            }
            for (Map.Entry<Integer, Pair<Symbol, String>> entry : map.entrySet()) {
                if (entry.getValue().getKey() == Symbol.SINGLE_SUB_COMMAND) {
                    if (args[entry.getKey()].equalsIgnoreCase(entry.getValue().getValue())) {
                        applicable = true; // Sub command matches arg
                    } else {
                        break; // We don't want to check any other args if this fails
                    }
                } else if (entry.getValue().getKey() == Symbol.MULTIPLE_SUB_COMMAND) {
                    for (String cmd : entry.getValue().getValue().split("\\|")) {
                        if (args[entry.getKey()].equalsIgnoreCase(cmd)) {
                            applicable = true;
                            break;
                        }
                    }
                    if (!applicable) break; // CHeck nothing else if this fails
                } else {
                    applicable = true;
                }
            }

            if (applicable) strings.add(usage);
        }
        return strings;
    }

    private static Map<Integer, Pair<Symbol, String>> findSymbols(String string) {
        Map<Integer, Pair<Symbol, String>> map = new HashMap<>();
        int i = 0;
        for (String s : string.split(" ")) {
            for (Symbol sy : Symbol.values()) {
                if (sy.matches(s)) map.put(i, new Pair<>(sy, s));
            }
            i++;
        }
        return map;
    }


    public enum Symbol {
        SINGLE_SUB_COMMAND(Pattern.compile("^[A-Za-z]+$")),
        MULTIPLE_SUB_COMMAND(Pattern.compile("^[A-z]+(\\|+[A-z]+)+$")),
        REQUIRED_ARG(Pattern.compile("^<.+>$")),
        OPTIONAL_ARG(Pattern.compile("^\\[.+\\]$"));

        private Pattern regex;

        Symbol(Pattern regex) {
            this.regex = regex;
        }

        public Pattern getRegex() {
            return regex;
        }

        public boolean matches(String arg) {
            return getRegex().matcher(arg).matches();
        }

    }

}

@@ -33,16 +33,61 @@
 .util;%0A%0A
+import org.apache.commons.lang3.StringUtils;%0A
 import s
@@ -232,32 +232,94 @@
 ndUsageCommand;%0A
+import stream.flarebot.flarebot.commands.general.PollCommand;%0A
 import stream.fl
@@ -389,24 +389,49 @@
 .ArrayList;%0A
+import java.util.Arrays;%0A
 import java.
@@ -695,28 +695,20 @@
 age(new 
-CommandUsage
+Poll
 Command(
@@ -934,24 +934,171 @@
 ayList%3C%3E();%0A
+        String%5B%5D usages = c.getUsage().split(%22%5Cn%22);%0A        usages = Arrays.stream(usages).filter(StringUtils::isNotEmpty).toArray(String%5B%5D::new);%0A
         if (
@@ -1161,32 +1161,14 @@
 gs, 
-c.getUsage().split(%22%5Cn%22)
+usages
 );%0A 
@@ -1236,32 +1236,14 @@
 e : 
-c.getUsage().split(%22%5Cn%22)
+usages
 ) %7B%0A
@@ -2196,32 +2196,76 @@
        %7D else %7B%0A
+                        applicable = false;%0A
                 
@@ -2435,32 +2435,75 @@
 _SUB_COMMAND) %7B%0A
+                    boolean valid = false;%0A
                 
@@ -2681,32 +2681,74 @@
 licable = true;%0A
+                            valid = true;%0A
                 
@@ -2839,27 +2839,92 @@
    if (!
-applicable)
+valid) %7B%0A                        applicable = false;%0A                       
  break; 
@@ -2951,32 +2951,54 @@
 e if this fails%0A
+                    %7D%0A
                 
@@ -3055,32 +3055,137 @@
               %7D%0A
+                if (!(args.length - 1 %3E= entry.getKey())) %7B%0A                    break;%0A                %7D%0A
             %7D%0A%0A 

Fix bugs kthnx