using System;
using System.Text;
using System.Data;
using System.Threading;
using System.Reflection;
using System.Data.SqlClient;
using System.Collections.Generic;

using FilterAPI;

using CS;
using SHN;

namespace FilterGameLogMonitor
{
    internal class Program
    {
        public static String ServiceName = "Game Log Monitor";

        public static Authentication Auth;
        public static Database SQL;

        public static SHNFile ItemInfo;
        public static SHNFile MobInfo;
        public static SHNFile ActiveSkill;

        private static Dictionary<Int32, String> ItemNames = new Dictionary<Int32, String>();
        private static Dictionary<Int32, String> MobNames = new Dictionary<Int32, String>();
        private static Dictionary<Int32, String> SkillNames = new Dictionary<Int32, String>();

        private static Boolean IsDone = true;

        private static Int64 nLogNo;

        private static void Main()
        {
            Auth = new Authentication();
            SQL = new Database(Auth);

            Console.Title = String.Format("{0} Filter [Game Log Monitor] :: Aeris.NET :: 2017/2018", Auth.ConfigValues["ServerName"]);

            nLogNo = Convert.ToInt64(Program.SQL.GetValue(Program.Auth.ConfigValues["GameLogDB"], "tGameLog", "nLogNo"));

            LoadSHNs();

            foreach (DataRow Row in ItemInfo.Table.Rows)
            {
                if (!ItemNames.ContainsKey(Convert.ToInt32(Row[0]))) { ItemNames.Add(Convert.ToInt32(Row[0]), Convert.ToString(Row[2])); }
            }

            foreach (DataRow Row in MobInfo.Table.Rows)
            {
                if (!MobNames.ContainsKey(Convert.ToInt32(Row[0]))) { MobNames.Add(Convert.ToInt32(Row[0]), Convert.ToString(Row[2])); }
            }

            foreach (DataRow Row in ActiveSkill.Table.Rows)
            {
                if (!SkillNames.ContainsKey(Convert.ToInt32(Row[0]))) { SkillNames.Add(Convert.ToInt32(Row[0]), Convert.ToString(Row[2])); }
            }

            Thread NewThread = new Thread(delegate ()
            {
                while (true)
                {
                    if (IsDone) { Run(); }

                    Thread.Sleep(5000);
                }
            });

            NewThread.Start();

            Console.ReadLine();
        }

        public static void LoadSHNs()
        {
            MethodInfo CryptoMethod = CSFile.LoadCode(Auth.ConfigValues["SHNCryptoFile"], "SHN.SHNCrypto", Auth.ConfigValues["SHNCryptoName"]);

            ItemInfo = new SHNFile(String.Format("{0}ItemInfo.shn", Auth.ConfigValues["ServerSHNPath"]), CryptoMethod);

            if (ItemInfo.Type == SHNType.TextData) { ItemInfo.SHNEncoding = Encoding.ASCII; }
            else { ItemInfo.SHNEncoding = Encoding.GetEncoding("ISO-8859-1"); }

            if (ItemInfo.Type != SHNType.QuestData) { ItemInfo.Read(); }
            else { ItemInfo.ReadQuest(); }

            ItemInfo.DisallowRowChanges();

            MobInfo = new SHNFile(String.Format("{0}MobInfo.shn", Auth.ConfigValues["ServerSHNPath"]), CryptoMethod);

            if (MobInfo.Type == SHNType.TextData) { MobInfo.SHNEncoding = Encoding.ASCII; }
            else { MobInfo.SHNEncoding = Encoding.GetEncoding("ISO-8859-1"); }

            if (MobInfo.Type != SHNType.QuestData) { MobInfo.Read(); }
            else { MobInfo.ReadQuest(); }

            MobInfo.DisallowRowChanges();

            ActiveSkill = new SHNFile(String.Format("{0}ActiveSkill.shn", Auth.ConfigValues["ServerSHNPath"]), CryptoMethod);

            if (ActiveSkill.Type == SHNType.TextData) { ActiveSkill.SHNEncoding = Encoding.ASCII; }
            else { ActiveSkill.SHNEncoding = Encoding.GetEncoding("ISO-8859-1"); }

            if (ActiveSkill.Type != SHNType.QuestData) { ActiveSkill.Read(); }
            else { ActiveSkill.ReadQuest(); }

            ActiveSkill.DisallowRowChanges();
        }

