From dad332b961d14cac6c398eb01b1507ca5e70b953 Mon Sep 17 00:00:00 2001
From: Artemis-the-gr8 <artemis.the.gr8@gmail.com>
Date: Thu, 12 May 2022 17:11:52 +0200
Subject: [PATCH] Worked on formatting, started implementing method to get
 stats below each other at same indentation

---
 .../the/gr8/playerstats/ConfigHandler.java    | 17 ++--
 .../the/gr8/playerstats/StatManager.java      | 97 +++++++++----------
 .../gr8/playerstats/commands/StatCommand.java |  8 ++
 .../playerstats/utils/OutputFormatter.java    | 64 +++++++++---
 src/main/resources/config.yml                 |  8 +-
 5 files changed, 118 insertions(+), 76 deletions(-)

diff --git a/src/main/java/com/gmail/artemis/the/gr8/playerstats/ConfigHandler.java b/src/main/java/com/gmail/artemis/the/gr8/playerstats/ConfigHandler.java
index 2bbe46b..81dfa8c 100644
--- a/src/main/java/com/gmail/artemis/the/gr8/playerstats/ConfigHandler.java
+++ b/src/main/java/com/gmail/artemis/the/gr8/playerstats/ConfigHandler.java
@@ -24,16 +24,17 @@ public class ConfigHandler {
         HashMap<String, ChatColor> chatColors = new HashMap<>();
 
         ConfigurationSection individual = config.getConfigurationSection("individual-statistics");
-        chatColors.put("playerNames", getChatColor(individual, "player-names"));
-        chatColors.put("statNames", getChatColor(individual, "stat-names"));
-        chatColors.put("subStatNames", getChatColor(individual, "sub-stat-names"));
-        chatColors.put("numbers", getChatColor(individual, "numbers"));
+        chatColors.put("player-names", getChatColor(individual, "player-names"));
+        chatColors.put("stat-names", getChatColor(individual, "stat-names"));
+        chatColors.put("sub-stat-names", getChatColor(individual, "sub-stat-names"));
+        chatColors.put("stat-numbers", getChatColor(individual, "stat-numbers"));
 
         ConfigurationSection ranked = config.getConfigurationSection("ranked-list");
-        chatColors.put("playerNamesRanked", getChatColor(ranked, "player-names"));
-        chatColors.put("statNamesRanked", getChatColor(ranked, "stat-names"));
-        chatColors.put("subStatNamesRanked", getChatColor(ranked, "sub-stat-names"));
-        chatColors.put("numbersRanked", getChatColor(ranked, "numbers"));
+        chatColors.put("player-names-ranked", getChatColor(ranked, "player-names"));
+        chatColors.put("list-title", getChatColor(ranked, "list-title"));
+        chatColors.put("sub-stat-names-ranked", getChatColor(ranked, "sub-stat-names"));
+        chatColors.put("stat-numbers-ranked", getChatColor(ranked, "stat-numbers"));
+        chatColors.put("list-numbers", getChatColor(ranked, "list-numbers"));
         return chatColors;
     }
 
diff --git a/src/main/java/com/gmail/artemis/the/gr8/playerstats/StatManager.java b/src/main/java/com/gmail/artemis/the/gr8/playerstats/StatManager.java
index d7a4c2f..b3e79c2 100644
--- a/src/main/java/com/gmail/artemis/the/gr8/playerstats/StatManager.java
+++ b/src/main/java/com/gmail/artemis/the/gr8/playerstats/StatManager.java
@@ -8,7 +8,6 @@ import org.bukkit.Statistic;
 import org.bukkit.entity.EntityType;
 import org.jetbrains.annotations.NotNull;
 
-import java.io.IOException;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -55,49 +54,6 @@ public class StatManager {
         throw new IllegalArgumentException("Player object for " + playerName + " could not be retrieved!");
     }
 
