using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using HaloObjects;
using System.Reflection;
using DevComponents.DotNetBar;
using DevExpress;
using DevExpress.XtraTab;
using System.Collections;
using DevExpress.XtraNavBar;

/*
 * Updated a lot of code, I still need to figure out how to tell if a reflexive has 0 Chunks,
 * although I need to double check there is a reflexive in this tag that has 0 Chunks. - Done.
 * 
 * I need to remove reflexive instance, and replace all references of it in LoadControls()
 * to list. - Done.
 * 
 * Need to make one general control for number values, and update reloading code. - Done.
 * 
 * Lastly need to break away from the FieldInfo/Chunk code. - Done.
 * 
 * Need to add Header to tags, also add Tag Reference/StringID Table at the end and make them - 100% - Done.
 * index based.
 * 
 * Still need to make plugins property based, but I better make controls loading working at 100% - Depreciated.
 * first.
 * 
 * Also susppend the layout on form load, and parse some dam arguments. - Done.
 * 
 * Make Debug Output static in some generic library to monitor stuff. - Depreciated.
 * 
 * Make all controls spaced to the same amount to look nice.
 * 
 * Break away from offsets, and maked an enabled attribute - Done.
 * 
 * Fix all the reloading and saving code in controls once generic value control is made and other - Done.
 * control problems are fixed.
 * 
 * Fix Reflexive reflexive Based Code. - Done.
 * 
 * Fix TagReference Globals ussage Code. - Done.
 * 
 * Fix New Project Dialog Code. - 50%
 * 
 * Fix Decompiling Code. - Done.
 * 
 * Optimize Decompiling. - Done.
 * 
 * Make a nice Loading bar for Decompiling. - Done.
 * 
 * Need to finish Saving code in Plugin class. - 90%
 * 
 * Make MetaNodes Clonable. - Done.
 * 
 * Add and debug the rest of the plugin classes. - Done.
 * 
 * Fix the open Tab Issue with Tag Reference Controls. - Done.
 * 
 * Extract Raw Data apon Decompilication. - Done.
 * 
 * Get TagTree to work soon. - Done.
 * 
 * Get Login Script Done to give Beta out. - Done.
*/

namespace HaloControls
{
    public partial class Reflexive : UserControl
    {
        public int Index;
        bool Expanded = true, Loading = true;
        XtraTabControl tabs;
        HaloObjects.Reflexive reflexive;

        public Reflexive(string Description, HaloObjects.Reflexive reflexive, int Index)
        {
            InitializeComponent();
            this.Index = Index;
            this.reflexive = reflexive;
            groupControl1.Text = Description;
        }

        private void Reflexive_Load(object sender, EventArgs ea)
        {
            //Collapse Panel
            button1_Click(null, null);

            //Find Tabs
            object parent = this.Parent;
            while (tabs == null)
            {
                if (parent.GetType() == typeof(XtraTabControl))
                    tabs = (XtraTabControl)parent;
                else
                    parent = ((Control)parent).Parent;
            }

            //Load Controls
            if (reflexive.GetChunkCount() > 0)
            {
                LoadControls(true);
                for (int i = 0; i < reflexive.GetChunkCount(); i++)
                {
                    comboBox1.Items.Add(i.ToString());
                }
                try { comboBox1.SelectedIndex = 0; }
                catch { }
            }
            else
            {
                LoadControls(false);
                panelControl2.Enabled = false;
                btnExpand.Enabled = false;
            }

            //Done
            Loading = false;
        }