        private static void Run()
        {
            IsDone = false;

            using (SqlCommand Command = SQL.Connection.CreateCommand())
            {
                Dictionary<Int32, String> CharacterNames = new Dictionary<Int32, String>();

                Command.CommandText = String.Format("SELECT nCharNo, sID FROM {0}..tCharacter", Program.Auth.ConfigValues["CharacterDB"]);

                using (var Reader = Command.ExecuteReader())
                {
                    while (Reader.Read())
                    {
                        if (!CharacterNames.ContainsKey(Convert.ToInt32(Reader["nCharNo"]))) { CharacterNames.Add(Convert.ToInt32(Reader["nCharNo"]), Convert.ToString(Reader["sID"])); }
                    }

                    Reader.Close();
                }

                Command.CommandText = String.Format("SELECT * FROM {0}..tGameLog WHERE nLogNo > {1}", Program.Auth.ConfigValues["GameLogDB"], nLogNo);

                using (SqlDataReader Reader = Command.ExecuteReader())
                {
                    while (Reader.Read())
                    {
                        try
                        {
                            switch (Convert.ToInt32(Reader["nType"]))
                            {
                                case 10:
                                    {
                                        Console.ForegroundColor = ConsoleColor.Green;
                                        Console.WriteLine(String.Format("[{0}] :: {1} Logged in.", Convert.ToDateTime(Reader["dDate"]).ToString("MM/dd/yyyy || HH:mm"), CharacterNames[Convert.ToInt32(Reader["nCharNo"])]));

                                        break;
                                    }
                                case 11:
                                    {
                                        Console.ForegroundColor = ConsoleColor.Red;
                                        Console.WriteLine(String.Format("[{0}] :: {1} Logged out.", Convert.ToDateTime(Reader["dDate"]).ToString("MM/dd/yyyy || HH:mm"), CharacterNames[Convert.ToInt32(Reader["nCharNo"])]));

                                        break;
                                    }
                                case 15:
                                    {
                                        Console.ForegroundColor = ConsoleColor.Magenta;
                                        Console.WriteLine(String.Format("[{0}] :: {1} went to {2}. X: {3}. Y: {4}.", Convert.ToDateTime(Reader["dDate"]).ToString("MM/dd/yyyy || HH:mm"), CharacterNames[Convert.ToInt32(Reader["nCharNo"])], Reader["sMap"], Reader["nMapX"], Reader["nMapY"]));

                                        break;
                                    }
                                case 17:
                                    {
                                        Console.ForegroundColor = ConsoleColor.Magenta;
                                        Console.WriteLine(String.Format("[{0}] :: {1} was created.", Convert.ToDateTime(Reader["dDate"]).ToString("MM/dd/yyyy || HH:mm"), CharacterNames[Convert.ToInt32(Reader["nCharNo"])]));

                                        break;
                                    }
                                case 18:
                                    {
                                        Console.ForegroundColor = ConsoleColor.Magenta;
                                        Console.WriteLine(String.Format("[{0}] :: {1} was deleted.", Convert.ToDateTime(Reader["dDate"]).ToString("MM/dd/yyyy || HH:mm"), CharacterNames[Convert.ToInt32(Reader["nCharNo"])]));

                                        break;
                                    }
                                case 30:
                                    {
                                        Console.ForegroundColor = ConsoleColor.Magenta;
                                        Console.WriteLine(String.Format("[{0}] :: {1} leveled up to {2}.", Convert.ToDateTime(Reader["dDate"]).ToString("MM/dd/yyyy || HH:mm"), CharacterNames[Convert.ToInt32(Reader["nCharNo"])], Reader["nInt1"]));

                                        break;
                                    }
                                case 41:
                                    {
                                        Console.ForegroundColor = ConsoleColor.Magenta;
                                        Console.WriteLine(String.Format("[{0}] :: {1} killed {2} at {3}. X: {4}. Y: {5}.", Convert.ToDateTime(Reader["dDate"]).ToString("MM/dd/yyyy || HH:mm"), CharacterNames[Convert.ToInt32(Reader["nCharNo"])], CharacterNames[(Convert.ToInt32(Reader["nTargetCharNo"]))], Reader["sMap"], Reader["nMapX"], Reader["nMapY"]));

                                        break;
                                    }
                                case 50:
                                    {
                                        Console.ForegroundColor = ConsoleColor.Magenta;
                                        Console.WriteLine(String.Format("[{0}] :: {1} learned skill {2}.", Convert.ToDateTime(Reader["dDate"]).ToString("MM/dd/yyyy || HH:mm"), CharacterNames[Convert.ToInt32(Reader["nCharNo"])], SkillNames[Convert.ToInt32(Reader["nInt1"])]));

                                        break;
                                    }
                                case 74:
                                    {
                                        Console.ForegroundColor = ConsoleColor.Cyan;
                                        Console.WriteLine(String.Format("[{0}] :: {1} traded {2} ({3}) to {4}. Amount: {5}.", Convert.ToDateTime(Reader["dDate"]).ToString("MM/dd/yyyy || HH:mm"), CharacterNames[Convert.ToInt32(Reader["nCharNo"])], ItemNames[Convert.ToInt32(Reader["nTargetID"])], Reader["nItemKey"], CharacterNames[(Convert.ToInt32(Reader["nTargetCharNo"]))], Reader["nInt1"]));

                                        break;
                                    }
                                case 82:
                                    {
                                        Console.ForegroundColor = ConsoleColor.Magenta;
                                        Console.WriteLine(String.Format("[{0}] :: {1} enchanted {2} by {3}. Old enchant level: {4}. New enchant level: {5}.", Convert.ToDateTime(Reader["dDate"]).ToString("MM/dd/yyyy || HH:mm"), CharacterNames[Convert.ToInt32(Reader["nCharNo"])], Reader["nItemKey"], Convert.ToInt32(Reader["nInt2"]) - Convert.ToInt32(Reader["nInt1"]), Convert.ToInt32(Reader["nInt1"]), Convert.ToInt32(Reader["nInt2"])));

                                        break;
                                    }
                                case 87:
                                    {
                                        Console.ForegroundColor = ConsoleColor.Cyan;
                                        Console.WriteLine(String.Format("[{0}] :: {1} took {2} from {3} ({4}). New stack amount: {5}. New item key: {6}.", Convert.ToDateTime(Reader["dDate"]).ToString("MM/dd/yyyy || HH:mm"), CharacterNames[Convert.ToInt32(Reader["nCharNo"])], Convert.ToInt32(Reader["nInt2"]), ItemNames[Convert.ToInt32(Reader["nTargetID"])], Reader["nItemKey"], Reader["nInt1"], Reader["nBigint1"]));

                                        break;
                                    }
                                case 89:
                                    {
                                        Console.ForegroundColor = ConsoleColor.Cyan;
                                        Console.WriteLine(String.Format("[{0}] :: {1} used {2} ({3}). Left with: {4}.", Convert.ToDateTime(Reader["dDate"]).ToString("MM/dd/yyyy || HH:mm"), CharacterNames[Convert.ToInt32(Reader["nCharNo"])], ItemNames[Convert.ToInt32(Reader["nInt1"])], Reader["nItemKey"], Reader["nInt2"]));

                                        break;
                                    }
                                case 91:
                                    {
                                        Console.ForegroundColor = ConsoleColor.Cyan;
                                        Console.WriteLine(String.Format("[{0}] :: {1} bought {2} ({3}) from {4}. Amount: {5}. Price: {6}. New balance: {7}.", Convert.ToDateTime(Reader["dDate"]).ToString("MM/dd/yyyy || HH:mm"), CharacterNames[Convert.ToInt32(Reader["nCharNo"])], ItemNames[Convert.ToInt32(Reader["nTargetID"])], Reader["nItemKey"], CharacterNames[Convert.ToInt32(Reader["nTargetCharNo"])], Reader["nInt1"], Reader["nInt2"], Reader["nBigint1"]));

                                        break;
                                    }
                                case 92:
                                    {
                                        Console.ForegroundColor = ConsoleColor.Cyan;
                                        Console.WriteLine(String.Format("[{0}] :: {1} sold {2} ({3}) to {4}. Amount: {5}. Price: {6}. New balance: {7}.", Convert.ToDateTime(Reader["dDate"]).ToString("MM/dd/yyyy || HH:mm"), CharacterNames[Convert.ToInt32(Reader["nCharNo"])], ItemNames[Convert.ToInt32(Reader["nTargetID"])], Reader["nItemKey"], CharacterNames[Convert.ToInt32(Reader["nTargetCharNo"])], Reader["nInt1"], Reader["nInt2"], Reader["nBigint1"]));

                                        break;
                                    }
                                case 94:
                                    {
                                        Console.ForegroundColor = ConsoleColor.Cyan;
                                        Console.WriteLine(String.Format("[{0}] :: {1} despoited {2} into storage. New balance: {3}.", Convert.ToDateTime(Reader["dDate"]).ToString("MM/dd/yyyy || HH:mm"), CharacterNames[Convert.ToInt32(Reader["nCharNo"])], Reader["nInt1"], Reader["nBigint1"]));

                                        break;
                                    }
                                case 95:
                                    {
                                        Console.ForegroundColor = ConsoleColor.Cyan;
                                        Console.WriteLine(String.Format("[{0}] :: {1} withdrew {2} from storage. New balance: {3}.", Convert.ToDateTime(Reader["dDate"]).ToString("MM/dd/yyyy || HH:mm"), CharacterNames[Convert.ToInt32(Reader["nCharNo"])], Reader["nInt1"], Reader["nBigint1"]));

                                        break;
                                    }
                                case 96:
                                    {
                                        Console.ForegroundColor = ConsoleColor.Cyan;
                                        Console.WriteLine(String.Format("[{0}] :: {1} received {2} from {3}. New balance: {4}.", Convert.ToDateTime(Reader["dDate"]).ToString("MM/dd/yyyy || HH:mm"), CharacterNames[Convert.ToInt32(Reader["nCharNo"])], Reader["nBigint1"], CharacterNames[Convert.ToInt32(Reader["nInt1"])], Reader["nItemKey"]));

                                        break;
                                    }
                                case 97:
                                    {
                                        Console.ForegroundColor = ConsoleColor.Cyan;
                                        Console.WriteLine(String.Format("[{0}] :: {1} paid {2} to {3}. New balance: {4}.", Convert.ToDateTime(Reader["dDate"]).ToString("MM/dd/yyyy || HH:mm"), CharacterNames[Convert.ToInt32(Reader["nCharNo"])], Reader["nBigint1"], CharacterNames[Convert.ToInt32(Reader["nInt1"])], Reader["nItemKey"]));

                                        break;
                                    }
                                case 140:
                                    {
                                        Console.ForegroundColor = ConsoleColor.Magenta;
                                        Console.WriteLine(String.Format("[{0}] :: {1} created guild {2} ({3}).", Convert.ToDateTime(Reader["dDate"]).ToString("MM/dd/yyyy || HH:mm"), CharacterNames[Convert.ToInt32(Reader["nCharNo"])], Reader["sMap"], Reader["nTargetID"]));

                                        break;
                                    }
                                case 510:
                                    {
                                        Console.ForegroundColor = ConsoleColor.Cyan;
                                        if (Convert.ToInt32(Reader["nTargetID"]) != 0) { Console.WriteLine(String.Format("[{0}] :: {1} picked up {2} ({3}).", Convert.ToDateTime(Reader["dDate"]).ToString("MM/dd/yyyy || HH:mm"), CharacterNames[Convert.ToInt32(Reader["nCharNo"])], ItemNames[Convert.ToInt32(Reader["nTargetID"])], Reader["nItemKey"])); }

                                        break;
                                    }
                                case 511:
                                    {
                                        Console.ForegroundColor = ConsoleColor.Magenta;
                                        Console.WriteLine(String.Format("[{0}] :: {1} dropped {2} ({3}).", Convert.ToDateTime(Reader["dDate"]).ToString("MM/dd/yyyy || HH:mm"), CharacterNames[Convert.ToInt32(Reader["nCharNo"])], ItemNames[Convert.ToInt32(Reader["nTargetID"])], Reader["nItemKey"]));

                                        break;
                                    }
                                case 512:
                                    {
                                        Console.ForegroundColor = ConsoleColor.Magenta;
                                        Console.WriteLine(String.Format("[{0}] :: {1} bought {2} ({3}) from NPC. Price: {4}.", Convert.ToDateTime(Reader["dDate"]).ToString("MM/dd/yyyy || HH:mm"), CharacterNames[Convert.ToInt32(Reader["nCharNo"])], ItemNames[Convert.ToInt32(Reader["nTargetID"])], Reader["nItemKey"], Reader["nInt3"]));

                                        break;
                                    }
                                case 513:
                                    {
                                        Console.ForegroundColor = ConsoleColor.Magenta;
                                        Console.WriteLine(String.Format("[{0}] :: {1} sold {2} ({3}) to NPC. Price: {4}.", Convert.ToDateTime(Reader["dDate"]).ToString("MM/dd/yyyy || HH:mm"), CharacterNames[Convert.ToInt32(Reader["nCharNo"])], ItemNames[Convert.ToInt32(Reader["nTargetID"])], Reader["nItemKey"], Reader["nInt3"]));

                                        break;
                                    }
                                //case 515:
                                //    {
                                //        Console.ForegroundColor = ConsoleColor.Magenta;
                                //        Console.WriteLine(String.Format("[{0}] :: {1} placed {2} into their storage.", Convert.ToDateTime(Reader["dDate"]).ToString("MM/dd/yyyy || HH:mm"), CharacterNames[Convert.ToInt32(Reader["nCharNo"])], Reader["nItemKey"]));

                                //        break;
                                //    }
                                //case 518:
                                //    {
                                //        Console.ForegroundColor = ConsoleColor.Cyan;
                                //        Console.WriteLine(String.Format("[{0}] :: {1} created {2} ({3}).", Convert.ToDateTime(Reader["dDate"]).ToString("MM/dd/yyyy || HH:mm"), CharacterNames[Convert.ToInt32(Reader["nCharNo"])], ItemNames[Convert.ToInt32(Reader["nTargetID"])], Reader["nItemKey"]));

                                //        break;
                                //    }
                                case 600:
                                    {
                                        Console.ForegroundColor = ConsoleColor.Magenta;
                                        Console.WriteLine(String.Format("[{0}] :: {1} accepeted {2} proposal.", Convert.ToDateTime(Reader["dDate"]).ToString("MM/dd/yyyy || HH:mm"), CharacterNames[Convert.ToInt32(Reader["nTargetCharNo"])], CharacterNames[Convert.ToInt32(Reader["nCharNo"])]));

                                        break;
                                    }
                                case 910:
                                    {
                                        Console.ForegroundColor = ConsoleColor.Cyan;
                                        Console.WriteLine(String.Format("[{0}] :: {1} was spawned at {2}. X: {3}. Y: {4}.", Convert.ToDateTime(Reader["dDate"]).ToString("MM/dd/yyyy || HH:mm"), MobNames[Convert.ToInt32(Reader["nTargetCharNo"])], Reader["sMap"], Reader["nMapX"], Reader["nMapY"]));

                                        break;
                                    }
                                case 911:
                                    {
                                        Console.ForegroundColor = ConsoleColor.Cyan;
                                        Console.WriteLine(String.Format("[{0}] :: {1} was near {2} when it was killed at {3}. X: {4}. Y: {5}.", Convert.ToDateTime(Reader["dDate"]).ToString("MM/dd/yyyy || HH:mm"), CharacterNames[Convert.ToInt32(Reader["nCharNo"])], MobNames[Convert.ToInt32(Reader["nTargetCharNo"])], Reader["sMap"], Reader["nMapX"], Reader["nMapY"]));

                                        break;
                                    }
                            }
                        }
                        catch { }

                        nLogNo = Convert.ToInt64(Reader["nLogNo"]);
                    }
                }
            }

            IsDone = true;
        }
    }
}
