// Copyright © 2017-2018 Atomic Software, LLC. All Rights Reserved.
// See LICENSE.md for full license information.

using Atom.Core.Collections;
using Atom.Core.Diagnostics;
using Atom.Core.Game;
using Atom.Core.Game.GameObjects.Characters;
using Atom.Core.IO;
using Microsoft.VisualBasic.FileIO;
using System;
using System.Data;
using System.IO;
using System.Linq;

namespace Atom.WorldManagerServer
{
    internal class Program
    {
        public static WorldManagerServer ServerInstance;
        public static string ShinePath;

        public static ConcurrentDictionary<byte, byte> FaceInfo;
        public static ConcurrentDictionary<byte, byte> HairColorInfo;
        public static ConcurrentDictionary<byte, byte> HairInfo;
        public static ConcurrentDictionary<string, ushort> SingleData;

        public static ConcurrentDictionary<CharacterClass, SimpleCharacter> DefaultCharacterData;

        /// <summary>
        /// The main entry point of the application.
        /// </summary>
        private static void Main()
        {
            ServerInstance = new WorldManagerServer();
            ServerInstance.Start();
        }

        public static void LoadSHNs()
        {
            FaceInfo = new ConcurrentDictionary<byte, byte>();

            using (var FileHandle = new SHNFile($"{ShinePath}FaceInfo.shn"))
            using (var Reader = new DataTableReader(FileHandle))
            {
                if (Reader.HasRows)
                {
                    while (Reader.Read())
                    {
                        if (FaceInfo.ContainsKey(Reader.GetByte(0)))
                        {
                            Log.Warning("Assert", "Duplicate handle in file 'FaceInfo.shn'");
                            continue;
                        }

                        FaceInfo.Add(Reader.GetByte(0), Reader.GetByte(2));
                    }
                }
            }

            HairColorInfo = new ConcurrentDictionary<byte, byte>();

            using (var FileHandle = new SHNFile($"{ShinePath}HairColorInfo.shn"))
            using (var Reader = new DataTableReader(FileHandle))
            {
                if (Reader.HasRows)
                {
                    while (Reader.Read())
                    {
                        if (HairColorInfo.ContainsKey(Reader.GetByte(0)))
                        {
                            Log.Warning("Assert", "Duplicate handle in file 'HairColorInfo.shn'");
                            continue;
                        }

                        HairColorInfo.Add(Reader.GetByte(0), Reader.GetByte(4));
                    }
                }
            }

            HairInfo = new ConcurrentDictionary<byte, byte>();

            using (var FileHandle = new SHNFile($"{ShinePath}HairInfo.shn"))
            using (var Reader = new DataTableReader(FileHandle))
            {
                if (Reader.HasRows)
                {
                    while (Reader.Read())
                    {
                        if (HairInfo.ContainsKey(Reader.GetByte(0)))
                        {
                            Log.Warning("Assert", "Duplicate handle in file 'HairInfo.shn'");
                            continue;
                        }

                        HairInfo.Add(Reader.GetByte(0), Reader.GetByte(3));
                    }
                }
            }

            SingleData = new ConcurrentDictionary<string, ushort>();

            using (var FileHandle = new SHNFile($"{ShinePath}SingleData.shn"))
            using (var Reader = new DataTableReader(FileHandle))
            {
                if (Reader.HasRows)
                {
                    while (Reader.Read())
                    {
                        if (SingleData.ContainsKey(Reader.GetString(0)))
                        {
                            Log.Warning("Assert", "Duplicate handle in file 'SingleData.shn'");
                            continue;
                        }

                        SingleData.Add(Reader.GetString(0), (ushort) Reader.GetValue(1));
                    }
                }
            }
        }

        public static void LoadShineTables()
        {
            DefaultCharacterData = new ConcurrentDictionary<CharacterClass, SimpleCharacter>();

            var Rows = new List<string[]>();
            var DataTypes = new[] {"CHARACTER", "ITEM", "SKILL", "QUEST", "MAXSHAPE", "SHORTCUT"};

            using (var FileHandle = File.OpenRead($"{ShinePath}DefaultCharacterData.txt"))
            using (var Reader = new TextFieldParser(FileHandle))
            {
                Reader.TrimWhiteSpace = true;
                Reader.CommentTokens = new[] {";"};
                Reader.Delimiters = new[] {",", "\t"};
                Reader.HasFieldsEnclosedInQuotes = true;

                while (!Reader.EndOfData)
                {
                    var LineHandle = Reader.ReadFields();

                    if (LineHandle == null || LineHandle.Length <= 0 || !DataTypes.Contains(LineHandle[0]))
                    {
                        continue;
                    }

                    Rows.Add(LineHandle.Where(Value => Value != "").ToArray());
                }
            }

            foreach (var ItemArray in Rows)
            {
                var Class = (CharacterClass) Convert.ToByte(ItemArray[1]);

                if (!DefaultCharacterData.TryGetValue(Class, out SimpleCharacter DefaultCharacter))
                {
                    DefaultCharacterData.Add(Class, new SimpleCharacter());
                    DefaultCharacter = DefaultCharacterData[Class];
                }

                switch (ItemArray[0])
                {
                    case "CHARACTER":
                        DefaultCharacter.MapIndx = ItemArray[2];
                        DefaultCharacter.X = Convert.ToInt32(ItemArray[3]);
                        DefaultCharacter.Y = Convert.ToInt32(ItemArray[4]);
                        DefaultCharacter.HP = Convert.ToInt32(ItemArray[5]);
                        DefaultCharacter.SP = Convert.ToInt32(ItemArray[6]);
                        DefaultCharacter.HPStone = Convert.ToInt32(ItemArray[7]);
                        DefaultCharacter.SPStone = Convert.ToInt32(ItemArray[8]);
                        DefaultCharacter.Money = Convert.ToInt64(ItemArray[9]);
                        DefaultCharacter.Level = Convert.ToByte(ItemArray[10]);
                        DefaultCharacter.EXP = Convert.ToInt64(ItemArray[11]);
                        break;
                    case "ITEM":
                        if (!DefaultCharacter.ItemLots.ContainsKey(Convert.ToUInt16(ItemArray[2])))
                        {
                            DefaultCharacter.ItemLots.Add(Convert.ToUInt16(ItemArray[2]), 1);
                        }

                        DefaultCharacter.ItemLots[Convert.ToUInt16(ItemArray[2])] = Convert.ToInt32(ItemArray[3]);
                        break;
                    case "SKILL":
                        if (DefaultCharacter.Skills.Contains(Convert.ToUInt16(ItemArray[2])))
                        {
                            break;
                        }

                        DefaultCharacter.Skills.Add(Convert.ToUInt16(ItemArray[2]));
                        break;
                    case "QUEST":
                        if (DefaultCharacter.Quests.Contains(Convert.ToInt32(ItemArray[2])))
                        {
                            break;
                        }

                        DefaultCharacter.Quests.Add(Convert.ToInt32(ItemArray[2]));
                        break;
                    case "SHORTCUT":
                        if (DefaultCharacter.Shortcuts.ContainsKey(Convert.ToByte(ItemArray[2])))
                        {
                            break;
                        }

                        DefaultCharacter.Shortcuts.Add(Convert.ToByte(ItemArray[2]), new Shortcut
                        {
                            Slot = Convert.ToByte(ItemArray[2]),
                            Code = Convert.ToUInt16(ItemArray[3]),
                            Value = Convert.ToUInt16(ItemArray[4])
                        });
                        break;
                }

                DefaultCharacterData[Class] = DefaultCharacter;
            }
        }
    }
}