        public void LoadControls(bool Read)
        {
            //Suspend the Layout
            string name = groupControl1.Text;
            panelControl2.SuspendLayout();
            
            //Add Controls
            List<Control> Controls = new List<Control>();
            MetaNode[] Fields = (MetaNode[])reflexive.GetValue();
            for (int i = 0; i < Fields.Length; i++)
            {
                if (Fields[i].GetType() == typeof(HaloObjects.Value))
                {
                    Value v = new Value(((HaloObjects.Value)Fields[i]).GetName(), ((HaloObjects.Value)Fields[i]).GetValue(), i);
                    v.Dock = DockStyle.Top;
                    Controls.Add(v);
                }
                else if (Fields[i].GetType() == typeof(HaloObjects.Bitmask))
                {
                    Bitmask b = new Bitmask(((HaloObjects.Bitmask)Fields[i]).GetName(), ((HaloObjects.Bitmask)Fields[i]).GetOptions(), ((HaloObjects.Bitmask)Fields[i]).GetValue(), ((HaloObjects.Bitmask)Fields[i]).GetBitCount(), i);
                    b.Dock = DockStyle.Top;
                    Controls.Add(b);
                }
                else if (Fields[i].GetType() == typeof(HaloObjects.Enum))
                {
                    Enum b = new Enum(((HaloObjects.Enum)Fields[i]).GetName(), ((HaloObjects.Enum)Fields[i]).GetOptions(), ((HaloObjects.Enum)Fields[i]).GetValue(), ((HaloObjects.Enum)Fields[i]).GetBitCount(), i);
                    b.Dock = DockStyle.Top;
                    Controls.Add(b);
                }
                else if (Fields[i].GetType() == typeof(String32))
                {
                    String s = new String(((HaloObjects.String32)Fields[i]).GetName(), ((HaloObjects.String32)Fields[i]).GetValue(), 32, i);
                    s.Dock = DockStyle.Top;
                    Controls.Add(s);
                }
                else if (Fields[i].GetType() == typeof(String256))
                {
                    String s = new String(((HaloObjects.String256)Fields[i]).GetName(), ((HaloObjects.String256)Fields[i]).GetValue(), 256, i);
                    s.Dock = DockStyle.Top;
                    Controls.Add(s);
                }
                else if (Fields[i].GetType() == typeof(Unicode64))
                {
                    String s = new String(((HaloObjects.Unicode64)Fields[i]).GetName(), ((HaloObjects.Unicode64)Fields[i]).GetValue(), 32, i);
                    s.Dock = DockStyle.Top;
                    Controls.Add(s);
                }
                else if (Fields[i].GetType() == typeof(Unicode256))
                {
                    String s = new String(((HaloObjects.Unicode256)Fields[i]).GetName(), ((HaloObjects.Unicode256)Fields[i]).GetValue(), 128, i);
                    s.Dock = DockStyle.Top;
                    Controls.Add(s);
                }
                else if (Fields[i].GetType() == typeof(StringID))
                {
                    String s = new String(((HaloObjects.StringID)Fields[i]).GetName(), ((HaloObjects.StringID)Fields[i]).GetValue(), 128, i);
                    s.Dock = DockStyle.Top;
                    Controls.Add(s);
                }
                else if (Fields[i].GetType() == typeof(HaloObjects.TagReference))
                {
                    TagReference t = new TagReference(((HaloObjects.TagReference)Fields[i]).GetName(), (string)((HaloObjects.TagReference)Fields[i]).GetValue(), i);
                    t.Dock = DockStyle.Top;
                    Controls.Add(t);
                }
                else if (Fields[i].GetType() == typeof(HaloObjects.Ident))
                {
                    TagReference t = new TagReference(((HaloObjects.Ident)Fields[i]).GetName(), (string)((HaloObjects.Ident)Fields[i]).GetValue(), i);
                    t.Dock = DockStyle.Top;
                    Controls.Add(t);
                }
                else if (Fields[i].GetType() == typeof(HaloObjects.Reflexive))
                {
                    Reflexive r = new Reflexive(((HaloObjects.Reflexive)Fields[i]).GetName(), ((HaloObjects.Reflexive)Fields[i]), i);
                    r.Dock = DockStyle.Top;
                    Controls.Add(r);
                }
            }

            //Load them in reverse
            Controls.Add(new EndReflexive(groupControl1.Text, DockStyle.Top));
            Controls.Reverse();
            panelControl2.Controls.AddRange(Controls.ToArray());

            //Resume
            panelControl2.ResumeLayout();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (Expanded)
            {
                panelControl2.Visible = false;
                Expanded = false;
            }
            else
            {
                panelControl2.Visible = true;
                Expanded = true;
            }
        }

        private void btnAddChunk_Click(object sender, EventArgs e)
        {
            // Add Chunk
            reflexive.AddChunk();

            // Update ComboBox
            comboBox1.Items.Add(comboBox1.Items.Count.ToString());
            comboBox1.SelectedIndex = comboBox1.Items.Count - 1;

            // Make sure the Panel Is Enabled
            panelControl2.Enabled = true;
            panelControl2.Visible = true;
            Expanded = true;
            btnExpand.Enabled = true;
        }

