// Tallies votes and displays the results as a text bar chart.

/// Returns a map from each option to its number of votes, in the order
/// the options first appear.
Map<String, Integer> tally(ArrayList<String> votes) {
    Map<String, Integer> counts = new LinkedHashMap<>();
    for (String vote : votes) {
        counts.put(vote, counts.getOrDefault(vote, 0) + 1);
    }
    return counts;
}

/// Returns every option tied for the most votes.
ArrayList<String> winners(Map<String, Integer> counts) {
    int best = 0;
    for (int count : counts.values()) {
        if (count > best) {
            best = count;
        }
    }

    ArrayList<String> leaders = new ArrayList<>();
    for (String option : counts.keySet()) {
        int count = counts.get(option);
        if (count == best) {
            leaders.add(option);
        }
    }
    return leaders;
}

/// Prints each option with its count, percentage, and a bar, most votes first.
void report(Map<String, Integer> counts, int total) {
    ArrayList<Map.Entry<String, Integer>> ranked = new ArrayList<>(counts.entrySet());
    ranked.sort(Comparator.comparing((Map.Entry<String, Integer> e) -> e.getValue())
            .reversed());

    IO.println(String.format("%-12s%6s%8s  Chart", "Option", "Votes", "Share"));
    IO.println("-".repeat(38));
    for (Map.Entry<String, Integer> entry : ranked) {
        int count = entry.getValue();
        double share = (double) count / total * 100;
        String bar = "#".repeat((int) Math.round(share / 4));
        String row = String.format("%-12s%6d%7.1f", entry.getKey(), count, share);
        IO.println(row + "%  " + bar);
    }
    IO.println("-".repeat(38));
}

void main() {
    ArrayList<String> votes = new ArrayList<>(List.of(
            "pizza", "tacos", "pizza", "sushi", "pizza",
            "tacos", "salad", "sushi", "pizza", "tacos",
            "sushi", "pizza", "tacos", "pizza", "sushi"));

    Map<String, Integer> counts = tally(votes);
    report(counts, votes.size());

    IO.println("Total votes:  " + votes.size());
    IO.println("Options used: " + new HashSet<>(votes).size());

    ArrayList<String> leaders = winners(counts);
    if (leaders.size() == 1) {
        IO.println("Winner:       " + leaders.get(0));
    } else {
        Collections.sort(leaders);
        IO.println("Tied:         " + String.join(", ", leaders));
    }
}

// From Groundwork, chapter 9 (ch09-maps-and-sets), box 23.
// This example is from Groundwork, licensed CC BY-NC-SA 4.0.
// Run with: java ch09_23.java
