using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;
using System.Collections;
using System.Xml.Linq;
using WeifenLuo.WinFormsUI.Docking;

namespace XuiWorkshop
{
    public sealed partial class Form1 : Form 
    {
        // Singleton
        static readonly Form1 instance = new Form1();

        public static Form1 Instance
        {
            get
            {
                return instance;
            }
        }
        // End Singleton

        public static string[] Args;

        private string filePath;
        private string extFilePath;

        // Local Array Lists
        private List<string> xmlExtensionsList;
        private List<XUI_CLASS> extensionClassList;

        // Local Class Instances
        public XmlExtensions _XmlExtensions;
        private INIFile inif;
        private XuiInjectExt extInject;
        private XUIOBJECTDATA xuiObject;

        // Form Classes
        public FormXui formXUI;
        private FormXur formXUR;
        private FormRecursive formRECURSIVE;
        public FormProperties formPROPERTIES;
        public FormTimelines formTIMELINES;

        //File System Watcher
        FileSystemWatcher watcher;

        public Form1()
        {
            InitializeComponent();

            // Load Files
            BuildXmlExtensionList();

            // Initialize Class Instances
            _XmlExtensions = new XmlExtensions();
            XuiClass.Instance.BuildClass(xmlExtensionsList);

            // Initialize Array Lists
            extensionClassList = new List<XUI_CLASS>();

            // Create Settings File
            inif = new INIFile(Directory.GetCurrentDirectory() + "\\settings.ini");

            // Read in our settings
            ReadSettings();

            // Hide menu items
            ToggleMenuStrip(false);
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            Args = Environment.GetCommandLineArgs();
            if (Args.Length > 1)
            {
                filePath = Args[1];
                LoadInfo();
            }
        }

