using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using Advanced_Combat_Tracker;
using System.IO;
using System.Reflection;
using System.Xml;

[assembly: AssemblyTitle("ACTUtility")]
[assembly: AssemblyCompany("쿨냠쿨냠")]
[assembly: AssemblyProduct("ACTUtility")]
[assembly: AssemblyVersion("1.0.0.2")]
[assembly: AssemblyFileVersion("1.0.0.2")]

namespace ACTUtility
{
    //using System.Linq;
    using System.Net.Sockets;
    using System.Runtime.CompilerServices;
    using System.Threading.Tasks;
    using System.Timers;

    public class ACTUtilityMain : UserControl, IActPluginV1
    {
        private Button Apply;
        private CheckBox autoStart;
        #region Designer Created Code (Avoid editing)
        /// <summary> 
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary> 
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Component Designer generated code

        /// <summary> 
        /// Required method for Designer support - do not modify 
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.Apply = new System.Windows.Forms.Button();
            this.autoStart = new System.Windows.Forms.CheckBox();
            this.SuspendLayout();
            // 
            // Apply
            // 
            this.Apply.Location = new System.Drawing.Point(3, 3);
            this.Apply.Name = "Apply";
            this.Apply.Size = new System.Drawing.Size(75, 23);
            this.Apply.TabIndex = 1;
            this.Apply.Text = "Patch";
            this.Apply.UseVisualStyleBackColor = true;
            this.Apply.Click += new System.EventHandler(this.Apply_Click);
            // 
            // autoStart
            // 
            this.autoStart.Location = new System.Drawing.Point(84, 2);
            this.autoStart.Name = "autoStart";
            this.autoStart.Size = new System.Drawing.Size(104, 24);
            this.autoStart.TabIndex = 0;
            this.autoStart.Text = "Auto Start";
            this.autoStart.UseVisualStyleBackColor = true;
            // 
            // ACTUtilityMain
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.Controls.Add(this.Apply);
            this.Controls.Add(this.autoStart);
            this.Name = "ACTUtilityMain";
            this.Size = new System.Drawing.Size(798, 407);
            this.Load += new System.EventHandler(this.ACTUtility_Load);
            this.ResumeLayout(false);

        }

        #endregion

        #endregion
        public ACTUtilityMain()
        {
            InitializeComponent();
        }

        ~ACTUtilityMain()
        {
        }

        private string GetPluginDirectory()
        {
            foreach (var x in ActGlobals.oFormActMain.ActPlugins)
            {
                if (x.pluginObj == this)
                {
                    if (x != null)
                    {
                        return System.IO.Path.GetDirectoryName(x.pluginFile.FullName);
                    }
                }
            }
            throw new Exception();
        }

        Label lblStatus;    // The status label that appears in ACT's Plugin tab
        string settingsFile = Path.Combine(ActGlobals.oFormActMain.AppDataFolder.FullName, "Config\\ACTUtility.config.xml");
        SettingsSerializer xmlSettings;

        #region IActPluginV1 Members

        public void InitPlugin(TabPage pluginScreenSpace, Label pluginStatusText)
        {
            lblStatus = pluginStatusText;   // Hand the status label's reference to our local var
            pluginScreenSpace.Controls.Add(this);   // Add this UserControl to the tab ACT provides
            this.Dock = DockStyle.Fill; // Expand the UserControl to fill the tab's client space
            xmlSettings = new SettingsSerializer(this); // Create a new settings serializer and pass it this instance

            LoadSettings();
            // Create some sort of parsing event handler.  After the "+=" hit TAB twice and the code will be generated for you.
            var s = ActGlobals.oFormActMain.ActPlugins;
            lblStatus.Text = "Plugin Started";

            if (autoStart.Checked)
            {
                Timer timer = new System.Timers.Timer();
                timer.Interval = 5000; // 5 sec
                timer.Elapsed += delegate { Patch(); timer.Close(); };
                timer.Start();
            }
        }

        public void DeInitPlugin()
        {
            // Unsubscribe from any events you listen to when exiting!

            SaveSettings();
            lblStatus.Text = "Plugin Exited";
        }

        #endregion

