﻿
/////////////////////////////////////////////////
//Major user handler, contains most of the project//
/////////////////////////////////////////////////

using Newtonsoft.Json;
using SteamKit2;
using SteamTrade;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Threading;
using System.Timers;
using System.Linq;
using SteamTrade.TradeWebAPI;
using SteamTrade.TradeOffer;
using System.Collections.Specialized;

namespace SteamBot
{
    public class MajorUserHandler : UserHandler
    {
        public static string ConsoleTitle = "Cheeky Wizard's Console of Magic"; //Edit to change title of console
        public static string BotVersion = "1.4.2"; //Change according to each update
        public static int InviteTimerInterval = 100; //Set invite timer interval
        //Change text in here to show what has been updated in the latest build
        public string ChangeLog = "Change log for version " + BotVersion + ". This latest build contains:\n:B1:Removed Moderator function.\n:B1:Added Restart Method for ease of restarting cmd.\n:B1:Restart now functions as it should. (No more crashing)\n:B1:Added Voting system to group chat.\n:B1:Voting now only counts Yes and No for an individual once.\n";

        public int userScrapAdded = 0;
        public int userWepAdded = 0;
        public int botScrapAdded = 0;
        public int botWepAdded = 0;
        public int invalidItem = 0;
        public int inventoryWeapon = 0;
        public int inventoryMetal = 0;
        public int inventoryKeys = 0;
        public int inventoryRef = 0;
        public int inventoryRec = 0;
        public int inventoryScrap = 0;
        public int giftWrap = 0;
        public int duelingGame = 0;
        public int decalTool = 0;
        public int backpackExpander = 0;
        public int helpNeeded = 0;
        public int ScrapPutUp = 0;
        public int fakeRep = 0;
        public int floodControl = 0;


        public bool buyWeapons = false;
        public bool errorMsgRun = false;
        public bool remove = false;
        public bool InGroupChat = false;
        public bool HasRun = false;
        public bool TimerDisabled = true;
        public bool TimerEnabled = false;
        public bool Crafted = true;
        public bool Smelt = false;
        public bool NoTrade = true;
        public bool HasCounted = false;

        static bool vote = false;
        static int yes = 0;
        static int no = 0;

        public bool LuckyCat() // Cheeky Wizard has a lucky cat, and the lucky cat says meow randomly
        {
            Random random = new Random();
            int RandomInt = random.Next(3);
            Bot.Log.LuckyCat("" + RandomInt);
            if (RandomInt.Equals(1))
            {
                Bot.Log.LuckyCat("meow");
                Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "meow");
            }
            return true;
        }

        public static String scrape(string Url)
        {
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(Url);
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            StreamReader sr = new StreamReader(response.GetResponseStream());
            string html = sr.ReadToEnd();
            sr.Close();
            response.Close();
            Console.Write(html);
            return html;
        }

        public void Restart() // Restart method
        {
            var filename = System.Reflection.Assembly.GetExecutingAssembly().Location;
            System.Diagnostics.Process.Start(filename);
            // Closes the current process
            Environment.Exit(0);
        }

        public void AddAllMetal() //Adds all metal in bot's inventory
        {
            var items = Trade.CurrentSchema.GetItemsByCraftingMaterial("craft_bar");

            foreach (var item in items)
            {
                Trade.AddAllItemsByDefindex(item.Defindex);
            }
        }

        public void AddAllItems() //Adds all items in bot's inventory
        {
            var items = Trade.CurrentSchema.GetItems();

            foreach (var item in items)
            {
                Trade.AddAllItemsByDefindex(item.Defindex, 0);
            }
        }

        public System.Timers.Timer inviteMsgTimer = new System.Timers.Timer(InviteTimerInterval);

        static SteamID currentSID;

        public MajorUserHandler(Bot bot, SteamID sid) : base(bot, sid) { }

        BotBan Ban = new BotBan();
        MembersList Group = new MembersList();
        SteamGauges Gauge = new SteamGauges();
        private string originalmessage;

        public bool isMarked(string steamId32)
        {
            // Create the SteamRep API address with the SteamID32.
            string api = "http://steamrep.com/id2rep.php?steamID32={0}";
            string url = string.Format(api, steamId32);

            // Fetch the result of the endpoint as a string.
            WebClient client = new WebClient();
            string result = client.DownloadString(url);

            // Check for the string "SCAMMER" in the result.
            return (result.IndexOf("SCAMMER") > -1);
        }

        /// <summary>
        /// Posts a comment to user's profile
        /// </summary>
        public bool PostComment(string comment, SteamID user)
        {
            {
                CookieContainer cookies = new CookieContainer(); cookies.Add(new Cookie("sessionid", SteamWeb.SessionId, String.Empty, "steamcommunity.com")); cookies.Add(new Cookie("steamLogin", SteamWeb.Token, String.Empty, "steamcommunity.com"));
                var data = new NameValueCollection();
                data.Add("comment", comment);
                data.Add("count", "6");
                data.Add("sessionid", SteamWeb.SessionId);
                string response = SteamWeb.Fetch("http://steamcommunity.com/comment/Profile/post/" + Convert.ToString(user) + "/-1/", "POST", data, true, "");
                GetRsaKey rsaJSON = JsonConvert.DeserializeObject<GetRsaKey>(response);
                if (rsaJSON.success == true)
                {
                    Log.Success("Comment success");
                    return rsaJSON.success;
                }
                else
                {
                    Log.Success("Comment failure");
                    return false;
                }
            }
        }
        // When a user sends a group request, log it
        public override bool OnGroupAdd()
        {
            Bot.Log.Success("Received group invite; declined.");
            return false;
        }

        // When a user adds this bot, Accept and log it
        public override bool OnFriendAdd()
        {
            Console.Beep(500, 500);
            Bot.Log.Success(Bot.SteamFriends.GetFriendPersonaName(OtherSID) + " (" + OtherSID.ConvertToUInt64() + ") added me!");
            inviteMsgTimer = new System.Timers.Timer();
            inviteMsgTimer.Interval = InviteTimerInterval;
            inviteMsgTimer.Elapsed += (sender, e) => OnInviteTimerElapsed(sender, e, EChatEntryType.ChatMsg);
            inviteMsgTimer.Enabled = true;
            return true;
        }

        // When bot logs on, set state and let the cheeky wizard in
        public override void OnLoginCompleted()
        {
            for (int i = 0; i <= 100; i++)
            {
                Console.Title = string.Format("Loading " + Bot.DisplayName + " - {0}%", i);
                Thread.Sleep(20);
            }
            Console.Title = ConsoleTitle;
            Bot.SteamFriends.SetPersonaState(EPersonaState.LookingToTrade);
            Bot.SteamFriends.JoinChat(103582791435642512);
        }

        public override void OnChatRoomMessage(SteamID chatID, SteamID sender, string message)
        {
            Bot.Log.Chat("GROUP: " + Bot.SteamFriends.GetFriendPersonaName(sender) + ": " + message);
            base.OnChatRoomMessage(chatID, sender, message);
            if (message.Equals("!vote"))
            {
                if (IsAdmin)
                {
                    File.WriteAllText(@"..\Debug\vote.txt", "");
                    if (!vote)
                    {
                        vote = true;
                        Bot.SteamFriends.SendChatRoomMessage(chatID, EChatEntryType.ChatMsg, "Voting has started. Type \"yes\" or \"no\" to cast your vote.");
                    }
                    else
                    {
                        vote = false;
                        Bot.SteamFriends.SendChatRoomMessage(chatID, EChatEntryType.ChatMsg, "The voting has ended with " + yes + " yes votes, and " + no + " no votes.");
                        yes = 0;
                        no = 0;
                    }
                }
            }
            if (vote)
            {
                if (!File.ReadAllText(@"..\Debug\vote.txt").ToString().Contains(OtherSID.ConvertToUInt64().ToString()))
                {
                    if (message.ToLower().Equals("yes"))
                    {
                        File.WriteAllText(@"..\Debug\vote.txt", OtherSID.ConvertToUInt64().ToString());
                        yes++;
                    }
                    else if (message.ToLower().Equals("no"))
                    {
                        File.WriteAllText(@"..\Debug\vote.txt", OtherSID.ConvertToUInt64().ToString());
                        no++;
                    }
                }
            }
        }
        // When a user removes this bot, log it and feel sad :(
        public override void OnFriendRemove()
        {
            Bot.Log.Success("Removed by: " + Bot.SteamFriends.GetFriendPersonaName(OtherSID) + " (" + OtherSID.ToString() + ")");
        }