-    private int getPlayerStat(@NotNull OfflinePlayer player, @NotNull Statistic stat, String subStatEntryName) throws IllegalArgumentException {
-        String methodName = "getPlayerStat";
-        long time = System.currentTimeMillis();
-
-        switch (stat.getType()) {
-            case UNTYPED -> {
-                return player.getStatistic(stat);
-            }
-            case BLOCK -> {
-                Material block = enumHandler.getBlock(subStatEntryName);
-                plugin.logTimeTaken(className, methodName, time, 68);
-                if (block != null) {
-                    return player.getStatistic(stat, block);
-                }
-                else {
-                    throw new IllegalArgumentException(subStatEntryName + " is not a valid block name!");
-                }
-            }
-            case ENTITY -> {
-                EntityType entity = enumHandler.getEntityType(subStatEntryName);
-                plugin.logTimeTaken(className, methodName, time, 78);
-                if (entity != null) {
-                    return player.getStatistic(stat, entity);
-                }
-                else {
-                    throw new IllegalArgumentException(subStatEntryName + " is not a valid entity name!");
-                }
-            }
-            case ITEM -> {
-                Material item = enumHandler.getItem(subStatEntryName);
-                plugin.logTimeTaken(className, methodName, time, 88);
-                if (item != null) {
-                    return player.getStatistic(stat, item);
-                }
-                else {
-                    throw new IllegalArgumentException(subStatEntryName + " is not a valid item name!");
-                }
-            }
-            default ->
-                throw new IllegalArgumentException("This statistic does not seem to be of type:untyped/block/entity/item, I think we should panic");
-        }
-    }
-
     public LinkedHashMap<String, Integer> getTopStatistics(String statName, String subStatEntry) throws IllegalArgumentException, NullPointerException {
         String methodName = "getTopStatistic";
         long time = System.currentTimeMillis();
@@ -114,7 +70,10 @@ public class StatManager {
                     OfflinePlayer player = offlinePlayerHandler.getOfflinePlayer(playerName);
                     if (player != null) {
                         try {
-                            playerStats.put(playerName, getPlayerStat(player, stat, subStatEntry));
+                            int statistic = getPlayerStat(player, stat, subStatEntry);
+                            if (statistic > 0) {
+                                playerStats.put(playerName, getPlayerStat(player, stat, subStatEntry));
+                            }
                         }
                         catch (IllegalArgumentException ignored) {
                         }
@@ -175,11 +134,6 @@ public class StatManager {
         throw new NullPointerException("Statistic " + statName + " could not be retrieved!");
     }
 
-    //checks if string is a valid statistic (param: statName, not case sensitive)
-    public boolean isStatistic(String statName) {
-        return statNames.contains(statName.toLowerCase());
-    }
-
     //gets the type of the statistic from the string, otherwise returns null (param: statName, not case sensitive)
     public Statistic.Type getStatType(String statName) {
         try {
@@ -205,6 +159,11 @@ public class StatManager {
         return entityStatNames;
     }
 
+    //checks if string is a valid statistic (param: statName, not case sensitive)
+    public boolean isStatistic(String statName) {
+        return statNames.contains(statName.toLowerCase());
+    }
+
     //checks if this statistic is a subStatEntry, meaning it is a block, item or entity (param: statName, not case sensitive)
     public boolean isSubStatEntry(String statName) {
         return subStatEntryNames.contains(statName.toLowerCase());
@@ -236,6 +195,44 @@ public class StatManager {
         }
     }
 
+    private int getPlayerStat(@NotNull OfflinePlayer player, @NotNull Statistic stat, String subStatEntryName) throws IllegalArgumentException {
+
+        switch (stat.getType()) {
+            case UNTYPED -> {
+                return player.getStatistic(stat);
+            }
+            case BLOCK -> {
+                Material block = enumHandler.getBlock(subStatEntryName);
+                if (block != null) {
+                    return player.getStatistic(stat, block);
+                }
+                else {
+                    throw new IllegalArgumentException(subStatEntryName + " is not a valid block name!");
+                }
+            }
+            case ENTITY -> {
+                EntityType entity = enumHandler.getEntityType(subStatEntryName);
+                if (entity != null) {
+                    return player.getStatistic(stat, entity);
+                }
+                else {
+                    throw new IllegalArgumentException(subStatEntryName + " is not a valid entity name!");
+                }
+            }
+            case ITEM -> {
+                Material item = enumHandler.getItem(subStatEntryName);
+                if (item != null) {
+                    return player.getStatistic(stat, item);
+                }
+                else {
+                    throw new IllegalArgumentException(subStatEntryName + " is not a valid item name!");
+                }
+            }
+            default ->
+                    throw new IllegalArgumentException("This statistic does not seem to be of type:untyped/block/entity/item, I think we should panic");
+        }
+    }
+
     //returns the statistic enum constant, or null if non-existent (param: statName, not case sensitive)
     private Statistic getStatisticEnum(String statName) {
         try {
diff --git a/src/main/java/com/gmail/artemis/the/gr8/playerstats/commands/StatCommand.java b/src/main/java/com/gmail/artemis/the/gr8/playerstats/commands/StatCommand.java
index c9c26c6..e58feee 100644
--- a/src/main/java/com/gmail/artemis/the/gr8/playerstats/commands/StatCommand.java
+++ b/src/main/java/com/gmail/artemis/the/gr8/playerstats/commands/StatCommand.java
@@ -73,7 +73,15 @@ public class StatCommand implements CommandExecutor {
 
                 if (topFlag) {
                     try {
+                        time = plugin.logTimeTaken("StatCommand", "onCommand", time, 76);
                         LinkedHashMap<String, Integer> topStats = statManager.getTopStatistics(statName, subStatEntry);
+
+                        time = plugin.logTimeTaken("StatCommand", "onCommand", time, 79);
+
+                        LinkedHashMap<String, Integer> topStats2 = statManager.getTopStatistics2(statName, subStatEntry);
+                        time = plugin.logTimeTaken("StatCommand", "onCommand", time, 82);
+
+                        sender.sendMessage(outputFormatter.formatTopStats(topStats, statName, subStatEntry));
                         return true;
                     }
                     catch (Exception e) {
diff --git a/src/main/java/com/gmail/artemis/the/gr8/playerstats/utils/OutputFormatter.java b/src/main/java/com/gmail/artemis/the/gr8/playerstats/utils/OutputFormatter.java
index 1eaa3b7..eb5aeb9 100644
--- a/src/main/java/com/gmail/artemis/the/gr8/playerstats/utils/OutputFormatter.java
+++ b/src/main/java/com/gmail/artemis/the/gr8/playerstats/utils/OutputFormatter.java
@@ -3,17 +3,20 @@ package com.gmail.artemis.the.gr8.playerstats.utils;
 import com.gmail.artemis.the.gr8.playerstats.ConfigHandler;
 import com.gmail.artemis.the.gr8.playerstats.Main;
 import org.bukkit.ChatColor;
+import org.bukkit.map.MinecraftFont;
 
-import java.util.HashMap;
-import java.util.LinkedHashMap;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
 
 public class OutputFormatter {
 
-    //keys for the HashMap are:
-        //playerNames(Ranked)
-        //statNames(Ranked)
-        //subStatNames(Ranked)
-        //numbers(Ranked)
+    //keys for the HashMap are the same as the config options:
+        //player-names(-ranked)
+        //stat-names OR list-title
+        //sub-stat-names(-ranked)
+        //stat-numbers(-ranked)
+        //list-numbers
+
     private final ConfigHandler config;
     private final Main plugin;
     private HashMap<String, ChatColor> chatColors;
@@ -23,14 +26,14 @@ public class OutputFormatter {
     public OutputFormatter(ConfigHandler c, Main p) {
         config = c;
         plugin = p;
-        pluginPrefix = ChatColor.GRAY + "[" + ChatColor.GOLD + "PlayerStats" + ChatColor.GRAY + "]" + ChatColor.RESET;
+        pluginPrefix = ChatColor.GRAY + "[" + ChatColor.GOLD + "PlayerStats" + ChatColor.GRAY + "] " + ChatColor.RESET;
 
         updateOutputColors();
         className = "OutputFormatter";
     }
 
     public String formatExceptions(String exception) {
-        return pluginPrefix + " " + exception;
+        return pluginPrefix + exception;
     }
 
     public String formatPlayerStat(String playerName, String statName, String subStatEntryName, int stat) {
@@ -39,17 +42,48 @@ public class OutputFormatter {
         time = plugin.logTimeTaken(className, methodName, time, 39);
 
         String subStat = subStatEntryName != null ?
-                chatColors.get("subStatNames") + " (" + subStatEntryName.toLowerCase().replace("_", " ") + ")" : "";
+                chatColors.get("sub-stat-names") + " (" + subStatEntryName.toLowerCase().replace("_", " ") + ")" : "";
         time = plugin.logTimeTaken(className, methodName, time, 43);
 
-        String msg = chatColors.get("playerNames") + playerName + chatColors.get("numbers") + ": " + stat + " " +
-                chatColors.get("statNames") + statName.toLowerCase().replace("_", " ") + subStat;
-        time = plugin.logTimeTaken(className, methodName, time, 47);
+        String msg = chatColors.get("player-names") + playerName + chatColors.get("stat-numbers") + ": " + stat + " " +
+                chatColors.get("stat-names") + statName.toLowerCase().replace("_", " ") + subStat;
+        plugin.logTimeTaken(className, methodName, time, 47);
         return msg;
     }
 
-    public String formatTopStats(LinkedHashMap<String, Integer> topStats) {
-        return "";
+    public String formatTopStats(LinkedHashMap<String, Integer> topStats, String statName, String subStatEntryName) {
+        String subStat = subStatEntryName != null ?
+                chatColors.get("sub-stat-names-ranked") + " (" + subStatEntryName.toLowerCase().replace("_", " ") + ")" : "";
+        String topCount = chatColors.get("list-numbers") + " " + topStats.size();
+        String title = pluginPrefix + chatColors.get("list-title") + "Top" + topCount + chatColors.get("list-title") + " " +
+                statName.toLowerCase().replace("_", " ") + subStat;
+
+        int count = 0;
+        final int[] longestName = {0};
+        Set<String> playerNames = topStats.keySet();
+        MinecraftFont font = new MinecraftFont();
+        playerNames.stream().map(font::getWidth).max(Integer::compareTo).orElseThrow();
+
+        try {
+            longestName[0] = playerNames.stream().map(String::length).max(Integer::compareTo).orElseThrow();
+        }
+        catch (NoSuchElementException e) {
+            longestName[0] = 20;
+        }
+
+
+        StringBuilder rankList = new StringBuilder();
+        for (String playerName : playerNames) {
+            count = count+1;
+
+            String spaces = (longestName[0] - playerName.length() > 0) ? " ".repeat(longestName[0] - playerName.length()) : "";
+            rankList.append("\n")
+                    .append(chatColors.get("list-numbers")).append(count).append(". ")
+                    .append(chatColors.get("player-names-ranked")).append(playerName).append(": ")
+                    .append(spaces)
+                    .append(chatColors.get("stat-numbers-ranked")).append(topStats.get(playerName).toString());
+        }
+        return title + rankList;
     }
 
     public void updateOutputColors() {
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index e1a083c..ef63dbd 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -6,10 +6,12 @@ individual-statistics:
   player-names: gold
   stat-names: yellow
   sub-stat-names: yellow
-  numbers: white
+  stat-numbers: white
 
 ranked-list:
   player-names: gold
-  stat-names: yellow
+  list-title: white
   sub-stat-names: yellow
-  numbers: white
\ No newline at end of file
+  stat-numbers: white
+  list-numbers: white
+