        // Generic Methods
        private void LoadInfo()
        {
            string fileName = Path.GetFileName(filePath);
            toolStripStatusLabel1.Text = "Opened: " + filePath;

            // Create Watcher to monitor changes
            CreateFileWatcher(filePath);

            // Show our menu
            ToggleMenuStrip(true);

            switch (Path.GetExtension(filePath))
            {
                case ".xur":
                    Console.WriteLine("Xur File Loaded");

                    FileStream fileReader = new FileStream(filePath, FileMode.Open);
                    XurReader xurReader = new XurReader(fileReader);

                    xuiObject = xurReader.LoadObjectsFromBinary();
                    fileReader.Close();

                    // Show view toggle for xur info
                    xurInfoToolStripMenuItem.Visible = true;

                    if (xuiObject != null)
                    {
                        // Create new FormObject and pass global XUIOBJECTDATA
                        formXUI = new FormXui(xuiObject);

                        // Add this form to our Docking Scene
                        formXUI.Show(parentPanel);

                        // Create new FormObject
                        formXUR = new FormXur(filePath);

                        // Add this form to our Docking Scene
                        formXUR.Show(parentPanel);
                    }
                    else
                        MessageBox.Show("Failed to Load File", "File Failed", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1 );

                    break;
                case ".xui":
                    Console.WriteLine("Xui File Loaded");

                    // Hide view toggle for xur info
                    xurInfoToolStripMenuItem.Visible = false;

                    // Create a new XuiReader
                    XuiReader xuiReader = new XuiReader();

                    // Set up our flags
                    PROCESS_FLAGS processFlags = new PROCESS_FLAGS();
                    processFlags.useXam = xamClassesToolStripMenuItem.Checked; // Not Used
                    processFlags.xuiToolVersion = false; // Not Used Here
                    processFlags.useAnimations = addAnimationsToolStripMenuItem.Checked;

                    // Build our Base XuiObject from the XUI File
                    xuiObject = xuiReader.ReadXui(filePath, processFlags);

                    if (xuiObject != null)
                    {
                        // Load Extension File If it Exists
                        string saveFolderPath = Path.GetDirectoryName(filePath);
                        string extFileName = Path.GetFileNameWithoutExtension(filePath) + "_EXT.xui";
                        extFilePath = saveFolderPath + "\\" + extFileName;

                        // If EXT file exists, build and merge its info in
                        if (File.Exists(extFilePath))
                        {
                            XUIOBJECTDATA xuiInjectObjects = xuiReader.ReadXui(saveFolderPath + "\\" + extFileName, processFlags);
                            // Fix Property Order before injection
                            Global.ReorderProperties(xuiInjectObjects);
                            Global.ReorderProperties(xuiObject);

                            // Create new XuiInjectExt
                            extInject = new XuiInjectExt();

                            // Create new merged object
                            XUIOBJECTDATA mergedObject = extInject.InjectExt(xuiInjectObjects, xuiObject);

                            // Fix Prop Order 
                            Global.ReorderProperties(mergedObject);

                            // Update the global object with the new merged object
                            xuiObject = mergedObject;
                        }

                        // Remove any design elements
                        Global.RemoveDesignTimeElements(xuiObject);

                        // Build Heriarchy ID string
                        Global.BuildHeriarchyId(xuiObject);

                        // Create new FormObject and pass global XUIOBJECTDATA
                        formXUI = new FormXui(xuiObject);

                        // Add this form to our Docking Scene
                        formXUI.Show(parentPanel);
                    }
                    else
                        MessageBox.Show("Failed to Load File", "File Failed", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                    break;
            }

            // Set Title Text with open file
            this.Text = "Xui Workshop - " + fileName;
        }

        private void BuildXmlExtensionList()
        {
            // Build list of extensions from file
            xmlExtensionsList = new List<string>();

            // Make sure file exists before trying to load
            if (File.Exists(Directory.GetCurrentDirectory() + "\\XmlExtensions.list"))
            {
                using (StreamReader fileRead = new StreamReader(Directory.GetCurrentDirectory() + "\\XmlExtensions.list"))
                {
                    string line;
                    while ((line = fileRead.ReadLine()) != null)
                    {
                        xmlExtensionsList.Add(line);
                    }
                }
            }
            else
            {
                // File not found create
                FileStream fs = File.Create(Directory.GetCurrentDirectory() + "\\XmlExtensions.list");
                fs.Close();
            }
        }

        private void ReadSettings()
        {
            if (inif.Read("Settings", "useXamClasses") != "" &&
                inif.Read("Settings", "xuiToolVersion") != "" &&
                inif.Read("Settings", "useAnimations") != "")
            {
                xamClassesToolStripMenuItem.Checked = Convert.ToBoolean(inif.Read("Settings", "useXamClasses"));
                xuiToolVersionToolStripMenuItem.Checked = Convert.ToBoolean(inif.Read("Settings", "xuiToolVersion"));
                addAnimationsToolStripMenuItem.Checked = Convert.ToBoolean(inif.Read("Settings", "useAnimations"));
            }
            else
            {
                inif.Write("Settings", "useXamClasses", xamClassesToolStripMenuItem.Checked.ToString());
                inif.Write("Settings", "xuiToolVersion", xuiToolVersionToolStripMenuItem.Checked.ToString());
                inif.Write("Settings", "useAnimations", addAnimationsToolStripMenuItem.Checked.ToString());
            }
        }

        private void CloseForms()
        {
            if (formPROPERTIES != null)
                formPROPERTIES.Close();
            if (formTIMELINES != null)
                formTIMELINES.Close();
            if (formRECURSIVE != null)
                formRECURSIVE.Close();
            if (formXUI != null)
                formXUI.Close();
            if (formXUR != null)
                formXUR.Close();
        }

        private void SaveFile(string xuiPath)
        {
            // Update file path to new path
            filePath = xuiPath;

            // Remove old path to avoid any issues
            if (File.Exists(xuiPath))
                File.Delete(xuiPath);

            // Xur loaded dump to Xui
            switch (Path.GetExtension(xuiPath))
            {
                case ".xui":
                    XuiWriter xuiWrite = new XuiWriter();
                    PROCESS_FLAGS processFlags = new PROCESS_FLAGS();
                    processFlags.useXam = Form1.Instance.xamClassesToolStripMenuItem.Checked;
                    processFlags.xuiToolVersion = Form1.Instance.xuiToolVersionToolStripMenuItem.Checked;
                    processFlags.useAnimations = Form1.Instance.addAnimationsToolStripMenuItem.Checked;
                    processFlags.extFile = false;

                    xuiWrite.BuildXui(xuiPath, xuiObject, processFlags);

                    // Build Ext File
                    processFlags.extFile = true;

                    string saveFolderPath = Path.GetDirectoryName(xuiPath);
                    string extFileName = Path.GetFileNameWithoutExtension(xuiPath) + "_EXT.xui";

                    xuiWrite.BuildXui(saveFolderPath + "\\" + extFileName, xuiObject, processFlags);

                    Log.Instance.completedScenes.Add(Path.GetFileNameWithoutExtension(xuiPath));

                    processFlags.extFile = false;
                    Form1.Instance.toolStripStatusLabel1.Text = "Dumped: " + Path.GetFileNameWithoutExtension(xuiPath);

                    // Print our log file
                    Log.Instance.PrintLog();

                    // Reload the file
                    CloseForms();
                    LoadInfo();
                break;
                case ".xur":
                    FileStream fileWriter = new FileStream(filePath, FileMode.Create);
                    XurWriter writer = new XurWriter(fileWriter);

                    writer.WriteObjectsToBinary(xuiObject);
                    writer.Close();
                break;
            }
        }

        private void ToggleMenuStrip(bool toggle)
        {
            saveToolStripMenuItem.Visible = toggle;
            saveAsToolStripMenuItem.Visible = toggle;
            recursiveDumpToolStripMenuItem.Visible = toggle;
            closeToolStripMenuItem.Visible = toggle;
            exportBinaryToolStripMenuItem.Visible = toggle;
            toolStripSeparator2.Visible = toggle;
            viewToolStripMenuItem.Visible = toggle;
            save_toolStripButton.Enabled = toggle;
        }


        // ToolStrip Items
        private void openToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            DialogResult result = openFileDialog1.ShowDialog(); // Show the dialog and get result.
            if (result == DialogResult.OK)
            {
                // Close any open forms
                CloseForms();

                // Open File
                filePath = openFileDialog1.FileName;
                LoadInfo();
            }
        }

