/// <summary>
        /// Admin command to end an existing vote.
        /// </summary>
        public void CMD_EndVote(string[] cmds, IUserMessage message)
        {
            if (!DemocracyBot.IsAdmin(message.Author))
            {
                return;
            }
            FDSSection topicSection = VotingCommands.GetVoteTopicSection(cmds, message, out string topicName);

            if (topicSection == null)
            {
                return;
            }
            topicName = topicName.ToLowerFast();
            Console.WriteLine($"Trying to end vote for {topicName} at {StringConversionHelper.DateTimeToString(DateTimeOffset.UtcNow, true)}");
            FDSSection choicesSection = topicSection.GetSection("Choices");

            Bot.ConfigFile.Set("old_topics." + StringConversionHelper.DateTimeToString(DateTimeOffset.UtcNow, true).Replace(".", "_") + "_topic_" + topicName.Replace(".", "_"), topicSection);
            string realKey = DemocracyBot.VoteTopicsSection.Data.Keys.First(s => s.ToLowerFast() == topicName);

            DemocracyBot.VoteTopicsSection.Remove(realKey);
            RefreshTopicData(topicName, topicSection, true);
            FDSSection userResultsSection = topicSection.GetSection("user_results");

            tallyVotes(topicSection, choicesSection, userResultsSection, message, topicName, true);
        }
        public void CMD_VoteStatus(string[] cmds, IUserMessage message)
        {
            if (!DemocracyBot.IsAdmin(message.Author))
            {
                return;
            }
            FDSSection topicSection = VotingCommands.GetVoteTopicSection(cmds, message, out string topicName);

            if (topicSection == null)
            {
                return;
            }
            topicName = topicName.ToLowerFast();
            Console.WriteLine($"Trying get vote status for {topicName} at {StringConversionHelper.DateTimeToString(DateTimeOffset.UtcNow, true)}");
            FDSSection choicesSection = topicSection.GetSection("Choices");
            string     realKey        = DemocracyBot.VoteTopicsSection.Data.Keys.First(s => s.ToLowerFast() == topicName);

            RefreshTopicData(topicName, topicSection, false);
            FDSSection userResultsSection = topicSection.GetSection("user_results");

            tallyVotes(topicSection, choicesSection, userResultsSection, message, topicName, false);
        }
        /// <summary>
        /// Admin command to end an existing vote.
        /// </summary>
        public void CMD_EndVote(string[] cmds, IUserMessage message)
        {
            if (!DemocracyBot.IsAdmin(message.Author))
            {
                return;
            }
            FDSSection topicSection = VotingCommands.GetVoteTopicSection(cmds, message, out string topicName);

            if (topicSection == null)
            {
                return;
            }
            topicName = topicName.ToLowerFast();
            Console.WriteLine($"Trying to end vote for {topicName} at {StringConversionHelper.DateTimeToString(DateTimeOffset.UtcNow, true)}");
            FDSSection choicesSection = topicSection.GetSection("Choices");

            Bot.ConfigFile.Set("old_topics." + StringConversionHelper.DateTimeToString(DateTimeOffset.UtcNow, true).Replace(".", "_") + "_topic_" + topicName.Replace(".", "_"), topicSection);
            string realKey = DemocracyBot.VoteTopicsSection.Data.Keys.First(s => s.ToLowerFast() == topicName);

            DemocracyBot.VoteTopicsSection.Remove(realKey);
            RefreshTopicData(topicName, topicSection, true);
            FDSSection userResultsSection = topicSection.GetSection("user_results");

            if (userResultsSection == null || userResultsSection.GetRootKeys().IsEmpty())
            {
                SendGenericNegativeMessageReply(message, $"Vote For Topic {topicName} Failed", "No votes were cast.");
                DemocracyBot.Save();
                return;
            }
            List <List <string> > voteSets = new List <List <string> >(50);

            foreach (string userId in userResultsSection.GetRootKeys())
            {
                List <string> choices = userResultsSection.GetStringList(userId);
                if (choices != null && !choices.IsEmpty() && !(choices.Count == 1 && choices[0] == "none"))
                {
                    voteSets.Add(choices);
                }
            }
            if (voteSets.IsEmpty())
            {
                SendGenericNegativeMessageReply(message, $"Vote For Topic {topicName} Failed", "No votes were cast.");
                DemocracyBot.Save();
                return;
            }
            int usersWhoVotedTotal = voteSets.Count;
            Dictionary <string, int> votesTracker = new Dictionary <string, int>(128);
            string winner           = voteSets[0][0];
            string secondPlace      = voteSets[0][0];
            int    discards         = 0;
            bool   haveWinner       = false;
            string winnerStats      = "(error: stats missing)";
            string secondPlaceStats = "(error: second place missing)";

            string gatherStats(string choice, string type)
            {
                int numberHadFirst = 0;
                int positionTotal  = 0;
                int numberHadAtAll = 0;

                foreach (string userId in userResultsSection.GetRootKeys())
                {
                    List <string> choices = userResultsSection.GetStringList(userId);
                    if (choices != null && !choices.IsEmpty())
                    {
                        int index = choices.IndexOf(choice);
                        if (index != -1)
                        {
                            numberHadAtAll++;
                            positionTotal += index + 1;
                            if (index == 0)
                            {
                                numberHadFirst++;
                            }
                        }
                    }
                }
                return($"Options that were discarded due to low support: {discards}\n"
                       + $"Users whose votes were discarded due to supporting only unpopular options: {usersWhoVotedTotal - voteSets.Count}\nUsers who listed the {type} first: {numberHadFirst}\n"
                       + $"Users who listed the {type} at all: {numberHadAtAll}\nAverage ranking of the {type}: {positionTotal / (float)numberHadAtAll:0.0}");
            }

            while (true)
            {
                votesTracker.Clear();
                foreach (List <string> voteSet in voteSets)
                {
                    string vote = voteSet[0];
                    if (!votesTracker.TryGetValue(vote, out int count))
                    {
                        count = 0;
                    }
                    votesTracker[vote] = count + 1;
                }
                if (votesTracker.Count == 0)
                {
                    Console.WriteLine("Something went funky in vote counting... tracker is empty without a clear winner!");
                    break;
                }
                string best = voteSets[0][0], worst = voteSets[0][0];
                int    bestCount = 0, worstCount = int.MaxValue;
                foreach (KeyValuePair <string, int> voteResult in votesTracker)
                {
                    if (voteResult.Value > bestCount)
                    {
                        best      = voteResult.Key;
                        bestCount = voteResult.Value;
                    }
                    if (voteResult.Value < worstCount)
                    {
                        worst      = voteResult.Key;
                        worstCount = voteResult.Value;
                    }
                }
                if (bestCount * 2 > voteSets.Count)
                {
                    if (!haveWinner)
                    {
                        winner      = best;
                        winnerStats = gatherStats(winner, "winner");
                        haveWinner  = true;
                        for (int i = 0; i < voteSets.Count; i++)
                        {
                            if (voteSets[i].Contains(winner))
                            {
                                voteSets[i].Remove(winner);
                                if (voteSets[i].IsEmpty())
                                {
                                    voteSets.RemoveAt(i--);
                                }
                            }
                        }
                        worst = winner;
                    }
                    else
                    {
                        secondPlace      = best;
                        secondPlaceStats = gatherStats(secondPlace, "runner up");
                        break;
                    }
                }
                for (int i = 0; i < voteSets.Count; i++)
                {
                    if (voteSets[i][0] == worst)
                    {
                        voteSets[i].RemoveAt(0);
                        if (voteSets[i].IsEmpty())
                        {
                            voteSets.RemoveAt(i--);
                        }
                    }
                }
                if (!haveWinner)
                {
                    discards++;
                }
            }
            SendGenericPositiveMessageReply(message, $"Vote Results For **{topicName}: {topicSection.GetString("Topic")}**", $"**__Winner__**: **{winner}**: `{choicesSection.GetString(winner)}`"
                                            + $"\n\n**Stats:**\nUsers who voted, in total: {usersWhoVotedTotal}\n{winnerStats}\n\n"
                                            + $"**__Runner Up__**: **{secondPlace}**: `{choicesSection.GetString(secondPlace)}`\n**Stats For Runner Up**:\n{secondPlaceStats}");
            DemocracyBot.Save();
        }