        private void btnDeleteChunk_Click(object sender, EventArgs e)
        {
            // Remove Chunk
            reflexive.DeleteChunk();

            // Update ComboBox
            int OldIndex = comboBox1.SelectedIndex;
            comboBox1.Items.Clear();
            comboBox1.Text = "";
            for (int i = 0; i < reflexive.GetChunkCount(); i++)
            {
                comboBox1.Items.Add(i.ToString());
            }

            // Selete Near Index
            try { comboBox1.SelectedIndex = OldIndex; }
            catch
            {
                try { comboBox1.SelectedIndex = OldIndex - 1; }
                catch { comboBox1.SelectedIndex = 0; }
            }

            // Double Check
            if (reflexive.GetChunkCount() == 0)
            {
                panelControl2.Visible = false;
                Expanded = false;
            }
        }

        private void btnDeleteAllChunks_Click(object sender, EventArgs e)
        {
            // Update Form
            comboBox1.Items.Clear();
            comboBox1.Text = "";
            panelControl2.Enabled = false;
            Expanded = false;

            // Clear Reflexive
            reflexive.DeleteAll();
        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            //Double Check
            if (Loading)
                return;

            // Save Old Values
            int Field = 0;
            MetaNode[] fields = (MetaNode[])reflexive.GetValue();
            for (int i = 0; i < panelControl2.Controls.Count; i++)
            {
                #region Save Old Values
                string type = panelControl2.Controls[i].GetType().Name;
                switch (type)
                {
                    case "Value":
                        {
                            Field = ((Value)(panelControl2.Controls[i])).Index;
                            fields[Field].SetValue(((Value)(panelControl2.Controls[i])).Save());
                            break;
                        }
                    case "String":
                        {
                            Field = ((String)(panelControl2.Controls[i])).Index;
                            fields[Field].SetValue(((String)(panelControl2.Controls[i])).Save());
                            break;
                        }
                    case "Enum":
                        {
                            Field = ((Enum)(panelControl2.Controls[i])).Index;
                            fields[Field].SetValue(((Enum)(panelControl2.Controls[i])).Save());
                            break;
                        }
                    case "Bitmask":
                        {
                            Field = ((Bitmask)(panelControl2.Controls[i])).Index;
                            fields[Field].SetValue(((Bitmask)(panelControl2.Controls[i])).Save());
                            break;
                        }
                    case "Ident":
                    case "TagReference":
                        {
                            Field = ((TagReference)(panelControl2.Controls[i])).Index;
                            fields[Field].SetValue(((TagReference)(panelControl2.Controls[i])).Save());
                            break;
                        }
                    case "Reflexive":
                        {
                            Field = ((Reflexive)(panelControl2.Controls[i])).Index;
                            fields[Field].SetValue(((Reflexive)(panelControl2.Controls[i])).Save());
                            break;
                        }
                }
                #endregion
            }

            reflexive.SetValue(fields);

            // Set Index
            reflexive.ChangeIndex(comboBox1.SelectedIndex);

            // Update
            Field = 0;
            fields = (MetaNode[])reflexive.GetValue();
            panelControl2.SuspendLayout();
            for (int i = 0; i < panelControl2.Controls.Count; i++)
            {
                #region Reload Values
                string type = panelControl2.Controls[i].GetType().Name;
                switch (type)
                {
                    case "Value":
                        {
                            Field = ((Value)(panelControl2.Controls[i])).Index;
                            ((Value)(panelControl2.Controls[i])).Reload(fields[Field].GetValue());
                            break;
                        }
                    case "String":
                        {
                            Field = ((String)(panelControl2.Controls[i])).Index;
                            ((String)(panelControl2.Controls[i])).Reload(fields[Field].GetValue());
                            break;
                        }
                    case "Enum":
                        {
                            Field = ((Enum)(panelControl2.Controls[i])).Index;
                            ((Enum)(panelControl2.Controls[i])).Reload(fields[Field].GetValue());
                            break;
                        }
                    case "Bitmask":
                        {
                            Field = ((Bitmask)(panelControl2.Controls[i])).Index;
                            ((Bitmask)(panelControl2.Controls[i])).Reload(fields[Field].GetValue());
                            break;
                        }
                    case "Ident":
                    case "TagReference":
                        {
                            Field = ((TagReference)(panelControl2.Controls[i])).Index;
                            ((TagReference)(panelControl2.Controls[i])).Reload(fields[Field].GetValue());
                            break;
                        }
                    case "Reflexive":
                        {
                            Field = ((Reflexive)(panelControl2.Controls[i])).Index;
                            ((Reflexive)(panelControl2.Controls[i])).Reload(fields[Field]);
                            break;
                        }
                }
                #endregion
            }
            panelControl2.ResumeLayout();
        }

