private void HandleMessage(string message) //when a the server receives a message from the client
            {
                if (message.StartsWith("GET_CATE:"))
                { // asking for specific category
                    string response = "";
                    message = message.Replace("GET_CATE:", "");
                    if (int.TryParse(message, out int id))
                    {
                        LastCategoryRequested = id;
                        if (Program.Database.AllCategories.TryGetValue(id, out Category cat))
                        {
                            response = $"{cat.ID}:{cat.Prompt}";
                            this.Send("Cat:" + response);
                        }
                    }
                    // dont respond if it is out of range.
                }/* else if (message.StartsWith("SET_CATE"))
                  * {
                  * message = message.Replace("SET_CATE", "");
                  * // expecting: ID:Username
                  *
                  * if(message.Contains(":"))
                  * {
                  *     string[] options = message.Split(':');
                  *     if(int.TryParse(options[0], out int id))
                  *     {
                  *         if(Program.TryGetUser(options[1], out User voted))
                  *         {
                  *             Program.Database.AddVoteFor(id, voted, this.User);
                  *         }
                  *     }
                  * }
                  * }*/
                else if (message.StartsWith("SUBMIT:"))
                { // submit all votes.
                    message = message.Replace("SUBMIT:", ""); //?? what is the format? SUBMIT:category;thing#category;thing ?
                    // SUBMIT:male;female#male;female#male;female ....
                    // the male;female pairs are in order, so we should just be able to increment a counter as we go thorugh each
                    string         rejectedReason = "";
                    UserVoteSubmit vote           = new UserVoteSubmit(this.User);
                    try
                    {
                        string[] cats = message.Split('#');               //categories
                        for (int index = 0; index < cats.Length; index++) //go through every category
                        {
                            string thing = cats[index];                   //?? a pair of male:female winners
                            if (string.IsNullOrWhiteSpace(thing))
                            {
                                continue;                          // but if we havnt given a winner for this category, it may be empty
                            }
                            string[] winners   = thing.Split(';'); // these are "male;female", so yes
                            string   maleWin   = winners[0];
                            string   femaleWin = winners[1];
                            Program.TryGetUser(maleWin, out User firstWinner);
                            Program.TryGetUser(femaleWin, out User secondWinner);
                            if ((firstWinner?.AccountName ?? ",") == (secondWinner?.AccountName ?? ""))
                            {
                                rejectedReason = "Rejected:Duplicate";
                                return; // break out
                            }
                            if (firstWinner != null)
                            {
                                if (firstWinner.AccountName == this.User.AccountName) //trying to vote for themself
                                {
                                    rejectedReason = "Rejected:Self";
                                }
                            }
                            if (secondWinner != null)
                            {
                                if (secondWinner.AccountName == this.User.AccountName)
                                {
                                    rejectedReason = "Rejected:Self";
                                }
                            }
                            if (string.IsNullOrWhiteSpace(rejectedReason))
                            {
                                vote.AddVote(index + 1, firstWinner, secondWinner);
                            }
                        }
                    } catch (Exception ex)
                    {
                        rejectedReason = "Rejected:Errored";
                        Logging.Log($"{UserName}/Submit", ex);
                    } finally
                    {
                        if (string.IsNullOrWhiteSpace(rejectedReason))
                        {
                            var now = DateTime.Now;
                            var ts  = now - this.StartedTime;
                            Program.Database.AlreadyVotedNames.Add(this.User.AccountName);
                            vote.Submit();
                            this.Send("Accepted");
                            Logging.Log(Logging.LogSeverity.Warning, $"User has voted (took: {ts})", this.User.AccountName);
                        }
                        else
                        {
                            this.Send(rejectedReason);
                        }
                        this.Close("Submitted");
                    }
                }
                else if (message.StartsWith("QUERY"))  //?? querying for what? - when user types in someone's name, query any student that contains that name
                {
                    message = message.Replace("QUERY:", "");
                    string response = "";
                    // format:
                    // ENTERED_TEXT
                    // its substring(2) '2' because we need to ignore first M/F and the :
                    var students = QueryStudent(message);
                    foreach (var student in students)
                    {
                        response += student.ToString("AN:FN:LN:TT") + "#";
                    }
                    this.Send("Q_RES:" + response);
                }
                else if (message.StartsWith("QUES:"))
                {
                    try
                    {
                        message = message.Substring(5);
                    } catch { }
                    Logging.Log(Logging.LogSeverity.Severe, "Category: " + message, this.UserName);
                    try
                    {
                        System.IO.File.AppendAllText($@"..\..\..\CategorySuggestions.txt", $"{this.UserName} - {message}\r\n");
                    } catch (Exception ex)
                    {
                        Logging.Log("SuggestFile", ex);
                    }
                }
                else if (message.StartsWith("REPORT:"))
                {
                    var report = BugReport.BugReport.Parse(message, this.User);
                    Logging.Log(Logging.LogSeverity.Warning,
                                $"NEW: {report.Primary ?? report.Additional}{(string.IsNullOrWhiteSpace(report.Primary) ? "" : " " + report.Additional)} @ {report.LogFile}"
                                , $"Bugs/{report.Reporter.AccountName}");
                    Program.BugReports.Add(report);
                    Program.SaveBugs();
                }
                else if (message.StartsWith("/"))
                {
                    // admin message
                    message = message.Substring(1);
                    if (message.StartsWith("CHAT:"))
                    {
                        message = message.Substring(5);
                        Program.SendAdminChat(new AdminMessage(this, message));
                    }
                    else if (message.StartsWith("QUEUE"))
                    {
                        var str = "/AQU:";
                        int num = 0;
                        foreach (var s in ClientQueue)
                        {
                            num += 1;
                            str += $"{s.User.AccountName}:{s.User.FirstName}:{s.User.LastName}:{s.User.Tutor}:{num}:{s.IPAddress}#";
                        }
                        Send(str);
                    }
                    else if (message.StartsWith("VOTERS"))
                    {
                        var str = "/AVT:";
                        int num = 0;
                        foreach (var s in CurrentClients)
                        {
                            num += 1;
                            str += $"{s.User.AccountName}:{s.User.FirstName}:{s.User.LastName}:{s.User.Tutor}:{(int)s.Authentication}:{s.IPAddress}#";
                        }
                        Send(str);
                    }
                    else if (message.StartsWith("KICK:"))
                    {
                        message = message.Substring("KICK:".Length);
                        var split = message.Split(':');
                        if (Program.TryGetUser(split[0], out User user))
                        {
                            var conn = AllClients.FirstOrDefault(x => x.User.AccountName == user.AccountName);
                            if (conn != null)
                            {
                                if (conn.Authentication >= this.Authentication || conn.UserName == this.UserName)
                                {
                                    return; // prevent kicking self or those with higher 'auth'
                                }
                                var kick = new Kick(conn, this.User, split[1]);
                                if (Program.Options.Perm_Block_Kicked_Users)
                                {
                                    PriorKickedUsers.Add(kick);
                                }
                                conn.Send("Kicked:" + kick.Reason);
                                AdminMessage msg = new AdminMessage("Server", Authentication.Sysadmin, $"[STATUS] {kick.Kicked.AccountName} was kicked by {kick.Admin.AccountName} for {kick.Reason}");
                                Program.SendAdminChat(msg);
                                conn.Close($"Kicked by {kick.Admin.AccountName} with reason {kick.Reason}");
                            }
                        }
                    }
                    else if (message.StartsWith("MANR:"))
                    {
                        message = message.Replace("MANR:", "");
                        if (Program.TryGetUser(message, out User user))
                        {
                            string response = "/MANRD:";
                            foreach (var category in Program.Database.AllCategories.Values)
                            {
                                var votes = category.GetVotesBy(user);
                                response += $"{votes.Item1?.ToString("AN:FN:LN:TT") ?? ""};{votes.Item2?.ToString("AN:FN:LN:TT") ?? ""}#";
                            }
                            Send(response);
                        }
                    }
                    else if (message.StartsWith("MANVOTE:"))
                    {
                        message = message.Replace("MANVOTE:", "");
                        var split = message.Split(':');
                        if (Program.Database.AllStudents.TryGetValue(split.ElementAt(0), out User user))
                        {
                            int categoryId = 1;
                            var votes      = split.ElementAt(1).Split('#').Where(x => !string.IsNullOrWhiteSpace(x));
                            foreach (string vote in votes)
                            {
                                var each = vote.Split(';');
                                Program.TryGetUser(each.ElementAt(0), out User first);
                                Program.TryGetUser(each.ElementAt(1), out User second);
                                if (first != null)
                                {
                                    Program.Database.AddVoteFor(categoryId, first, user);
                                }
                                if (second != null)
                                {
                                    Program.Database.AddVoteFor(categoryId, second, user);
                                }
                                categoryId++;
                            }
                        }
                    }
                    else if (message.StartsWith("QUERY:"))
                    {
                        message = message.Replace("QUERY:", "");
                        var split = message.Split(':').Where(x => !string.IsNullOrWhiteSpace(x)).ToList();

                        var rowIndex = int.Parse(split[0]);
                        var colIndex = int.Parse(split[1]);
                        var queryT   = split[2];
                        var students = QueryStudent(queryT);
                        if (students.Count == 1)
                        {
                            Send($"/QUERY:{rowIndex}:{colIndex}:{students[0].ToString("AN;FN;LN;TT")}");
                        }
                    }
                }
            }