        void LoadSettings()
        {
            xmlSettings.AddControlSetting(autoStart.Name, autoStart);
            if (File.Exists(settingsFile))
            {
                FileStream fs = new FileStream(settingsFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                XmlTextReader xReader = new XmlTextReader(fs);

                try
                {
                    while (xReader.Read())
                    {
                        if (xReader.NodeType == XmlNodeType.Element)
                        {
                            if (xReader.LocalName == "SettingsSerializer")
                            {
                                xmlSettings.ImportFromXml(xReader);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    lblStatus.Text = "Error loading settings: " + ex.Message;
                }
                xReader.Close();
            }
        }

        void SaveSettings()
        {
            FileStream fs = new FileStream(settingsFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
            XmlTextWriter xWriter = new XmlTextWriter(fs, Encoding.UTF8);
            xWriter.Formatting = Formatting.Indented;
            xWriter.Indentation = 1;
            xWriter.IndentChar = '\t';
            xWriter.WriteStartDocument(true);
            xWriter.WriteStartElement("Config");    // <Config>
            xWriter.WriteStartElement("SettingsSerializer");    // <Config><SettingsSerializer>
            xmlSettings.ExportToXml(xWriter);   // Fill the SettingsSerializer XML
            xWriter.WriteEndElement();  // </SettingsSerializer>
            xWriter.WriteEndElement();  // </Config>
            xWriter.WriteEndDocument(); // Tie up loose ends (shouldn't be any)
            xWriter.Flush();    // Flush the file buffer to disk
            xWriter.Close();
        }

        private void Patch()
        {

            object plugin = null;
            if (plugin == null)
            {
                foreach (var item in ActGlobals.oFormActMain.ActPlugins)
                {
                    if (item.pluginFile.Name.ToUpper() == "FFXIV_ACT_Plugin.dll".ToUpper() &&
                        item.lblPluginStatus.Text.ToUpper() == "FFXIV Plugin Started.".ToUpper())
                    {
                        plugin = item.pluginObj;
                        break;
                    }
                }
            }

            try
            {
                if (plugin != null)
                {
                    {
                        //FFXIVPointers.ChatLog
                        var t = plugin.GetType().Module.Assembly.GetType("FFXIV_ACT_Plugin.Memory.FFXIVPointers");
                        var obj = t.GetField("_Signatures", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
                        var t2 = plugin.GetType().Module.Assembly.GetType("FFXIV_ACT_Plugin.FFXIVClientMode");
                        string[] names = Enum.GetNames(t2);
                        object ffxiv32 = Enum.GetValues(t2).GetValue(Array.IndexOf(names, "FFXIV_32"));
                        var t3 = plugin.GetType().Module.Assembly.GetType("FFXIV_ACT_Plugin.Memory.FFXIVPointers+SignatureType");
                        names = Enum.GetNames(t3);
                        object chatLog = Enum.GetValues(t3).GetValue(Array.IndexOf(names, "ChatLog"));

                        if (ffxiv32 != null && chatLog != null)
                        {
                            var TryGetValueMethod = obj.GetType().GetMethod("TryGetValue", BindingFlags.Public | BindingFlags.Instance);
                            object[] args = new object[] { ffxiv32, null };
                            if ((bool)TryGetValueMethod.Invoke(obj, args))
                            {
                                var obj2 = args[1];
                                var TryGetValueMethod2 = obj2.GetType().GetMethod("TryGetValue", BindingFlags.Public | BindingFlags.Instance);
                                object[] args2 = new object[] { chatLog, null };
                                if ((bool)TryGetValueMethod2.Invoke(obj2, args2))
                                {
                                    string s2 = (string)args2[1];
                                    // original signature
                                    //MessageBox.Show(s2);
                                }
                            }
                            if ((bool)TryGetValueMethod.Invoke(obj, args))
                            {
                                var obj2 = args[1];
                                var RemoveMethod2 = obj2.GetType().GetMethod("Remove", BindingFlags.Public | BindingFlags.Instance);
                                var SetValueMethod2 = obj2.GetType().GetMethod("Add", BindingFlags.Public | BindingFlags.Instance);
                                object[] args20 = new object[] { chatLog };
                                RemoveMethod2.Invoke(obj2, args20);
                                string s3 = "**088b**********505152e8********a1";
                                object[] args21 = new object[] { chatLog, s3 };
                                SetValueMethod2.Invoke(obj2, args21);
                            }
                        }
                    }

                    {
                        var Settings = plugin.GetType().GetField("Settings", BindingFlags.Public | BindingFlags.Instance).GetValue(plugin);
                        ComboBox cboLanguage = (ComboBox)Settings.GetType().GetField("cboLanguage", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(Settings);
                        cboLanguage.Enabled = false;
                        cboLanguage.SelectedIndex = 3;
                        //FFXIV_ACT_Plugin.Parse.LogParse
                        var _LogParse = plugin.GetType().GetField("_LogParse", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(plugin);
                        //cboLanguage
                        var OnParseSettingsChanged = _LogParse.GetType().GetMethod("OnParseSettingsChanged");
                        var _settings = _LogParse.GetType().GetField("_settings", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(_LogParse);
                        _settings.GetType().GetField("LanguageID", BindingFlags.Public | BindingFlags.Instance).SetValue(_settings, 4);
                        OnParseSettingsChanged.Invoke(_LogParse, new object[] { plugin, _settings });
                        cboLanguage.Text = "Korean";
                    }

                    // Pets
                    {
                        //FFXIV_ACT_Plugin.FFXIV_ACT_Plugin._LogParse
                        var _LogParse = plugin.GetType().GetField("_LogParse", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(plugin);
                        // FFXIV_ACT_Plugin.Parse.LogParse._settings.CombatantHistory.m_PetNames
                        var _settings = _LogParse.GetType().GetField("_settings", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(_LogParse);
                        var CombatantHistory = _settings.GetType().GetField("CombatantHistory", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(_settings);
                        List<string> m_PetNames = (List<string>)CombatantHistory.GetType().GetField("m_PetNames", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(CombatantHistory);
                        List<string> m_NonPetNames = (List<string>)CombatantHistory.GetType().GetField("m_NonPetNames", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(CombatantHistory);
                        //m_PetNames;
                        m_PetNames.Clear();
                        m_NonPetNames.Clear();

                        m_PetNames.AddRange(new List<string>
                    {
                        "가루다 에기",
                        "타이탄 에기",
                        "이프리트 에기",
                        "요정 에오스",
                        "요정 셀레네",
                        "카벙클 에메랄드",
                        "카벙클 토파즈",
                        "자동포탑 룩",
                        "자동포탑 비숍"
                    });
                        m_NonPetNames.AddRange(new List<string>
                    {
                        "가루다",
                        "타이탄",
                        "이프리트"
                    });
                    }

                    // Skills
                    {
                        GetPluginDirectory();
                        var t = plugin.GetType().Module.Assembly.GetType("FFXIV_ACT_Plugin.Resources.SkillList");
                        var obj = t.GetField("_instance", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
                        var names = typeof(ACTUtilityMain).Module.Assembly.GetManifestResourceNames();
                        String manifestResourceStream = this.GetPluginDirectory() + "/SkillList_KR.txt";
                        //manifestResourceStream = typeof(ACTUtilityMain).Module.Assembly.GetManifestResourceStream("SkillList_KR.txt");
                        using (StreamReader streamReader = new StreamReader(manifestResourceStream))
                        {
                            string text = streamReader.ReadToEnd();
                            var list = new SortedDictionary<int, string>();
                            string[] tmp = text.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
                            foreach (string x in tmp)
                            {
                                string[] tmp2 = x.Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries);
                                if (tmp2.Length == 2)
                                {
                                    list[Convert.ToInt32(tmp2[0], 16)] = tmp2[1];
                                }
                            }
                            t.GetField("_SkillList", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(obj, list);
                        }
                    }

                    // Buff
                    {
                        var t = plugin.GetType().Module.Assembly.GetType("FFXIV_ACT_Plugin.Resources.BuffList");
                        var obj = t.GetField("_instance", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
                        String manifestResourceStream = this.GetPluginDirectory() + "/BuffList_KR.txt";
                        //manifestResourceStream = typeof(ACTUtilityMain).Module.Assembly.GetManifestResourceStream("BuffList_KR.txt");
                        using (StreamReader streamReader = new StreamReader(manifestResourceStream))
                        {
                            string text = streamReader.ReadToEnd();
                            var list = new SortedDictionary<int, string>();
                            string[] tmp = text.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
                            foreach (string x in tmp)
                            {
                                string[] tmp2 = x.Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries);
                                if (tmp2.Length == 2)
                                {
                                    list[Convert.ToInt32(tmp2[0], 16)] = tmp2[1];
                                }
                            }
                            t.GetField("_BuffList", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(obj, list);
                        }
                    }

                    // Zone
                    {
                        var t = plugin.GetType().Module.Assembly.GetType("FFXIV_ACT_Plugin.Resources.ZoneList");
                        var obj = t.GetField("_instance", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
                        var s = t.GetField("_Zones", BindingFlags.NonPublic | BindingFlags.Instance).ReflectedType;
                        var list = t.GetField("_Zones", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(obj);
                        var listType = list.GetType();
                        var ClearMethod = listType.GetMethod("Clear", BindingFlags.Public | BindingFlags.Instance);
                        var AddMethod = listType.GetMethod("Add", BindingFlags.Public | BindingFlags.Instance);
                        var zoneType = AddMethod.GetParameters()[1].ParameterType;

                        var idField = zoneType.GetField("id", BindingFlags.Public | BindingFlags.Instance);
                        var nameField = zoneType.GetField("name", BindingFlags.Public | BindingFlags.Instance);
                        String manifestResourceStream = this.GetPluginDirectory() + "/ZoneList_KR.txt";
                        //manifestResourceStream = typeof(ACTUtilityMain).Module.Assembly.GetManifestResourceStream("ZoneList_KR.txt");
                        using (StreamReader streamReader = new StreamReader(manifestResourceStream))
                        {
                            string text = streamReader.ReadToEnd();

                            ClearMethod.Invoke(list, null);

                            string[] tmp = text.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
                            foreach (string x in tmp)
                            {
                                string[] tmp2 = x.Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries);
                                if (tmp2.Length == 2)
                                {
                                    var zone = Activator.CreateInstance(zoneType);
                                    idField.SetValue(zone, Convert.ToInt32(tmp2[0], 16));
                                    nameField.SetValue(zone, tmp2[1]);
                                    AddMethod.Invoke(list, new object[] { Convert.ToInt32(tmp2[0], 16), zone });
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                lblStatus.Text = "Error Patch : " + ex.Message;
            }
        }

        private void ACTUtility_Load(object sender, EventArgs e)
        {
        }

        private void Apply_Click(object sender, EventArgs e)
        {
            Patch();
        }
    }
}