        public void Reload(object Value)
        {
            reflexive = (HaloObjects.Reflexive)Value;
            if (reflexive.GetChunkCount() > 0)
            {
                //Set Loading
                Loading = true;

                //Change Index
                reflexive.ChangeIndex(0);
                comboBox1.Items.Clear();
                for (int i = 0; i < reflexive.GetChunkCount(); i++)
                {
                    comboBox1.Items.Add(i.ToString());
                }
                comboBox1.SelectedIndex = 0;

                //Load Controls
                MetaNode[] fields = (MetaNode[])reflexive.GetValue();
                int Field = 0;

                for (int i = 0; i < panelControl2.Controls.Count; i++)
                {
                    #region Reload Values
                    if (panelControl2.Controls[i].GetType() == typeof(Value))
                    {
                        Field = ((Value)(panelControl2.Controls[i])).Index;
                        ((Value)(panelControl2.Controls[i])).Reload(fields[Field].GetValue());
                    }
                    else if (panelControl2.Controls[i].GetType() == typeof(String))
                    {
                        Field = ((String)(panelControl2.Controls[i])).Index;
                        ((String)(panelControl2.Controls[i])).Reload(fields[Field].GetValue());
                    }
                    else if (panelControl2.Controls[i].GetType() == typeof(Enum))
                    {
                        Field = ((Enum)(panelControl2.Controls[i])).Index;
                        ((Enum)(panelControl2.Controls[i])).Reload(fields[Field].GetValue());
                    }
                    else if (panelControl2.Controls[i].GetType() == typeof(Bitmask))
                    {
                        Field = ((Bitmask)(panelControl2.Controls[i])).Index;
                        ((Bitmask)(panelControl2.Controls[i])).Reload(fields[Field].GetValue());
                    }
                    else if (panelControl2.Controls[i].GetType() == typeof(TagReference))
                    {
                        Field = ((TagReference)(panelControl2.Controls[i])).Index;
                        ((TagReference)(panelControl2.Controls[i])).Reload(fields[Field].GetValue());
                    }
                    else if (panelControl2.Controls[i].GetType() == typeof(Reflexive))
                    {
                        Field = ((Reflexive)(panelControl2.Controls[i])).Index;
                        ((Reflexive)(panelControl2.Controls[i])).Reload(fields[Field]);
                    }
                    #endregion
                }

                Loading = false;
            }
        }

        public object Save()
        {
            // Sanity Check
            if (reflexive.GetChunkCount() == 0)
                return reflexive;

            // Save Values
            int Field = 0;
            MetaNode[] fields = (MetaNode[])reflexive.GetValue();
            for (int i = 0; i < panelControl2.Controls.Count; i++)
            {
                #region Save Values
                if (panelControl2.Controls[i].GetType() == typeof(Value))
                {
                    Field = ((Value)(panelControl2.Controls[i])).Index;
                    fields[Field].SetValue(((Value)(panelControl2.Controls[i])).Save());
                }
                else if (panelControl2.Controls[i].GetType() == typeof(String))
                {
                    Field = ((String)(panelControl2.Controls[i])).Index;
                    fields[Field].SetValue(((String)(panelControl2.Controls[i])).Save());
                }
                else if (panelControl2.Controls[i].GetType() == typeof(Enum))
                {
                    Field = ((Enum)(panelControl2.Controls[i])).Index;
                    fields[Field].SetValue(((Enum)(panelControl2.Controls[i])).Save());
                }
                else if (panelControl2.Controls[i].GetType() == typeof(Bitmask))
                {
                    Field = ((Bitmask)(panelControl2.Controls[i])).Index;
                    fields[Field].SetValue(((Bitmask)(panelControl2.Controls[i])).Save());
                }
                else if (panelControl2.Controls[i].GetType() == typeof(TagReference))
                {
                    Field = ((TagReference)(panelControl2.Controls[i])).Index;
                    fields[Field].SetValue(((TagReference)(panelControl2.Controls[i])).Save());
                }
                else if (panelControl2.Controls[i].GetType() == typeof(Reflexive))
                {
                    Field = ((Reflexive)(panelControl2.Controls[i])).Index;
                    fields[Field].SetValue(((Reflexive)(panelControl2.Controls[i])).Save());
                }
                #endregion
            }

            reflexive.SetValue(fields);
            return reflexive;
        }
    }
}