        // When a user messages me, respond accordingly
        public override void OnMessage(string message, EChatEntryType EChatEntryType)
        {
            originalmessage = message;
            message = message.ToLower();
            if (Ban.IsBanned(OtherSID))
            {
                Bot.Log.Ban(Bot.SteamFriends.GetFriendPersonaName(OtherSID) + ": " + message);
            }
            else
            {
                Bot.Log.Chat(Bot.SteamFriends.GetFriendPersonaName(OtherSID) + ": " + message);
            }

            // BANNED chat commands
            // If user asks if they're banned, answer them
            if (message.Contains("banned"))
            {
                if (Ban.IsBanned(OtherSID))
                {
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "You are banned.");
                }
                else
                {
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "You are not banned. Thanks.");
                }
            }

            else if (Ban.IsBanned(OtherSID))
            {
                Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "meow");
            }

            // DOT chat commands (ADMIN)
            // Bot adds all it's items in trade window
            else if (message.Contains("add all") || message == ".addall")
            {
                if (IsAdmin)
                {
                    AddAllItems();
                }
                else
                {
                    Trade.SendMessage("You are not an admin, you may not access this command.");
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "You are not an admin, you may not access this command.");
                    Bot.Log.Admin(Bot.SteamFriends.GetFriendPersonaName(OtherSID) + " (" + OtherSID.ToString() + ") tried to accessed the add all command.");
                }
            }

            // Bot adds all it's metal in trade window
            else if (message.Contains("add metal") || message == ".addmetal")
            {
                if (IsAdmin)
                {
                    AddAllMetal();
                }
                else
                {
                    Trade.SendMessage("You are not an admin, you may not access this command.");
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "You are not an admin, you may not access this command.");
                    Bot.Log.Admin(Bot.SteamFriends.GetFriendPersonaName(OtherSID) + " (" + OtherSID.ToString() + ") tried to accessed the add metal command.");
                }
            }
            // ] Also change these AddAll commands down below at 'OnTradeMessage', use search function. ^^

            // Ease of use to get specific api key through chat
            else if (message == ".api")
            {
                if (IsAdmin)
                {
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, Bot.ApiKey);
                }
                else
                {
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "You are not an admin, you may not access this command.");
                    Bot.Log.Admin(Bot.SteamFriends.GetFriendPersonaName(OtherSID) + " (" + OtherSID.ConvertToUInt64().ToString() + ") tried to access the api command.");
                }
            }

            //else if (message.EndsWith("=") || message.EndsWith("?"))
            //{
            //    double x = Convert.ToInt32(message.First().ToString());
            //    double y = Convert.ToInt32(message.TrimEnd('?', '=').Last().ToString());
            //    if (message.Contains("+"))
            //    {
            //        Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, (x + y).ToString());
            //    }
            //    else if (message.Contains("-"))
            //    {
            //        Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, (x - y).ToString());
            //    }
            //    else if (message.Contains("*"))
            //    {
            //        Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, (x * y).ToString());
            //    }
            //    else if (message.Contains("/"))
            //    {
            //        Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, (x / y).ToString());
            //    }
            //}

            // Set status as away
            else if (message == ".afk" || message == ".away")
            {
                if (IsAdmin)
                {
                    Bot.SteamFriends.SetPersonaState(EPersonaState.Away);
                }
            }
            // Set status as looking to trade (online/working)
            else if (message == ".online" || message == ".lookingtotrade" || message == ".back")
            {
                if (IsAdmin)
                {
                    Bot.SteamFriends.SetPersonaState(EPersonaState.LookingToTrade);
                }
            }

            else if (message.StartsWith(".rep"))
            {
                if (message.Equals(".rep") || message.Equals(".rep "))
                {
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, ".rep data is gathered in real-time from SteamRep.com. Use: '.rep <SteamID64>'");
                }
                else if (message.Equals(".rep fake"))
                {
                    if (fakeRep == 0)
                    {
                        fakeRep = 1;
                        Bot.Log.Admin("Fake Rep is " + fakeRep + ": ONLINE.");
                        Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "Fake Rep is " + fakeRep + ": Online.");
                    }
                    else
                    {
                        fakeRep = 0;
                        Bot.Log.Admin("Fake Rep is " + fakeRep + ": OFFLINE.");
                        Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "Fake Rep is " + fakeRep + ": Offline.");
                    }
                }
                else
                {
                    string[] sSplit = message.Split(' ');
                    SteamID friendtorep = new SteamID((sSplit[1]));
                    {
                        if (fakeRep == 1)
                        {
                            Bot.Log.Admin("Fake Rep is " + fakeRep + ": Online.");
                            Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, Bot.SteamFriends.GetFriendPersonaName(friendtorep) + " (" + friendtorep.ConvertToUInt64() + ") is marked as a Scammer! Be precautious.");
                        }
                        else if (!isMarked(friendtorep.Render()))
                        {
                            Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, Bot.SteamFriends.GetFriendPersonaName(friendtorep) + " (" + friendtorep.ConvertToUInt64() + ") is not marked as a Scammer. They are safe.");
                            Bot.Log.Success(Bot.SteamFriends.GetFriendPersonaName(friendtorep) + " (" + friendtorep.ConvertToUInt64() + ") is not marked as a Scammer. They are safe.");
                            if (Bot.SteamFriends.GetFriendPersonaName(friendtorep) == "[unknown]")
                            {
                                Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "\"[unknown]\" means I am not friends with this user.");
                            }
                        }
                        else
                        {
                            Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, Bot.SteamFriends.GetFriendPersonaName(friendtorep) + " (" + friendtorep.ConvertToUInt64() + ") is marked as a Scammer! Be precautious.");
                            Bot.Log.Warn(Bot.SteamFriends.GetFriendPersonaName(friendtorep) + " (" + friendtorep.ConvertToUInt64() + ") is marked as a Scammer! Be precautious.");
                            if (Bot.SteamFriends.GetFriendPersonaName(friendtorep) == "[unknown]")
                            {
                                Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "\"[unknown]\" means I am not friends with this user.");
                            }
                        }
                    }
                }
            }

            //.ban a user via their SteamID64 (This will NOT block them on steam), eg: .ban 76561198065217384
            else if (message.StartsWith(".ban"))
            {
                if (IsAdmin)
                {
                    string[] sSplit = message.Split(' ');
                    SteamID friendtoban = new SteamID(Convert.ToUInt64(sSplit[1]));
                    Ban.AddBan(Bot, friendtoban, false);
                    Bot.Log.Admin("Banned: " + Bot.SteamFriends.GetFriendPersonaName(friendtoban) + " (" + friendtoban.ConvertToUInt64() + ")");
                }
            }
            //.permban a user via their SteamID64 (This WILL block them on steam), eg: .permban 76561198065217384
            else if (message.StartsWith(".permban") || message.StartsWith(".permaban"))
            {
                if (IsAdmin)
                {
                    string[] sSplit = message.Split(' ');
                    SteamID friendtopermban = new SteamID(Convert.ToUInt64(sSplit[1]));
                    Ban.AddBan(Bot, friendtopermban, true);
                    Bot.Log.Admin("Permanently banned: " + Bot.SteamFriends.GetFriendPersonaName(friendtopermban) + " (" + friendtopermban.ConvertToUInt64() + ")");
                }
            }
            //.unban a user via their SteamID64, eg: .unban 76561198065217384
            else if (message.StartsWith(".unban"))
            {
                if (IsAdmin)
                {
                    string[] sSplit = message.Split(' ');
                    SteamID friendtounban = new SteamID(Convert.ToUInt64(sSplit[1]));
                    Ban.RemoveBan(Bot, friendtounban, false);
                    Bot.Log.Admin("Unbanned: " + Bot.SteamFriends.GetFriendPersonaName(friendtounban) + " (" + friendtounban.ConvertToUInt64() + ")");
                }
            }
            //.add a user via their SteamID64, eg: .add 76561198065217384
            else if (message.StartsWith(".add"))
            {
                if (IsAdmin)
                {
                    string[] sSplit = message.Split(' ');
                    SteamID friendtoadd = new SteamID(Convert.ToUInt64(sSplit[1]));
                    Bot.SteamFriends.AddFriend(friendtoadd);
                    Bot.Log.Admin("Added: " + Bot.SteamFriends.GetFriendPersonaName(friendtoadd) + " (" + friendtoadd.ConvertToUInt64() + ")");
                }
            }
            //.remove a user via their SteamID64, eg: .remove 76561198065217384
            else if (message.StartsWith(".remove"))
            {
                if (IsAdmin)
                {
                    string[] sSplit = message.Split(' ');
                    SteamID friendtoremove = new SteamID(Convert.ToUInt64(sSplit[1]));
                    Bot.SteamFriends.RemoveFriend(friendtoremove);
                    Bot.Log.Admin("Removed: " + Bot.SteamFriends.GetFriendPersonaName(friendtoremove) + " (" + friendtoremove.ConvertToUInt64() + ")");
                }
            }

            //.trade a user via their SteamID64, eg: .trade 76561198065217384
            else if (message.StartsWith(".trade"))
            {
                if (IsAdmin)
                {
                    string[] sSplit = message.Split(' ');
                    SteamID friendtotrade = new SteamID(Convert.ToUInt64(sSplit[1]));
                    Bot.SteamTrade.Trade(friendtotrade);
                    Bot.Log.Admin("Traded: " + Bot.SteamFriends.GetFriendPersonaName(friendtotrade) + " (" + friendtotrade.ConvertToUInt64() + ")");
                }
            }

            //.invite a user to 'Tradr' Steam Group via their SteamID64, eg: .invite 76561198065217384
            else if (message.StartsWith(".invite"))
            {
                if (IsAdmin)
                {
                    string[] sSplit = message.Split(' ');
                    SteamID friendtoinvite = new SteamID(Convert.ToUInt64(sSplit[1]));
                    Bot.InviteUserToGroup(friendtoinvite, 103582791435642512);
                    Bot.Log.Admin("Invited to group: " + Bot.SteamFriends.GetFriendPersonaName(friendtoinvite) + " (" + friendtoinvite.ConvertToUInt64() + ")");
                }
            }

            else if (message.StartsWith("http://") || message.StartsWith("https://") || message.StartsWith("www."))
            {
                if (IsAdmin)
                {
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, scrape(message));
                    Bot.Log.Success(Bot.SteamFriends.GetFriendPersonaName(OtherSID) + " (" + OtherSID.ConvertToUInt64() + ") requested webpage: " + message);
                }
            }

            else if (message.Contains("scraptf"))
            {
                HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("https://scrap.tf/raffles");
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                StreamReader sr = new StreamReader(response.GetResponseStream());
                string html = sr.ReadToEnd();
                sr.Close();
                response.Close();
                Console.Write(html);
                var url = html.StartsWith("ScrapTF.Raffles.RedirectToRaffle('");
                Log.Admin(url.ToString());
            }

            //else if (message.StartsWith(".convert"))
            //{
            //    //    var filetype = message.Substring(message.Length - 3);
            //    //    var filetypeconversion = "https://api.cloudconvert.com/conversiontypes?inputformat=" + filetype;
            //    //    var preClient = new WebClient();
            //    //    var preResponse = preClient.DownloadString(filetypeconversion);
            //    //    Log.Admin(preResponse.Replace('[', '{').Replace(']', '}'));
            //    //    var preCloud = JsonConvert.DeserializeObject<ConversionTypes>(preResponse);
            //    //    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "Valid file types for " + filetype + " are " + preCloud.outputformat.ToString());

            //    var messagetostring = message.Remove(10);
            //    var convertapikey = "ojN0U282VJXNqj_CjoBxnKYkYFsKalRbptxKgmCup8gvrZkTZ5OwWXKHntBXSdkQnOLYVbJGtS8v8mvwQz1d-A";
            //    var converturl = "https://api.cloudconvert.com/convert?apikey=" + convertapikey + "&input=download&filename=" + Bot.SteamFriends.GetFriendPersonaName(OtherSID) + ".png&download=inline&wait=false&inputformat=png&outputformat=png&file=" + messagetostring;

            //    var finalClient = new WebClient();
            //    var finalResponse = finalClient.DownloadString(converturl);
            //    var finalCloud = JsonConvert.DeserializeObject<CloudConvert>(finalResponse);
            //    Bot.Log.Admin(Bot.SteamFriends.GetFriendPersonaName(OtherSID) + " converted file URL at " + finalCloud.output.url.ToString());
            //    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "Your image has been rehosted at " + finalCloud.output.url.ToString());
            //}

            else if (message.StartsWith(".comment"))
            {
                if (IsAdmin)
                {
                    if (message.Equals(".comment") || message.Equals(".comment "))
                    {
                        Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "Comment is a feature where you can comment on a friend's profile via the Bot. To comment on someone's profile, simply type \".comment <User to comment on's SteamID64> \"your comment here>\"\".");
                    }
                    else
                    {
                        string[] sSplit = message.Split(' ');
                        string[] mSplit = message.Split('"');
                        SteamID profiletocomment = new SteamID(Convert.ToUInt64(sSplit[1]));
                        PostComment(mSplit[1], profiletocomment);
                        Bot.Log.Message(Bot.SteamFriends.GetFriendPersonaName(profiletocomment) + " (" + profiletocomment.ConvertToUInt64() + ") received: " + mSplit[1] + ".");
                    }
                }
                else
                {
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "You are not an admin, you may not access this command.");
                    Bot.Log.Admin(Bot.SteamFriends.GetFriendPersonaName(OtherSID) + " (" + OtherSID.ToString() + ") tried to accessed the message command.");
                }
            }

            //.message a user via their SteamID64, eg: .message, 76561198065217384, <your message here>
            else if (message.StartsWith(".message"))
            {
                if (IsAdmin)
                {
                    if (message.Equals(".message") || message.Equals(".message "))
                    {
                        Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "Message is a feature where you can message a friend via the Bot. To message someone, simply type \".message <User to message's SteamID64> \"your message here>\"\".");
                    }
                    else
                    {
                        string[] sSplit = message.Split(' ');
                        string[] mSplit = message.Split('"');
                        SteamID friendtomessage = new SteamID(Convert.ToUInt64(sSplit[1]));
                        Bot.SteamFriends.SendChatMessage(friendtomessage, EChatEntryType.ChatMsg, "[MESSAGE] " + mSplit[1]);
                        Bot.Log.Message(Bot.SteamFriends.GetFriendPersonaName(friendtomessage) + " (" + friendtomessage.ConvertToUInt64() + ") received: " + mSplit[1] + ".");
                    }
                }
                else
                {
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "You are not an admin, you may not access this command.");
                    Bot.Log.Admin(Bot.SteamFriends.GetFriendPersonaName(OtherSID) + " (" + OtherSID.ToString() + ") tried to accessed the message command.");
                }
            }

            // Broadcast a message to all online friends. Use: .announce <your message here>
            else if (message.StartsWith(".announce"))
            {
                if (IsAdmin)
                {
                    if (message.Equals(".announce") || message.Equals(".announce "))
                    {
                        Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "Announcements is a feature where you can announce to online friends a message. To announce something, simply type \".announce <your message here>\".");
                    }
                    else
                    {
                        int numFriends = Bot.SteamFriends.GetFriendCount();
                        for (int count = 0; count < numFriends; count++)
                        {
                            SteamID SendChatMessage = Bot.SteamFriends.GetFriendByIndex(count);
                            ulong FriendID = SendChatMessage.ConvertToUInt64();
                            {
                                if (Bot.SteamFriends.GetFriendPersonaState(FriendID) != EPersonaState.Offline)
                                {
                                    Bot.SteamFriends.SendChatMessage(FriendID, EChatEntryType.ChatMsg, "[ANNOUNCEMENT]" + message.TrimStart('.', 'a', 'n', 'o', 'u', 'c', 'e').ToString()); // TrimStart will remove .announce from the announcement you are announcing.
                                    System.Threading.Thread.Sleep(100);
                                }
                            }
                        }
                        Bot.Log.Announcement(Bot.SteamFriends.GetFriendPersonaName(OtherSID) + " (" + OtherSID.ConvertToUInt64() + "): " + message + ".");
                    }
                }
                else
                {
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "You are not an admin, you may not access this command.");
                    Bot.Log.Admin(Bot.SteamFriends.GetFriendPersonaName(OtherSID) + " (" + OtherSID.ToString() + ") tried to accessed the announcement command.");
                }
            }

            else if (message.StartsWith(".status"))
            {
                var Client = new WebClient();
                var Response = Client.DownloadString(new Uri("https://steamgaug.es/api/v2"));
                var Gauge = JsonConvert.DeserializeObject<SteamGauges>(Response);
                if (Gauge.SteamCommunity.online != 1)
                {
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "SteamCommunity returned " + Gauge.SteamStore.online + " meaning it's down, in " + Gauge.SteamStore.time.ToString() + " ms");
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "It is down because " + Gauge.SteamCommunity.error);
                }
                else
                {
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "SteamCommunity returned " + Gauge.SteamStore.online + " meaning it's online, in " + Gauge.SteamStore.time.ToString() + " ms");
                }
            }

            // Restart the bot by typing this command
            else if (message == ".restart")
            {
                if (IsAdmin)
                {
                    Bot.Log.Interface("Console has been manually restarted.");
                    Restart();
                }
                else
                {
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "You are not an admin, you may not access this command.");
                    Bot.Log.Admin(Bot.SteamFriends.GetFriendPersonaName(OtherSID) + " (" + OtherSID.ToString() + ") tried to accessed the restart command.");
                }
            }

            // Stop the bot by typing this command
            else if (message == ".stop")
            {
                if (IsAdmin)
                {
                    Bot.Log.Interface(Bot.DisplayName + " has been stopped.");
                    Bot.StopBot();
                }
                else
                {
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "You are not an admin, you may not access this command.");
                    Bot.Log.Admin(Bot.SteamFriends.GetFriendPersonaName(OtherSID) + " (" + OtherSID.ToString() + ") tried to accessed the stop command.");
                }
            }

            else if (message.Equals(".shutdown"))
            {
                if (IsAdmin)
                {
                    Bot.Log.Interface("Console has been terminated.");
                    Environment.Exit(0);
                }
                else
                {
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "You are not an admin, you may not access this command.");
                    Bot.Log.Admin(Bot.SteamFriends.GetFriendPersonaName(OtherSID) + " (" + OtherSID.ToString() + ") tried to accessed the stop command.");
                }
            }

            // Craft all possible weapons in inventory together
            else if (message == ".craft")
            {
                if (IsAdmin)
                {
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "Checking inventory for all possible crafts.");
                    AutoCraftAll();
                }
                else
                {
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "You are not an admin, you may not access this command.");
                    Bot.Log.Admin(Bot.SteamFriends.GetFriendPersonaName(OtherSID) + " (" + OtherSID.ToString() + ") tried to accessed the craft command.");
                }
            }

            // Smelt all possible reclaimed in inventory together
            else if (message == ".smeltreclaimed")
            {
                if (IsAdmin)
                {
                    Bot.GetInventory();
                    Bot.SetGamePlaying(440);
                    try
                    {
                        foreach (var item in Bot.MyInventory.GetItemsByDefindex(5001))
                        {
                            ulong[] metal = { item.Id };
                            TF2GC.Crafting.CraftItems(Bot, (short)TF2GC.ECraftingRecipe.SmeltReclaimed, metal);
                        }
                        Bot.Log.Craft("Found Reclaimed. Smelting...");
                    }
                    catch
                    {
                        Bot.Log.Craft("Can't Smelt.");
                    }
                    Bot.SetGamePlaying(0);
                }
            }

            // Smelt all possible refined in inventory together
            else if (message == ".smeltrefined")
            {
                if (IsAdmin)
                {
                    Bot.GetInventory();
                    Bot.SetGamePlaying(440);
                    try
                    {
                        foreach (var item in Bot.MyInventory.GetItemsByDefindex(5002))
                        {
                            ulong[] metal = { item.Id };
                            TF2GC.Crafting.CraftItems(Bot, (short)TF2GC.ECraftingRecipe.SmeltRefined, metal);
                        }
                        Bot.Log.Craft("Found Refined. Smelting...");
                    }
                    catch
                    {
                        Bot.Log.Craft("Can't Smelt.");
                    }
                    Bot.SetGamePlaying(0);
                }
            }

            // Open/Close Team Fortress 2 with one simple command
            else if (message == ".tf2")
            {
                if (IsAdmin)
                {
                    if (Bot.CurrentGame != 440)
                    {
                        Bot.SetGamePlaying(440);
                        Bot.Log.TF2("Username: \"" + Bot.SteamFriends.GetFriendPersonaName(OtherSID) + "\" (" + OtherSID.ToString() + ") made me OPEN Team Fortress 2.");
                    }
                    else
                    {
                        Bot.SetGamePlaying(0);
                        Bot.Log.TF2("Username: \"" + Bot.SteamFriends.GetFriendPersonaName(OtherSID) + "\" (" + OtherSID.ToString() + ") made me CLOSE Team Fortress 2.");
                    }
                }
            }

            // Check if you're admin; if you are, it will list some commands available to admins
            else if (message == ".admin")
            {
                if (IsAdmin)
                {
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "Yes, you are an admin. Helpful admin commands include: .restart, .stop, .cancel, .craft, .announce");
                    Bot.Log.Admin(Bot.SteamFriends.GetFriendPersonaName(OtherSID) + " (" + OtherSID.ToString() + ") accessed the admin command.");
                }
                else
                {
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "You are not an admin, you may not access this command.");
                    Bot.Log.Admin(Bot.SteamFriends.GetFriendPersonaName(OtherSID) + " (" + OtherSID.ToString() + ") tried to accessed the admin command.");
                }
            }

            // List of user handlers that you can simply switch to
            else if (message == ".userhandler")
            {
                if (IsAdmin)
                {
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "A list of '.dot' user handler includes .userhandlermajor, .userhandleradmin, and .userhandlerdonate");
                }
                else
                {
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "You are not an admin, you may not access this command.");
                    Bot.Log.Admin(Bot.SteamFriends.GetFriendPersonaName(OtherSID) + " (" + OtherSID.ToString() + ") tried to accessed the user handler command.");
                }
            }

            // Switch to Admin User handler
            else if (message == ".userhandleradmin")
            {
                if (IsAdmin)
                {
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "Switching to Admin User handler.");
                    string json = System.IO.File.ReadAllText("settings.json");
                    dynamic jsonObj = Newtonsoft.Json.JsonConvert.DeserializeObject(json);
                    jsonObj["Bots"][0]["BotControlClass"] = "SteamBot.AdminUserHandler";
                    jsonObj["Bots"][0]["ChatResponse"] = "Welcome to Mattr's personal SteamBot. This bot is currently in Admin User handler.";
                    string output = Newtonsoft.Json.JsonConvert.SerializeObject(jsonObj, Newtonsoft.Json.Formatting.Indented);
                    System.IO.File.WriteAllText("settings.json", output);
                    Bot.Log.Interface("Switched bot to Admin User handler.");
                    Restart();
                }
                else
                {
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "You are not an admin, you may not access this command.");
                    Bot.Log.Admin(Bot.SteamFriends.GetFriendPersonaName(OtherSID) + " (" + OtherSID.ToString() + ") tried to accessed the admin user handler command.");
                }
            }

            // Switch to Major User handler
            else if (message == ".userhandlermajor")
            {
                if (IsAdmin)
                {
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "Switching to Major User handler.");
                    string json = System.IO.File.ReadAllText("settings.json");
                    dynamic jsonObj = Newtonsoft.Json.JsonConvert.DeserializeObject(json);
                    jsonObj["Bots"][0]["BotControlClass"] = "SteamBot.MajorUserHandler";
                    jsonObj["Bots"][0]["ChatResponse"] = "I am a Personal SteamBot, I will not be able to respond to your in depth conversations. I am currently scrapbanking. type \"help\" for help.";
                    string output = Newtonsoft.Json.JsonConvert.SerializeObject(jsonObj, Newtonsoft.Json.Formatting.Indented);
                    System.IO.File.WriteAllText("settings.json", output);
                    Bot.Log.Interface("Switched bot to Major User handler.");
                    Restart();
                }
                else
                {
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "You are not an admin, you may not access this command.");
                    Bot.Log.Admin(Bot.SteamFriends.GetFriendPersonaName(OtherSID) + " (" + OtherSID.ToString() + ") tried to accessed the scrap user handler command.");
                }
            }

            // Switch to Donate User handler
            else if (message == ".userhandlerdonate")
            {
                if (IsAdmin)
                {
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "Switching to Donate User handler.");
                    string json = System.IO.File.ReadAllText("settings.json");
                    dynamic jsonObj = Newtonsoft.Json.JsonConvert.DeserializeObject(json);
                    jsonObj["Bots"][0]["BotControlClass"] = "SteamBot.DonateUserHandler";
                    jsonObj["Bots"][0]["ChatResponse"] = "Welcome to Mattr's personal SteamBot. This bot is currently in Donation Mode.";
                    string output = Newtonsoft.Json.JsonConvert.SerializeObject(jsonObj, Newtonsoft.Json.Formatting.Indented);
                    System.IO.File.WriteAllText("settings.json", output);
                    Bot.Log.Interface("Switched bot to Donate User handler.");
                    Restart();
                }
                else
                {
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "You are not an admin, you may not access this command.");
                    Bot.Log.Admin(Bot.SteamFriends.GetFriendPersonaName(OtherSID) + " (" + OtherSID.ToString() + ") tried to accessed the admin user handler command.");
                }
            }

            // If trade is open, cancel it
            else if (message == ".cancel")
            {
                if (IsAdmin)
                {
                    if (Trade.TradeStarted == true)
                    {
                        var TraderID = Trade.OtherSID;
                        Bot.SteamFriends.SendChatMessage(TraderID, EChatEntryType.ChatMsg, "Trade has been manually canceled by an Admin.");
                        Trade.CancelTrade();
                        Bot.Log.Interface("Trade has been forcefully canceled.");
                    }
                    else
                    {
                        Bot.SteamFriends.SendChatMessage(currentSID, EChatEntryType.ChatMsg, "No trade was open to cancel");
                    }
                }
            }

            //REGULAR chat commands
            // Sending love
            else if (message.Equals("<3") || message.Equals("♥"))
            {
                Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, message);
            }

            else if (message.Contains("meme"))
            {
                Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "http://niceme.me/");
            }

            else if (message.StartsWith("\u02D0") && message.EndsWith("\u02D0"))
            {
                Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, message);
            }

            else if (message.Contains("sonic"))
            {
                Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "gotta go fast!!");
            }

            // Meow
            else if ((message.Contains("meow") && message.EndsWith(":3")) && !Ban.IsBanned(OtherSID))
            {
                Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "=^.^=");
            }
            else if ((message.Contains("meow") || message.Contains(":3")) && !Ban.IsBanned(OtherSID))
            {
                Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "meow");
            }


            // Let's the user know you're appreciated
            else if (message.StartsWith("thank") || message.StartsWith("ty") || message.StartsWith("thx") || message.StartsWith("thnx"))
            {
                Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "You're welcome!");
            }

            else if (message.StartsWith("steamid"))
            {

                // STEAM_X:Y:Z
                // [U:Y:Z*2+Y]

                if (message.Equals("steamid"))
                {
                    string Steam3 = OtherSID.ToString();
                    char Y;
                    string Z;
                    Y = Steam3.ElementAt(8);
                    Z = Steam3.Substring(10);
                    int intZ = Int32.Parse(Z);
                    int intY = Int32.Parse(Y.ToString());
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "Your SteamID's are \nsteamID: " + OtherSID.ToString() + "\nsteamID64: " + OtherSID.ConvertToUInt64() + "\nsteamID3: [U:" + Y + ":" + (intZ * 2 + Y) + "]");
                }
                else
                {
                    string Steam3 = message.Substring(8);
                    char Y;
                    string Z;
                    Y = Steam3.ElementAt(8);
                    Z = Steam3.Substring(10);
                    int intZ = Int32.Parse(Z);
                    int intY = Int32.Parse(Y.ToString());
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "\nsteamID: " + OtherSID.ToString() + "\nsteamID64: " + OtherSID.ConvertToUInt64() + "\nsteamID3: [U:" + Y + ":" + (intZ * 2 + Y) + "]");

                }
            }

            // Trade with user if they're unsure how to trade
            else if (message == ("!trade") || (message.Contains("trade") && message.Contains("how")))
            {
                if (!Ban.IsBanned(OtherSID))
                {
                    Bot.SteamTrade.Trade(OtherSID);
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "I am sending you a trade request, as you requested.");
                    Bot.Log.Trade("Trading: \"" + Bot.SteamFriends.GetFriendPersonaName(OtherSID) + "\" (" + OtherSID.ConvertToUInt64() + ")");
                }
                else
                {
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "meow");
                }
            }

            else if (message == (".group") || (message.Contains("invite") && message.Contains("group")))
            {
                if (!Group.isMember(OtherSID))
                {
                    Bot.InviteUserToGroup(OtherSID, Group.Tradr);
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "You requested to join our Steam Group, an invite has been sent.");
                }
                else
                {
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "You are already part of our Steam Group, check your groups tab to find us.\nAlternatively, here is a convenient link: http://steamcommunity.com/gid/103582791435642512");
                }
            }

            // Tell user you're in the wrong chat to buy
            else if (message == "buy")
            {
                Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "Type that into the Trade Window, not here!");
            }

            // Popping pingas, Fucking mingas
            else if (message.Contains("pinga"))
            {
                Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "\"Popping pingas; fucking mingas\" - Cheeky Wizard's life quote");
            }

            else if (message == "test")
            {
            }

            // Helps the user by sending them 'help'
            else if (message.Contains("help"))
            {
                helpNeeded++;

                if (helpNeeded == 1)
                {
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "If you are selling weapons, simply add 2 weapons and the bot will automatically add 1 scrap.");
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "If you want to buy weapons, first you must type \"buy\" and then type in what weapon you want. ");
                }
                else if (helpNeeded < 3)
                {
                    if (message.Equals("help needed"))
                    {
                        helpNeeded++;
                        //Bot.SteamFriends.SendChatMessage(Bot.Admins, EChatEntryType.ChatMsg, Bot.SteamFriends.GetFriendPersonaName(OtherSID) + " (" + OtherSID.ConvertToUInt64() + ") needs further assistance.");
                        Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "An admin has been notified that you need further assistance");
                    }
                    else
                    {
                        Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "Type \"help needed\" if you wish to call an admin to assist you.");
                        helpNeeded = 0;
                    }
                }
                else if (helpNeeded >= 3)
                {
                    helpNeeded--;
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "If an admin does not arrive soon, feel free to add them via the Steam Group admins. \".group\" to get an invite to the group.");
                }
            }

            // Tell user about what the 'Dot' commands are
            else if (message == "." || message.Contains(".dot"))
            {
                Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "'Dots' are admin commands, standard users will not be able to access these. ");
            }

            // Wizard telling them to fuck off
            else if (message.Contains("cheeky wizard"))
            {
                Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "fuck off, I'm not your mate");
            }

            // Tell the user how much metal the bot currently has
            // Doesn't work while not in trade.
            else if ((message == "stock") || ((message.Contains("much") || message.Contains("many")) && (message.Contains("scrap") || message.Contains("metal"))))
            {
                if (Trade.TradeStarted)
                {
                    TradeCountInventory();
                }
                else
                {
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "You must be in a trade for 'stock' to load.");
                }
            }

            // User requesting change log, give them change log and log it
            else if (message.Contains("changelog"))
            {
                Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, ChangeLog);
                Bot.Log.Success(Bot.SteamFriends.GetFriendPersonaName(OtherSID) + " (" + OtherSID.ToString() + ") requested changelog.");
            }

            //When user needs help, let me Google that for them
            else if ((message.Contains("who") || message.Contains("what") || message.Contains("why") || message.Contains("when") || message.Contains("where") || message.Contains("how")) && message.EndsWith("?"))
            {
                Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "Let me Google™ that for you! http://lmgtfy.com/?q=" + Uri.EscapeUriString(message));
            }

            // SPAM filter
            // If a user says any letter more than 10 times; let them know, ban them and remove them
            else if (message.Length > 10 || message.Contains(" "))
            {
                string msg = message;
                var occurances = new Dictionary<char, int>();
                foreach (char chr in msg)
                {
                    if (occurances.ContainsKey(chr))
                        occurances[chr] = occurances[chr] + 1;
                    else
                        occurances[chr] = 1;
                }
                foreach (var entry in occurances)
                {
                    if ((entry.Value > 20) && !IsAdmin)
                    {
                        Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "It is noted that you are spamming me, you will now be banned.");
                        Ban.AddBan(Bot, OtherSID, false);
                    }
                }
            }


            // Send stock bot response if nothing applies to commands above
            else
            {
                Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, Bot.ChatResponse);
            }
        }

        // On trade offer request, log it
        public override void OnNewTradeOffer(TradeOffer offer)
        {
            var myItems = offer.Items.GetMyItems();
            var theirItems = offer.Items.GetTheirItems();
            if (myItems.Count == 0)
            {
                Log.Admin("lol accepted");
                offer.Accept();
            }
            else
            {
                offer.Decline();
                Log.Trade("OFFER: from " + Bot.SteamFriends.GetFriendPersonaName(offer.PartnerSteamId) + " was declined");
                Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "Tradr Bots currently do NOT accept trade offers, implementation of this feature will occur soon. ᵛᵃᶫᵛᵉ ᵗᶦᵐᵉ");
                Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "Don't forget to join the 'Tradr' group for announcements of when this feature is available. !group to automatically get an invite");
            }
        }

        // On trade request, log it
        public override bool OnTradeRequest()
        {
            if (!Ban.IsBanned(OtherSID))
            {
                LuckyCat();
                Bot.Log.Trade("Requested trade from: \"" + Bot.SteamFriends.GetFriendPersonaName(OtherSID) + "\" (" + OtherSID.ConvertToUInt64() + ")");
                return true;
            }
            else
            {
                Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "You are banned. You may not trade with this bot.");
                return false;
            }
        }


        // On trade error, let user know what happened
        public override void OnTradeError(string error)
        {
            Bot.SteamFriends.SendChatMessage(OtherSID,
                                              EChatEntryType.ChatMsg,
                                              "Error: " + error + "."
                                              );
            Bot.Log.Warn(error);
            Bot.SteamFriends.SetPersonaState(EPersonaState.LookingToTrade);
        }

        // If trade timeout/user is afk, let them know
        public override void OnTradeTimeout()
        {
            Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "Sorry, but you were either AFK or took too long and the trade was canceled.");
            Bot.Log.Warn("User was kicked because he was AFK.");
            Bot.SteamFriends.SetPersonaState(EPersonaState.LookingToTrade);
        }

        // When in trade, Welcome user and let them know what to do
        public override void OnTradeInit()
        {
            Bot.SteamFriends.SetPersonaState(EPersonaState.Busy);
            ReInit();
            Bot.Log.Trade("Accepting trade from: \"" + Bot.SteamFriends.GetFriendPersonaName(OtherSID) + "\" (" + OtherSID.ConvertToUInt64() + ")");
            Trade.SendMessage("Welcome to Mattr's personal bot (version: " + BotVersion + ")!");
            TradeCountInventory();
            Trade.SendMessage("Please add your items now. Type \"buy\" if you are buying weapons.");
        }

        // When item is added, check qualities and that
        public override void OnTradeAddItem(Schema.Item schemaItem, Inventory.Item inventoryItem)
        {
            var item = Trade.CurrentSchema.GetItem(schemaItem.Defindex);
            Bot.Log.Success(Bot.SteamFriends.GetFriendPersonaName(OtherSID) + " added: " + schemaItem.Name);
            if (invalidItem >= 4)
            {
                Trade.CancelTrade();
                Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "Stop messing around. This bot is used for scrapbanking, and will only accept scrap or craftable weapons.");
            }
            else if ((item.CraftClass == "weapon" || item.CraftMaterialType == "weapon") && !inventoryItem.IsNotCraftable)
            {
                if (inventoryItem.Quality.ToString() != "6" || item.Name.Contains("Festive"))
                {
                    Trade.SendMessage(schemaItem.ItemName + " is not a valid item! Please remove it from the trade.");
                    invalidItem++;
                    Bot.Log.Warn("This is a special weapon and will not be accepted.");
                }
                else
                {
                    userWepAdded++;
                }
                if (inventoryScrap == 0)
                {
                    Trade.SendMessage("I have no more scrap so I can't accept any more weapons! Please remove the item.");
                    Bot.Log.Warn("I don't have enough scrap to give to the user.");
                }
                else if (userWepAdded % 2 == 0 && userWepAdded != 0)
                {
                    Trade.AddItemByDefindex(5000);
                    botScrapAdded++;
                    inventoryScrap--;
                    Bot.Log.Warn(Bot.DisplayName + " added: Scrap Metal");
                }
            }
            else if (item.Defindex == 5000)
            {
                userScrapAdded++;
            }
            else
            {
                Trade.SendMessage(schemaItem.ItemName + " is not a valid item! Please remove it from the trade.");
                invalidItem++;
            }
        }

        // When item is removed, log it
        public override void OnTradeRemoveItem(Schema.Item schemaItem, Inventory.Item inventoryItem)
        {
            var item = Trade.CurrentSchema.GetItem(schemaItem.Defindex);
            Bot.Log.Success(Bot.SteamFriends.GetFriendPersonaName(OtherSID) + " removed: " + schemaItem.Name);
            if ((item.CraftClass == "weapon" || item.CraftMaterialType == "weapon") && !inventoryItem.IsNotCraftable)
            {
                if (inventoryItem.Quality.ToString() != "6" || item.Name.Contains("Festive"))
                {
                    invalidItem--;
                    Bot.Log.Warn(Bot.SteamFriends.GetFriendPersonaName(OtherSID) + " (" + OtherSID.ConvertToUInt64() + ") removed special item.");
                }
                else
                {
                    userWepAdded--;
                }
                if (userWepAdded < botScrapAdded * 2 && userWepAdded != 0)
                {
                    Trade.RemoveItemByDefindex(5000);
                    botScrapAdded--;
                    inventoryScrap++;
                    Bot.Log.Warn(Bot.SteamFriends.GetFriendPersonaName(currentSID) + " (" + currentSID.ConvertToUInt64() + ") removed: Scrap Metal");
                }
            }
            else if (item.Defindex == 5000)
            {
                userScrapAdded--;
            }
            else
            {
                invalidItem--;
            }
        }

        public override void OnTradeMessage(string message)
        {
            Bot.Log.Trade("[TRADE MESSAGE] " + message);
            message = message.ToLower();
            if (message == "buy")
            {
                Trade.SendMessage("You have chosen to buy weapons! Please type part of the weapon's name into the trade chat and I will try to find that weapon for you.");
                Trade.SendMessage("To tell the bot to remove an item, type \"/remove\" first and hit enter, and then type the item name. For help, type \"help\".");
                Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "You have decided to buy weapons. Check my backpack at to see what I have! Remember the time limit, so make it quick!");
                buyWeapons = true;
            }

            else if (message.Contains("add all") || message == ".addall")
            {
                if (IsAdmin)
                {
                    AddAllItems();
                }
                else
                {
                    Trade.SendMessage("You are not an admin, you may not access this command.");
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "You are not an admin, you may not access this command.");
                    Bot.Log.Admin(Bot.SteamFriends.GetFriendPersonaName(OtherSID) + " (" + OtherSID.ConvertToUInt64() + ") tried to accessed the add metal command.");
                }
            }

            else if (message.Contains("add metal") || message == ".addmetal")
            {
                if (IsAdmin)
                {
                    AddAllMetal();
                }
                else
                {
                    Trade.SendMessage("You are not an admin, you may not access this command.");
                    Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "You are not an admin, you may not access this command.");
                    Bot.Log.Admin(Bot.SteamFriends.GetFriendPersonaName(OtherSID) + " (" + OtherSID.ConvertToUInt64() + ") tried to accessed the add metal command.");
                }
            }

            // Give user help
            else if (message == "help")
            {
                Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "If you are selling weapons, simply add 2 weapons and the bot will automatically add 1 scrap.");
                Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "If you want to buy weapons, first you must type \"buy\" and then type in what weapon you want. ");
            }
            else if (buyWeapons)
            {
                if (message.Length >= 7 && message.Substring(0, 7) == "/remove")
                {
                    remove = true;
                    Trade.SendMessage("MODE: Remove items. To exit this mode type \"/add\".");
                }
                else if (message.Length >= 4 && message.Substring(0, 4) == "/add")
                {
                    remove = false;
                    Trade.SendMessage("MODE: Add items.");
                }
                else
                {
                    string[] splitmessage = message.Split(',');
                    Inventory.Item[] myitems = Trade.MyInventory.Items;
                    foreach (string weaponName in splitmessage)
                    {
                        int closestdefindex = FindClosestDefindexInInventory(myitems, weaponName);
                        if (closestdefindex == -1)
                        {
                            Trade.SendMessage("I can't find anything that sounds like " + weaponName);
                            Bot.Log.Warn("They asked for something I don't have.");
                        }
                        else
                        {
                            if (remove)
                            {
                                if (Trade.RemoveItemByDefindex(closestdefindex) != false)
                                {
                                    Bot.Log.Warn("They asked to remove " + weaponName + " and I found " + Trade.CurrentSchema.GetItem(closestdefindex).ItemName + " to be the closest match! Removing it now...");
                                    Trade.SendMessage("The closest thing I have to " + weaponName + " is a " + Trade.CurrentSchema.GetItem(closestdefindex).ItemName);
                                    botWepAdded--;
                                    Bot.Log.Warn("I am offering them " + botWepAdded + " weapons and " + botScrapAdded + " scrap.");
                                }
                                else
                                {
                                    Trade.SendMessage("I couldn't find the item to remove!");
                                }
                            }
                            else
                            {
                                if (Trade.AddItemByDefindex(closestdefindex) != false)
                                {
                                    Bot.Log.Warn("They asked for a " + weaponName + " and I found " + Trade.CurrentSchema.GetItem(closestdefindex).ItemName + " to be the closest match! Adding it now.");
                                    Trade.SendMessage("The closest thing I have to " + weaponName + " is a " + Trade.CurrentSchema.GetItem(closestdefindex).ItemName);
                                    botWepAdded++;
                                    Bot.Log.Warn("I am offering them " + botWepAdded + " weapons and " + botScrapAdded + " scrap.");
                                }
                                else
                                {
                                    Trade.SendMessage("Something went wrong or my only \"" + weaponName + "\" is already being offered.");
                                }
                            }
                        }
                    }
                }
            }
        }

        // When user is ready, validate trade and accept/decline accordingly
        public override void OnTradeReady(bool ready)
        {
            if (!ready)
            {
                Trade.SetReady(false);
                Bot.Log.Trade("Unreadied trade.");
            }
            else
            {
                if (Validate())
                {
                    Trade.SetReady(true);
                }
                Bot.Log.Success("User is ready to trade!");
            }
        }

        // Trade completed successfully
        public override void OnTradeSuccess()
        {
            Bot.SteamFriends.SetPersonaState(EPersonaState.LookingToTrade);
            Log.Success("Trade Complete.");
            if (!Group.isMember(OtherSID))
            {
                Bot.InviteUserToGroup(OtherSID, 103582791435642512);
                Bot.Log.Success("Invited " + Bot.SteamFriends.GetFriendPersonaName(OtherSID) + " to 'Tradr'");
            }
        }

        public override void OnTradeAwaitingConfirmation(long tradeOfferID)
        {
            Log.Warn("Trade ended awaiting email confirmation");
            SendChatMessage("Please complete the email confirmation to finish the trade");
        }

        // On trade accept, if is admin or validated; accept
        public override void OnTradeAccept()
        {
            if (Validate() || IsAdmin)
            {
                bool success = Trade.AcceptTrade();
                if (success)
                {
                    LuckyCat();
                    if (IsAdmin)
                    {
                        Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "Master, you have fed me once more.");
                    }
                    else
                    {
                        Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "Thank you, come again.");
                    }
                    Log.Success("Trade was successful!");
                }
                else
                {
                    Log.Warn("Trade might have failed.");
                }
            }
            OnTradeClose();
        }

        // When trade closes, set state to "looking to trade"
        // If backpack has less than 9 scrap, smelt refined/reclaimed to get more scrap
        public override void OnTradeClose()
        {
            bool madeReclaimed = false;
            if (inventoryScrap < 9)
            {
                ulong[] smelt = new ulong[1];
                Bot.SetGamePlaying(440);
                Bot.GetInventory();
                Inventory myInventory = Bot.MyInventory;
                foreach (Inventory.Item item in myInventory.Items)
                {
                    if (item.Defindex == 5001)
                    {
                        smelt[0] = item.Id;
                        SteamBot.TF2GC.Crafting.CraftItems(Bot, smelt);
                        madeReclaimed = true;
                        break;
                    }
                }
                if (!madeReclaimed)
                {
                    foreach (Inventory.Item item in Trade.MyInventory.Items)
                    {
                        if (item.Defindex == 5002)
                        {
                            smelt[0] = item.Id;
                            SteamBot.TF2GC.Crafting.CraftItems(Bot, smelt);
                            madeReclaimed = true;
                            if (item.Defindex == 5001)
                            {
                                smelt[0] = item.Id;
                                SteamBot.TF2GC.Crafting.CraftItems(Bot, smelt);
                                madeReclaimed = true;
                                break;
                            }
                        }
                    }
                }
            }
            LuckyCat();
            Bot.SetGamePlaying(0);
            Bot.SteamFriends.SetPersonaState(EPersonaState.LookingToTrade);
        }

        // Checks if trade is valid
        public bool Validate()
        {
            ScrapPutUp = 0;

            List<string> errors = new List<string>();

            foreach (TradeUserAssets asset in Trade.OtherOfferedItems)
            {
                var item = Trade.OtherInventory.GetItem(asset.assetid);
                if (item.Defindex == 5000)
                    ScrapPutUp++;
                else if (item.Defindex == 5001)
                    ScrapPutUp += 3;
                else if (item.Defindex == 5002)
                    ScrapPutUp += 9;
            }

            if (invalidItem > 0)
            {
                errors.Add("You have given me invalid items! Please remove them!");
                Bot.Log.Warn("User has invalid items put up!");
            }
            if (ScrapPutUp != (float)botWepAdded / 2 && botWepAdded > 0)
            {
                errors.Add("You've added the wrong amount of scrap!");
                Bot.Log.Warn("User has added the wrong amount of scrap!");
            }
            if (botScrapAdded != (float)userWepAdded / 2 && botScrapAdded > 0)
            {
                errors.Add("The amount of weapons you've added isn't right!");
                Bot.Log.Warn("User has added the wrong amount of weapons!");
            }

            // send the errors
            if (errors.Count != 0)
                Trade.SendMessage("There were errors in your trade: ");

            foreach (string error in errors)
            {
                Trade.SendMessage(error);
            }

            return errors.Count == 0;
        }
        public void TradeCountInventory()
        {
            Bot.GetInventory();
            // Let's count our inventory
            Inventory.Item[] inventory = Bot.MyInventory.Items;
            inventoryWeapon = 0;
            inventoryMetal = 0;
            inventoryKeys = 0;
            inventoryRef = 0;
            inventoryRec = 0;
            inventoryScrap = 0;
            giftWrap = 0;
            duelingGame = 0;
            decalTool = 0;
            backpackExpander = 0;
            foreach (var item in Bot.MyInventory.Items)
            {
                var schemaItem = Trade.CurrentSchema.GetItem(item.Defindex);
                if (schemaItem.ItemQuality == 6 && schemaItem.CraftClass == "weapon" && !item.IsNotCraftable)
                {
                    inventoryWeapon++;
                }
                else if (item.Defindex == 5000)
                {
                    inventoryMetal++;
                    inventoryScrap++;
                }
                else if (item.Defindex == 5001)
                {
                    inventoryMetal += 3;
                    inventoryRec++;
                }
                else if (item.Defindex == 5002)
                {
                    inventoryMetal += 9;
                    inventoryRef++;
                }
                else if (item.Defindex == 5050)
                {
                    backpackExpander++;
                }
                else if (item.Defindex == 5026)
                {
                    decalTool++;
                }
                else if (item.Defindex == 5042)
                {
                    giftWrap++;
                }
                else if (item.Defindex == 5082)
                {
                    duelingGame++;
                }
                else if (schemaItem.ItemName == "Mann Co. Supply Crate Key" || schemaItem.ItemName == "#TF_Tool_DecoderRing")
                {
                    inventoryKeys++;
                }
            }
            double MetalToRef = (inventoryMetal / 9.0) - 0.01;
            string TotalMetal = string.Format("{0:N2}", MetalToRef);
            Trade.SendMessage("Metal Stock: I have " + TotalMetal + " Refined (" + inventoryRef + " refined, " + inventoryRec + " reclaimed, " + inventoryScrap + " scrap) in my backpack.");
            Trade.SendMessage("I can afford to buy " + inventoryScrap * 2 + " weapons.");
            Trade.SendMessage("Weapon stock: I have " + inventoryWeapon + " weapons");
            Bot.Log.Success("Metal stock: I have " + TotalMetal + " Refined (" + inventoryRef + " refined, " + inventoryRec + " reclaimed, " + inventoryScrap + " scrap) in my backpack.");
            Bot.Log.Success("I can afford to buy " + inventoryScrap * 2 + " weapons.");
            Bot.Log.Success("Weapon stock: I have " + inventoryWeapon + " weapons");
            HasCounted = true;
        }

        public void ReInit()
        {
            userScrapAdded = 0;
            userWepAdded = 0;
            botScrapAdded = 0;
            botWepAdded = 0;
            inventoryWeapon = 0;
            inventoryMetal = 0;
            inventoryKeys = 0;
            inventoryRef = 0;
            inventoryRec = 0;
            inventoryScrap = 0;
            giftWrap = 0;
            duelingGame = 0;
            decalTool = 0;
            backpackExpander = 0;
            invalidItem = 0;
            errorMsgRun = false;
            buyWeapons = false;
            remove = false;
            currentSID = OtherSID;
        }

        private void OnInviteTimerElapsed(object source, ElapsedEventArgs e, EChatEntryType type)
        {
            Bot.SteamFriends.SendChatMessage(OtherSID, EChatEntryType.ChatMsg, "Hi. You have added Mattr's personal bot! Welcome to my personal project, feel free to send a trade request or snoop around");
            Bot.Log.Success("Welcome message sent to Username:" + Bot.SteamFriends.GetFriendPersonaName(OtherSID) + " (" + OtherSID.ConvertToUInt64() + ")");
            inviteMsgTimer.Enabled = false;
            inviteMsgTimer.Stop();
        }

        public int FindClosestDefindexInInventory(Inventory.Item[] inventory, string word)
        {
            if (word.Length < 4)
            {
                Trade.SendMessage("You need to give me more of the weapon's name!");
                return -1;
            }
            Dictionary<string, int> inventorydict = new Dictionary<string, int>();
            foreach (Inventory.Item item in inventory)
            {
                if (inventorydict.ContainsKey(Trade.CurrentSchema.GetItem(item.Defindex).ItemName.ToLower()) == false && (Trade.CurrentSchema.GetItem(item.Defindex).CraftClass == "weapon" || Trade.CurrentSchema.GetItem(item.Defindex).CraftMaterialType == "weapon"))
                {
                    inventorydict.Add(Trade.CurrentSchema.GetItem(item.Defindex).ItemName.ToLower(), item.Defindex);
                }
            }
            int closestindex = -1;
            int closestdistance = 0;
            int count = 0;
            foreach (string key in inventorydict.Keys)
            {
                int c = LevDistance(key, word);
                if (c < closestdistance || closestindex == -1)
                {
                    closestdistance = c;
                    closestindex = inventorydict[key];
                    count = 1;
                }
                else if (c == closestdistance)
                {
                    count += 1;
                }
                if (key.Contains(word))
                {
                    return inventorydict[key];
                }

            }
            if (count > 1)
            {
                return -1;
            }
            return closestindex;
        }

        public static int LevDistance(string s, string t)
        {
            int n = s.Length;
            int m = t.Length;
            int[,] d = new int[n + 1, m + 1];

            // Step 1
            if (n == 0)
            {
                return m;
            }

            if (m == 0)
            {
                return n;
            }

            // Step 2
            for (int i = 0; i <= n; d[i, 0] = i++)
            {
            }

            for (int j = 0; j <= m; d[0, j] = j++)
            {
            }

            // Step 3
            for (int i = 1; i <= n; i++)
            {
                //Step 4
                for (int j = 1; j <= m; j++)
                {
                    // Step 5
                    int cost = (t[j - 1] == s[i - 1]) ? 0 : 1;

                    // Step 6
                    d[i, j] = Math.Min(
                        Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1),
                        d[i - 1, j - 1] + cost);
                }
            }
            // Step 7
            return d[n, m];
        }

        #region Crafting
        // A little rough around the edges.

        /// <summary>
        /// Crafts an array of items.
        /// </summary>
        public void Craft(Inventory.Item[] CraftItems)
        {
            ulong[] CraftIds = new ulong[CraftItems.Length];
            Bot.Log.Info("Crafting " + CraftItems.Length + " items.");

            int index = 0;
            foreach (Inventory.Item item in CraftItems)
            {
                CraftIds[index] = item.Id;
                Bot.Log.Debug("Crafting Item ID: " + item.Id);
                index++;
            }

            TF2GC.Crafting.CraftItems(Bot, CraftIds);

            // Give time for callbacks to update, otherwise backpack may not be up-to-date
            // after a large amount of crafting. Sleep may be moved elsewhere to allow for
            // fast crafting when inventory refresh isn't required.
            Thread.Sleep(100);
        }

        /// <summary>
        /// Crafts all clean, unique weapons to ref (doesn't check for item duplicates or anything too fancy yet)
        /// Also calls GetInventory() so it's not necessary prior
        /// </summary>
        /// <returns>false if there were no weapons to craft otherwise, true</returns>
        public bool AutoCraftAll()
        {
            Bot.Log.Craft("AutoCrafting Weapons");

            // Will hold all craftable/tradable weapons
            List<Inventory.Item> MyCleanWeapons = new List<Inventory.Item>();

            Bot.Log.Debug("Getting Inventory");
            Bot.GetInventory();

            MyCleanWeapons = GetCleanItemsOfMaterial("weapon");
            Bot.Log.Craft("Number of weapons to craft: " + MyCleanWeapons.Count);
            if (MyCleanWeapons.Count < 2)
            {
                Bot.Log.Warn("There are not enough weapons to craft");
                return false;
            }

            Bot.Log.Info("Setting Game State to Playing TF2.");
            Bot.SetGamePlaying(440);

            int ScrapMade = ScrapWeapons(MyCleanWeapons);
            Bot.Log.Craft("Scrap made: " + ScrapMade);

            Bot.Log.Craft("Combining Metal");
            CombineAllMetal();

            Bot.Log.Info("Resetting Game State");
            Bot.SetGamePlaying(0);
            Bot.Log.Craft("Crafting Complete");
            return true;
        }

        /// <summary>
        /// Scraps a List of Weapons into scrap.
        /// </summary>
        /// <param name="CleanWeapons">List of all weapons to scrap.</param>
        /// <returns>Number of scrap made.</returns>
        public int ScrapWeapons(List<Inventory.Item> CleanWeapons)
        {
            if (Bot.CurrentGame != 440)
            {
                Bot.SetGamePlaying(440);
            }

            Bot.Log.Info("Sorting items by class.");
            List<List<Inventory.Item>> allWeapons = SortItemsByClass(CleanWeapons);

            List<Inventory.Item> multiWeps = allWeapons[9];

            // Separate the multi-class weapons again because it's so special
            allWeapons.RemoveAt(9);

            Inventory.Item[] CraftItems;
            int scrapMade = 0;
            Bot.Log.Info("Beginning smelt sequence.");

            // Crafting off pairs of weapons in class lists
            foreach (List<Inventory.Item> list in allWeapons)
            {
                while (list.Count > 1)
                {
                    CraftItems = new Inventory.Item[2];
                    CraftItems[0] = list[0];
                    list.RemoveAt(0);
                    CraftItems[1] = list[0];
                    list.RemoveAt(0);
                    Craft(CraftItems);
                    scrapMade++;
                }
            }

            //(Still needs to be optimised) Crafting the remaining multi-class weapons
            Bot.Log.Info("Scrapping multi-class weps");
            foreach (List<Inventory.Item> list in allWeapons)
            {
                CraftItems = new Inventory.Item[2];
                if (list.Count > 0)
                {
                    foreach (Inventory.Item item in multiWeps)
                    {
                        List<string> classes = new List<string>(Trade.CurrentSchema.GetItem(item.Defindex).UsableByClasses);
                        string[] itemClass = Trade.CurrentSchema.GetItem(list[0].Defindex).UsableByClasses;
                        if (classes.Contains(itemClass[0]))
                        {
                            CraftItems[0] = item;
                            // I can remove items from this for each because I'm going to break anyway
                            multiWeps.Remove(item);
                            CraftItems[1] = list[0];
                            list.RemoveAt(0);
                            Craft(CraftItems);
                            scrapMade++;
                            break;
                        }
                    }
                }
            }
            // Clean up any leftover
            while (multiWeps.Count > 1)
            {
                CraftItems = new Inventory.Item[2];
                CraftItems[0] = multiWeps[0];
                multiWeps.RemoveAt(0);
                CraftItems[1] = multiWeps[0];
                multiWeps.RemoveAt(0);
                Craft(CraftItems);
                scrapMade++;
            }
            return scrapMade;
        }

        /// <summary>
        /// Crafts all scrap into reclaimed, then all reclaimed into refined.
        /// </summary>
        public void CombineAllMetal()
        {
            if (Bot.CurrentGame != 440)
            {
                Bot.SetGamePlaying(440);
            }
            // May use for inventory management
            //List<Inventory.Item> myScrap = new List<Inventory.Item>();
            //List<Inventory.Item> myReclaimed = new List<Inventory.Item>();
            //List<Inventory.Item> myRefined = new List<Inventory.Item>();

            Bot.Log.Info("Combining all metal");

            // Scrap, Reclaimed, and Refined are def index 5000, 5001, 5002 respectively

            List<Inventory.Item> ScrapToCraft = new List<Inventory.Item>();

            Bot.Log.Debug("Getting Inventory");
            Thread.Sleep(300); // Just another pause to be sure inventory has updated.
            Bot.GetInventory();

            ScrapToCraft = Bot.MyInventory.GetItemsByDefindex(5000);

            Bot.Log.Debug("Total Scrap: " + ScrapToCraft.Count);
            Bot.Log.Debug("Crafting " + (ScrapToCraft.Count / 3) + " Reclaimed.");

            while (ScrapToCraft.Count > 2)
            {
                Inventory.Item[] CraftItems = new Inventory.Item[3];
                CraftItems[0] = ScrapToCraft[0];
                CraftItems[1] = ScrapToCraft[1];
                CraftItems[2] = ScrapToCraft[2];
                Craft(CraftItems);
                for (int x = 0; x < 3; x++)
                {
                    ScrapToCraft.RemoveAt(0);
                }
            }

            List<Inventory.Item> ReclaimedToCraft = new List<Inventory.Item>();

            Bot.Log.Debug("Getting Inventory");
            Thread.Sleep(300); // Just another pause to be sure inventory has updated.
            Bot.GetInventory();

            ReclaimedToCraft = Bot.MyInventory.GetItemsByDefindex(5001);

            Bot.Log.Debug("Total Reclaimed: " + ReclaimedToCraft.Count);
            Bot.Log.Debug("Crafting " + (ReclaimedToCraft.Count / 3) + " Refined.");

            while (ReclaimedToCraft.Count > 2)
            {
                Inventory.Item[] craftIds = new Inventory.Item[3];
                craftIds[0] = ReclaimedToCraft[0];
                craftIds[1] = ReclaimedToCraft[1];
                craftIds[2] = ReclaimedToCraft[2];
                Craft(craftIds);
                for (int x = 0; x < 3; x++)
                {
                    ReclaimedToCraft.RemoveAt(0);
                }
            }
        }

        /// <summary>
        /// Gets all unique, craftable, and tradable items of the specified crafting material
        /// </summary>
        /// <param name="CraftingMaterial">CraftingMaterial from schema</param>
        /// <returns>List of items in inventory that are craftable, tradable, and match
        /// the crafting material.</returns>
        public List<Inventory.Item> GetCleanItemsOfMaterial(string CraftingMaterial)
        {
            Bot.Log.Debug("Getting list of craftable weapons from schema");
            var CraftableItemList = Trade.CurrentSchema.GetItemsByCraftingMaterial(CraftingMaterial);
            var myItems = new List<Inventory.Item>();

            foreach (Inventory.Item invItem in Bot.MyInventory.Items)
            {
                if (!invItem.IsNotTradeable && !invItem.IsNotCraftable && invItem.Quality.Equals(6))
                {
                    foreach (Schema.Item scItem in CraftableItemList)
                    {
                        if (invItem.Defindex == scItem.Defindex)
                        {
                            myItems.Add(invItem);
                            break;
                        }
                    }
                }
            }
            return myItems;
        }

        /// <summary>
        /// Sorts items based on which of the 9 classes can use them
        /// </summary>
        /// <param name="items">List of items to sort</param>
        /// <returns>Lists of Lists of all the weapons in appropriate class lists, the 10th
        /// list is for multi-class weapons.</returns>
        public List<List<Inventory.Item>> SortItemsByClass(List<Inventory.Item> items)
        {
            // List for each class' weps
            List<Inventory.Item> scoutWeps = new List<Inventory.Item>();
            List<Inventory.Item> soldierWeps = new List<Inventory.Item>();
            List<Inventory.Item> pyroWeps = new List<Inventory.Item>();
            List<Inventory.Item> demoWeps = new List<Inventory.Item>();
            List<Inventory.Item> heavyWeps = new List<Inventory.Item>();
            List<Inventory.Item> engyWeps = new List<Inventory.Item>();
            List<Inventory.Item> medicWeps = new List<Inventory.Item>();
            List<Inventory.Item> sniperWeps = new List<Inventory.Item>();
            List<Inventory.Item> spyWeps = new List<Inventory.Item>();
            List<Inventory.Item> multiWeps = new List<Inventory.Item>();

            // List of the above lists
            List<List<Inventory.Item>> allWeps = new List<List<Inventory.Item>>(10);

            allWeps.Add(scoutWeps);
            allWeps.Add(soldierWeps);
            allWeps.Add(pyroWeps);
            allWeps.Add(demoWeps);
            allWeps.Add(heavyWeps);
            allWeps.Add(engyWeps);
            allWeps.Add(medicWeps);
            allWeps.Add(sniperWeps);
            allWeps.Add(spyWeps);

            foreach (Inventory.Item item in items)
            {
                var classes = Trade.CurrentSchema.GetItem(item.Defindex).UsableByClasses;
                if (classes.Length > 1)
                {
                    multiWeps.Add(item);
                }
                else
                    switch (classes[0])
                    {
                        case ("Scout"): scoutWeps.Add(item); break;
                        case ("Soldier"): soldierWeps.Add(item); break;
                        case ("Pyro"): pyroWeps.Add(item); break;
                        case ("Demoman"): demoWeps.Add(item); break;
                        case ("Heavy"): heavyWeps.Add(item); break;
                        case ("Engineer"): engyWeps.Add(item); break;
                        case ("Medic"): medicWeps.Add(item); break;
                        case ("Sniper"): sniperWeps.Add(item); break;
                        case ("Spy"): spyWeps.Add(item); break;
                        default: Bot.Log.Debug("what happened? 10th class? idk"); break;
                    }
            }
            Bot.Log.Debug("Number of...");
            Bot.Log.Debug("Scout items: " + scoutWeps.Count);
            Bot.Log.Debug("Soldier items: " + soldierWeps.Count);
            Bot.Log.Debug("Pyro items: " + pyroWeps.Count);
            Bot.Log.Debug("Demoman items: " + demoWeps.Count);
            Bot.Log.Debug("Heavy items: " + heavyWeps.Count);
            Bot.Log.Debug("Engineer items: " + engyWeps.Count);
            Bot.Log.Debug("Medic items: " + medicWeps.Count);
            Bot.Log.Debug("Sniper items: " + sniperWeps.Count);
            Bot.Log.Debug("Spy items: " + spyWeps.Count);
            Bot.Log.Debug("Multi-class items (pain train + half-zatoichi): " + multiWeps.Count);

            // Add multiWeps back to return allWeps
            allWeps.Add(multiWeps);

            return allWeps;
        }

        #endregion

    }
}