package io.github.mikesaelim.nomenclature;

import com.google.common.collect.Lists;
import com.google.common.collect.TreeMultimap;
import lombok.Value;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.egit.github.core.RepositoryId;
import org.eclipse.egit.github.core.Tree;
import org.eclipse.egit.github.core.TreeEntry;
import org.eclipse.egit.github.core.service.DataService;

import java.io.IOException;
import java.util.List;
import java.util.Set;

import static java.util.stream.Collectors.toSet;
import static org.apache.commons.lang3.StringUtils.removeEnd;
import static org.apache.commons.lang3.StringUtils.substringAfterLast;

public class Application {

    public static void main(String[] args) {
        DataService dataService = new DataService();

        Tree tree;
        try {
            tree = dataService.getTree(RepositoryId.create("mikesaelim", "arXivOAIHarvester"), "master", true);
        } catch (IOException e) {
            System.out.println(e.getMessage());
            return;
        }

        TreeMultimap<String, String> javaClassNamesByRoot = extractClassNamesAndCollateByRoot(tree);

        for (String root : javaClassNamesByRoot.keySet()) {
            Set<String> classNames = javaClassNamesByRoot.get(root);
            System.out.println(root + " (" + classNames.size() + "):");
            for (String className : classNames) {
                System.out.println("    " + className);
            }
        }
    }

    /**
     * TODO this method's name is intentionally annoying so that I will refactor this into smaller methods later
     * @param tree
     * @return
     */
    private static TreeMultimap<String, String> extractClassNamesAndCollateByRoot(Tree tree) {
        Set<String> classNames = tree.getTree().stream()
                .filter(t -> TreeEntry.TYPE_BLOB.equals(t.getType()))
                .filter(t -> t.getPath().endsWith(".java"))
                .map(t -> substringAfterLast(t.getPath(), "/"))
                .map(s -> removeEnd(s, ".java"))
                .sorted()
                .collect(toSet());

        TreeMultimap<String, String> classNamesByRoot = TreeMultimap.create();

        classNames.stream()
                .filter(StringUtils::isNotBlank)
                .filter(StringUtils::isAlphanumeric)
                .map(Application::tokenize)
                .filter(name -> name.numTokens() >= 2)
                .filter(name -> !name.getRoot().equals("Test"))
                .forEach(name -> classNamesByRoot.put(name.getRoot(), name.getClassName()));

        return classNamesByRoot;
    }

    private static TokenizedClassName tokenize(String className) {
        return new TokenizedClassName(className,
                Lists.newArrayList(StringUtils.splitByCharacterTypeCamelCase(className)));
    }

    @Value
    private static class TokenizedClassName {
        String className;
        List<String> tokens;

        public int numTokens() {
            return tokens.size();
        }

        public String getRoot() {
            return tokens.get(numTokens() - 1);
        }
    }

}

@@ -455,21 +455,128 @@
 va.util.
-Set;%0A
+Map;%0Aimport java.util.Set;%0Aimport java.util.function.Function;%0A%0Aimport static java.util.stream.Collectors.toMap;
 %0Aimport 
@@ -975,39 +975,32 @@
 te(%22
-mikesaelim%22, %22arXivOAIHarvester
+elastic%22, %22elasticsearch
 %22), 
@@ -1227,24 +1227,84 @@
 oot(tree);%0A%0A
+        System.out.println();%0A        System.out.println();%0A
         for 
@@ -1613,32 +1613,706 @@
      %7D%0A        %7D
+%0A%0A        Map%3CString, Integer%3E multiplicities = javaClassNamesByRoot.keySet().stream()%0A                .collect(toMap(Function.%3CString%3Eidentity(), s -%3E javaClassNamesByRoot.get(s).size()));%0A%0A        System.out.println();%0A        System.out.println();%0A        System.out.println(%22Mult.  Classname%22);%0A        System.out.println(%22----------------------------------%22);%0A        multiplicities.keySet().stream()%0A                .sorted((s1, s2) -%3E Integer.compare(multiplicities.get(s2), multiplicities.get(s1)))%0A                .forEachOrdered(s -%3E %7B%0A                    System.out.println(StringUtils.leftPad(multiplicities.get(s).toString(), 5) + %22  %22 + s);%0A                %7D);
 %0A    %7D%0A%0A    /**%0A

improve output; use elasticsearch for more interesting data