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

namespace Engineer.Librarys.Plugin_Converter
{
    public partial class Converter : Form
    {
        public Converter()
        {
            InitializeComponent();
        }

        private void btnLoadPlugins_Click(object sender, EventArgs e)
        {
            //Create a open file dialog
            OpenFileDialog ofd = new OpenFileDialog();
            //Allow mutliple files to be opened
            ofd.Multiselect = true;
            //Set file types allowed to be opened
            ofd.Filter = "Ent Plugin (*.ENT)|*.ent|Ifp Plugin (*.IFP)|*.ifp|All Files(*.*)|*.*";
            //Show open file dialog
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                for (int i = 0; i < ofd.FileNames.Length; i++)
                {
                    listBox1.Items.Add(ofd.FileNames[i]);                    
                }

                progressBar1.Value = 0;
            }

            progressBar1.Maximum = listBox1.Items.Count;
        }

        private void btnConvertPlugins_Click(object sender, EventArgs e)
        {
            //For each file name in listbox1
            for (int i = 0; i < listBox1.Items.Count; i++)
            {
                //Get file info
                FileInfo fi = new FileInfo(listBox1.Items[i].ToString());
                //Open a xml reader to read plugin
                XmlTextReader xmlr = new XmlTextReader(fi.OpenRead());
                //Declare file strea so we can write our new plugin to it
                FileStream fs;                
                //If user chose to copy new plugin to thier plugin folder
                if (cbxCopyToFolder.Checked)
                {
                    //Check if a plugin of already exist for this name
                    if(File.Exists(Application.StartupPath + "\\CSPlugins\\" + fi.Name.Replace(".ent", "") + ".cs"))
                    {
                        //Ask user if they want to make a backup of the old plugin
                        DialogResult result = MessageBox.Show("A plugin by the name of " + fi.Name.Replace(".ent", "") + ".cs already exist, make backup?", 
                            "File exist", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
                        //If yes is chosen create a copy of the old plugin with the extension .bak
                        if (result == DialogResult.Yes)
                            File.Copy(Application.StartupPath + "\\CSPlugins\\" + fi.Name.Replace(".ent", "") + ".cs", Application.StartupPath + "\\CSPlugins\\" + fi.Name.Replace(".ent", "") + ".cs.bak", true);
                    }
                    //Create the file we will write the plugin to in the users plugin folder
                    fs = new FileStream(Application.StartupPath + "\\CSPlugins\\" + fi.Name.Replace(".ent", "") + ".cs", FileMode.Create);
                }
                else
                {
                    //Create file to write plugin to in same folder as source plugin
                    fs = new FileStream((fi.DirectoryName + "\\" + fi.Name + ".cs").Replace(".ent", ""), FileMode.Create);
                }
                //Create stream writer so we can write text to the filestream
                StreamWriter sw = new StreamWriter(fs);
                //This will lest us know if the last xml element was a struct(Reflexive)
                bool lastWasstruct = false;
                //How far to indent the text
                int indent = 0;
                //Start conversion
                Convert(ref xmlr, ref sw, indent, lastWasstruct);
                //Close streams
                sw.Close();
                fs.Close();
                //Increase progress bar value
                progressBar1.Value++;
            }
            //Show done message
            MessageBox.Show("Done " + listBox1.Items.Count.ToString() + "Plugins were converted");
        }
        /// <summary>
        /// Converts a .Ent plugin file to a .CS plugin file
        /// </summary>
        /// <param name="xmlr">Xml Reader to use</param>
        /// <param name="sw">Stream writer to use</param>
        /// <param name="i">Current level of indentation</param>
        /// <param name="lastWasstruct">Was the last element a struct</param>
        private void Convert(ref XmlTextReader xmlr, ref StreamWriter sw, int i, bool lastWasstruct)
        {
            //Read file and at each node
            while (xmlr.Read())
            {
                //check the node type
                switch (xmlr.NodeType.ToString())
                {
                    //If the node is an element
                    case "Element":
                        {
                            //Check the element type
                            switch (xmlr.Name.ToLower())
                            {
                                //If plugin type
                                case "plugin":
                                    {
                                        //Write .cs header
                                        sw.WriteLine("using System;");
                                        sw.WriteLine("using System.Collections.Generic;");
                                        sw.WriteLine("using System.Text;");
                                        sw.WriteLine("using Halo3Map.IO;");
                                        sw.WriteLine("using Halo3Map.Data;");
                                        sw.WriteLine();
                                        sw.WriteLine("namespace Halo3Map.Tags.Layouts");
                                        sw.WriteLine("{");
                                        sw.WriteLine("    [Tag(\"" + xmlr.GetAttribute("author") + "\", \"" + xmlr.GetAttribute("class") + "\", " + xmlr.GetAttribute("version") + ")]");
                                        sw.WriteLine("    public class " + xmlr.GetAttribute("class") + " : H3Tag");
                                        sw.WriteLine("    {");
                                        break;
                                    }
                                case "revision":
                                    {
                                        //Write revision
                                        sw.WriteLine("        //Revision: shade45 - Converted to CS from Ent");
                                        sw.WriteLine("        //Revision: " + xmlr.GetAttribute("author") + " - " + xmlr.ReadString());
                                        break;
                                    }
                                case "undefined":
                                    {
                                        if (!lastWasstruct)
                                        {
                                            sw.WriteLine();
                                            for (int x = 0; x < i; x++)
                                            {
                                                sw.Write(" ");
                                            }
                                            sw.Write("        public int Unknown" + xmlr.GetAttribute("offset") + ";");
                                        }
                                        else lastWasstruct = false;
                                        break;
                                    }
                                case "tag":
                                    {
                                        if (!lastWasstruct)
                                        {
                                            sw.WriteLine();
                                            for (int x = 0; x < i; x++)
                                            {
                                                sw.Write(" ");
                                            }
                                            sw.Write("        public TagReference" + xmlr.GetAttribute("name") + ";");
                                        }
                                        else lastWasstruct = false;
                                        break;
                                    }
                                case "id":
                                    { break; }
                                case "unused":
                                    {                                        
                                        if (!lastWasstruct)
                                        {
                                            sw.WriteLine();
                                            for (int x = 0; x < i; x++)
                                            {
                                                sw.Write(" ");
                                            }
                                            sw.WriteLine("        [Size(" + xmlr.GetAttribute("size") + ")]");
                                            sw.WriteLine();
                                            for (int x = 0; x < i; x++)
                                            {
                                                sw.Write(" ");
                                            }
                                            sw.Write("        public byte[]" + xmlr.GetAttribute("name") + xmlr.GetAttribute("offset") + ";");
                                        }
                                        else lastWasstruct = false;
                                        break;
                                    }
                                case "byte":
                                    {
                                        sw.WriteLine();
                                        for (int x = 0; x < i; x++)
                                        {
                                            sw.Write(" ");
                                        }
                                        sw.Write("        public byte Unknown" + xmlr.GetAttribute("offset") + ";");
                                        break;
                                    }
                                case "short":
                                    {
                                        sw.WriteLine();
                                        for (int x = 0; x < i; x++)
                                        {
                                            sw.Write(" ");
                                        }
                                        sw.Write("        public short Unknown" + xmlr.GetAttribute("offset") + ";");
                                        break;
                                    }
                                case "ushort":
                                    {
                                        sw.WriteLine();
                                        for (int x = 0; x < i; x++)
                                        {
                                            sw.Write(" ");
                                        }
                                        sw.Write("        public ushort Unknown" + xmlr.GetAttribute("offset") + ";");
                                        break;
                                    }
                                case "float":
                                    {
                                        if (!lastWasstruct)
                                        {
                                            sw.WriteLine();
                                            for (int x = 0; x < i; x++)
                                            {
                                                sw.Write(" ");
                                            }
                                            sw.Write("        public float" + xmlr.GetAttribute("name") + ";");
                                        }
                                        else lastWasstruct = false;
                                        break;
                                    }
                                case "int":
                                    {
                                        if (!lastWasstruct)
                                        {
                                            sw.WriteLine();
                                            for (int x = 0; x < i; x++)
                                            {
                                                sw.Write(" ");
                                            }
                                            sw.Write("        public int" + xmlr.GetAttribute("name") + ";");
                                        }
                                        else lastWasstruct = false;
                                        break;
                                    }
                                case "uint":
                                    {
                                        if (!lastWasstruct)
                                        {
                                            sw.WriteLine();
                                            for (int x = 0; x < i; x++)
                                            {
                                                sw.Write(" ");
                                            }
                                            sw.Write("        public uint" + xmlr.GetAttribute("name") + ";");
                                        }
                                        else lastWasstruct = false;
                                        break;
                                    }
                                case "enum":
                                    {
                                        goto case "enum32";
                                    }
                                case "enum32":
                                    {
                                        if (!lastWasstruct)
                                        {
                                            sw.WriteLine();
                                            for (int x = 0; x < i; x++)
                                            {
                                                sw.Write(" ");
                                            }
                                            sw.Write("        public int " + xmlr.GetAttribute("name") + "enum" + xmlr.GetAttribute("offset") + ";");
                                        }
                                        else lastWasstruct = false;
                                        break;
                                    }
                                case "enum16":
                                    {
                                        if (!lastWasstruct)
                                        {
                                            sw.WriteLine();
                                            for (int x = 0; x < i; x++)
                                            {
                                                sw.Write(" ");
                                            }
                                            sw.Write("        public short " + xmlr.GetAttribute("name") + "enum" + xmlr.GetAttribute("offset") + ";");
                                        }
                                        else lastWasstruct = false;
                                        break;
                                    }
                                case "enum8":
                                    {
                                        if (!lastWasstruct)
                                        {
                                            sw.WriteLine();
                                            for (int x = 0; x < i; x++)
                                            {
                                                sw.Write(" ");
                                            }
                                            sw.Write("        public byte " + xmlr.GetAttribute("name") + "enum" + xmlr.GetAttribute("offset") + ";");
                                        }
                                        else lastWasstruct = false;
                                        break;
                                    }
                                case "string32":
                                    {
                                        if (!lastWasstruct)
                                        {
                                            sw.WriteLine();
                                            for (int x = 0; x < i; x++)
                                            {
                                                sw.Write(" ");
                                            }
                                            sw.Write("        public string" + xmlr.GetAttribute("name") + ";");
                                        }
                                        else lastWasstruct = false;
                                        break; 
                                    }
                                case "struct":
                                    {
                                        sw.WriteLine();
                                        sw.WriteLine();
                                        sw.WriteLine("        public H3Reflexive<" + "Unkn" + xmlr.GetAttribute("offset") + "> " + xmlr.GetAttribute("name").ToLower() + ";");
                                        sw.WriteLine("        [Size(" + xmlr.GetAttribute("size") + ")]");
                                        sw.WriteLine("        public class " + "Unkn" + xmlr.GetAttribute("offset") + "  : Chunk");
                                        sw.WriteLine("        {");

                                        i += 4;

                                        Convert(ref xmlr, ref sw, i, lastWasstruct);
                                        break;
                                    }
                            }
                            break;
                        }
                    case "EndElement":
                        {
                            switch (xmlr.Name)
                            {

                                case "struct":
                                    {
                                        sw.WriteLine();
                                        sw.Write("        }");
                                        sw.WriteLine();
                                        i -= 4;
                                        lastWasstruct = true;
                                        break;
                                    }
                                case "plugin":
                                    {
                                        //Write .cs closing brackets
                                        sw.WriteLine();
                                        sw.WriteLine("    }");
                                        sw.WriteLine("}");
                                        break;
                                    }
                            }
                            break;
                        }
                }
            }
        }        
    }
}