        private void open_toolStripButton_Click(object sender, EventArgs e)
        {
            DialogResult result = openFileDialog1.ShowDialog(); // Show the dialog and get result.
            if (result == DialogResult.OK)
            {
                // Close any open forms
                CloseForms();

                // Open File
                filePath = openFileDialog1.FileName;
                LoadInfo();
            }
        }

        private void recursiveDumpToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DialogResult result = folderBrowserDialog1.ShowDialog(); // Show the dialog and get result.
            if (result == DialogResult.OK)
            {
                // Create new FormObject
                formRECURSIVE = new FormRecursive(folderBrowserDialog1.SelectedPath);

                // Add this form to our Docking Scene
                formRECURSIVE.Show(parentPanel);

                // Dump Our Files
                formRECURSIVE.RecursiveDump();
            }
        }

        private void xmlExtensionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // Update properties to current list
            _XmlExtensions.xmlExtensionList = xmlExtensionsList;

            DialogResult dialogResult = _XmlExtensions.ShowDialog(this);

            if (dialogResult == DialogResult.OK)
            {
                StreamWriter write = new StreamWriter(Directory.GetCurrentDirectory() + "\\XmlExtensions.list");

                // Update local version to new version
                xmlExtensionsList = _XmlExtensions.xmlExtensionList;

                // Save List of paths to file
                foreach (string path in xmlExtensionsList)
                {
                    write.WriteLine(path);
                }

                write.Close();

                // Update XuiClass instance
                XuiClass.Instance.UpdateClassList(xmlExtensionsList);
            }
        }

        private void xamClassesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            inif.Write("Settings", "useXamClasses", xamClassesToolStripMenuItem.Checked.ToString());
        }

        private void xuiToolVersionToolStripMenuItem_Click(object sender, EventArgs e)
        {
            inif.Write("Settings", "xuiToolVersion", xuiToolVersionToolStripMenuItem.Checked.ToString());
        }

        private void addAnimationsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            inif.Write("Settings", "useAnimations", addAnimationsToolStripMenuItem.Checked.ToString());
        }

        private void aboutToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            About commandMenu = new About();
            commandMenu.ShowDialog();
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (Path.GetExtension(filePath) == ".xur")
            {
                saveFileDialog1.Filter = "XUI (*.xui)|*.xui";
                saveFileDialog1.FileName = Path.GetFileNameWithoutExtension(filePath);
                DialogResult save = saveFileDialog1.ShowDialog(); // Show the dialog and get result.

                if (save == DialogResult.OK)
                    SaveFile(saveFileDialog1.FileName);
            }
            else
                SaveFile(filePath);
        }

        private void save_toolStripButton_Click(object sender, EventArgs e)
        {
            if (Path.GetExtension(filePath) == ".xur")
            {
                saveFileDialog1.Filter = "XUI (*.xui)|*.xui";
                saveFileDialog1.FileName = Path.GetFileNameWithoutExtension(filePath);
                DialogResult save = saveFileDialog1.ShowDialog(); // Show the dialog and get result.

                if (save == DialogResult.OK)
                    SaveFile(saveFileDialog1.FileName);
            }
            else
                SaveFile(filePath);
        }

        private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            saveFileDialog1.Filter = "XUI (*.xui)|*.xui";
            saveFileDialog1.FileName = Path.GetFileNameWithoutExtension(filePath);
            DialogResult save = saveFileDialog1.ShowDialog(); // Show the dialog and get result.

            if (save == DialogResult.OK)
                SaveFile(saveFileDialog1.FileName);
        }

        private void propertiesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (propertiesToolStripMenuItem.Checked)
                formPROPERTIES.Show();
            else
                formPROPERTIES.Hide();
        }

        private void timelinesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (timelinesToolStripMenuItem.Checked)
                formTIMELINES.Show();
            else
                formTIMELINES.Hide();
        }

        private void xurInfoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (xurInfoToolStripMenuItem.Checked)
                formXUR.Show();
            else
                formXUR.Hide();
        }

        private void closeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            CloseForms();

            ToggleMenuStrip(false);
        }

        private void exportBinaryToolStripMenuItem_Click(object sender, EventArgs e)
        {
            saveFileDialog1.Filter = "XUR (*.xur)|*.xur";
            saveFileDialog1.FileName = Path.GetFileNameWithoutExtension(filePath);
            DialogResult save = saveFileDialog1.ShowDialog(); // Show the dialog and get result.

            if (save == DialogResult.OK)
                SaveFile(saveFileDialog1.FileName);
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }


        //File System Watcher
        public void CreateFileWatcher(string path)
        {
            if (watcher == null)
            {
                // Create a new FileSystemWatcher and set its properties.
                watcher = new FileSystemWatcher();
                watcher.SynchronizingObject = Form1.instance;
                watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName;

                // Add event handlers.
                watcher.Changed += new FileSystemEventHandler(OnChanged);
                watcher.Renamed += new RenamedEventHandler(OnRenamed);
            }

            watcher.Path = Path.GetDirectoryName(path);
            watcher.Filter = Path.GetFileName(path);

            // Begin watching.
            if(!watcher.EnableRaisingEvents)
                watcher.EnableRaisingEvents = true;
        }

        // Define the event handlers.
        private static void OnChanged(object source, FileSystemEventArgs e)
        {
            try
            {
                Form1.instance.watcher.EnableRaisingEvents = false;

                if (MessageBox.Show("The file has been updated outside this program. Would you like to reload?", "File Modified", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.Yes)
                {
                    Form1.instance.CloseForms();
                    Form1.instance.filePath = e.FullPath;
                    Form1.instance.LoadInfo();

                    if (MessageBox.Show("Would you like to build a binary?", "Build Binary", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                    {
                        Form1.instance.saveFileDialog1.Filter = "XUR (*.xur)|*.xur";
                        Form1.instance.saveFileDialog1.FileName = Path.GetFileNameWithoutExtension(Form1.instance.filePath);
                        DialogResult save = Form1.instance.saveFileDialog1.ShowDialog(); // Show the dialog and get result.

                        if (save == DialogResult.OK)
                            Form1.instance.SaveFile(Form1.instance.saveFileDialog1.FileName);
                    }
                }
            }
            finally
            {
                Form1.instance.watcher.EnableRaisingEvents = true;
            }
        }

        private static void OnRenamed(object source, RenamedEventArgs e)
        {
            try
            {
                Form1.instance.watcher.EnableRaisingEvents = false;

                if (MessageBox.Show("The file has been updated outside this program. Would you like to reload?", "File Modified", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.Yes)
                {
                    Form1.instance.CloseForms();
                    Form1.instance.filePath = e.FullPath;
                    Form1.instance.LoadInfo();

                    if (MessageBox.Show("Would you like to build a binary?", "Build Binary", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                    {
                        Form1.instance.saveFileDialog1.Filter = "XUR (*.xur)|*.xur";
                        Form1.instance.saveFileDialog1.FileName = Path.GetFileNameWithoutExtension(Form1.instance.filePath);
                        DialogResult save = Form1.instance.saveFileDialog1.ShowDialog(); // Show the dialog and get result.

                        if (save == DialogResult.OK)
                            Form1.instance.SaveFile(Form1.instance.saveFileDialog1.FileName);
                    }
                }
            }
            finally
            {
                Form1.instance.watcher.EnableRaisingEvents = true;
            }
        }
    }
}
