using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using Halo3Map.Data;
using System.Collections;
using System.Reflection;
using Halo3Map.Map;

namespace MetaEditor.Controls
{
    /// <summary>
    /// Holds controls for a Halo3 Reflexives values
    /// </summary>
    public partial class Reflexive : UserControl
    {
        /// <summary>
        /// Holds list of the reflexives chunks
        /// </summary>
        public IList list;
        /// <summary>
        /// Lets us access various information about the map file we are working with
        /// </summary>
        public Map map;
        /// <summary>
        /// Creates a new instance of Reflexive
        /// </summary>
        /// <param name="l">List of chunks</param>
        /// <param name="name">Name of relfex</param>
        /// <param name="Map">Map file to get information from</param>
        public Reflexive(IList l, string name, Map Map)
        {
            map = Map;
            InitializeComponent();
            list = l;
            label1.Text = name;
            for (int i = 0; i < l.Count; i++)
                cmbChunkSelect.Items.Add("Chunk # " + i);
        }
        /// <summary>
        /// Constructs a blank reflexive control to use with null reflexives
        /// </summary>
        /// <param name="name">Name of reflexive</param>
        public Reflexive(string name)
        {
            InitializeComponent();
            label1.Text = name;
            this.Enabled = false;
        }
        /// <summary>
        /// Reloads control with new value
        /// </summary>
        /// <param name="l"></param>
        public void Reload(IList l)
        {
            list = l;

            int chunk = cmbChunkSelect.SelectedIndex;

            cmbChunkSelect.Text = "";
            cmbChunkSelect.Items.Clear();

            for (int i = 0; i < l.Count; i++)
                cmbChunkSelect.Items.Add("Chunk # " + i);

            if (chunk != -1 && l.Count > 0)
            {
                this.Enabled = true;
                cmbChunkSelect.SelectedIndex = 0;
            }
        }

        /// <summary>
        /// Changes the currently selected chunk
        /// </summary>
        private void cmbChunkSelect_SelectedIndexChanged_1(object sender, EventArgs e)
        {
            if (panel2.Controls.Count == 0)
                LoadControls(cmbChunkSelect.SelectedIndex);
            else
                LoadChunk(cmbChunkSelect.SelectedIndex);
        }
        /// <summary>
        /// Loads controls + chunks values in the H3Reflexive control
        /// </summary>
        /// <param name="chunk">Chunk number to load</param>
        public void LoadControls(int chunk)
        {
            panel2.Controls.Clear();

            FieldInfo[] fields = list[chunk].GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);
            foreach (FieldInfo fi in fields)
            {
                if (fi.FieldType == typeof(byte))
                {
                    MetaEditor.Controls.Byte b = new MetaEditor.Controls.Byte((byte)fi.GetValue(list[chunk]), fi.Name);
                    b.Dock = DockStyle.Top;
                    panel2.Controls.Add(b);
                    panel2.Controls[panel2.Controls.Count - 1].BringToFront();
                }
                if (fi.FieldType == typeof(char))
                {
                    MetaEditor.Controls.String s = new MetaEditor.Controls.String((char)fi.GetValue(list[chunk]), fi.Name);
                    s.Dock = DockStyle.Top;
                    panel2.Controls.Add(s);
                    panel2.Controls[panel2.Controls.Count - 1].BringToFront();
                }
                else if (fi.FieldType == typeof(short))
                {
                    Short s = new Short((short)fi.GetValue(list[chunk]), fi.Name);
                    s.Dock = DockStyle.Top;
                    panel2.Controls.Add(s);
                    panel2.Controls[panel2.Controls.Count - 1].BringToFront();
                }
                else if (fi.FieldType == typeof(ushort))
                {
                    Short s = new Short((ushort)fi.GetValue(list[chunk]), fi.Name);
                    s.Dock = DockStyle.Top;
                    panel2.Controls.Add(s);
                    panel2.Controls[panel2.Controls.Count - 1].BringToFront();
                }
                else if (fi.FieldType == typeof(int))
                {
                    Int i = new Int((int)fi.GetValue(list[chunk]), fi.Name);
                    i.Dock = DockStyle.Top;
                    panel2.Controls.Add(i);
                    panel2.Controls[panel2.Controls.Count - 1].BringToFront();
                }
                else if (fi.FieldType == typeof(uint))
                {
                    Int i = new Int((uint)fi.GetValue(list[chunk]), fi.Name);
                    i.Dock = DockStyle.Top;
                    panel2.Controls.Add(i);
                    panel2.Controls[panel2.Controls.Count - 1].BringToFront();
                }
                else if (fi.FieldType == typeof(long))
                {
                    Int i = new Int((long)fi.GetValue(list[chunk]), fi.Name);
                    i.Dock = DockStyle.Top;
                    panel2.Controls.Add(i);
                    panel2.Controls[panel2.Controls.Count - 1].BringToFront();
                }
                else if (fi.FieldType == typeof(ulong))
                {
                    Int i = new Int((ulong)fi.GetValue(list[chunk]), fi.Name);
                    i.Dock = DockStyle.Top;
                    panel2.Controls.Add(i);
                    panel2.Controls[panel2.Controls.Count - 1].BringToFront();
                }
                else if (fi.FieldType == typeof(double))
                {
                    Float f = new Float((double)fi.GetValue(list[chunk]), fi.Name);
                    f.Dock = DockStyle.Top;
                    panel2.Controls.Add(f);
                    panel2.Controls[panel2.Controls.Count - 1].BringToFront();
                }
                else if (fi.FieldType == typeof(float))
                {
                    Float f = new Float((float)fi.GetValue(list[chunk]), fi.Name);
                    f.Dock = DockStyle.Top;
                    panel2.Controls.Add(f);
                    panel2.Controls[panel2.Controls.Count - 1].BringToFront();
                }
                else if (fi.FieldType.IsEnum)
                {
                    Type t = System.Enum.GetUnderlyingType(fi.FieldType);
                    if (t == typeof(byte))
                    {
                        MetaEditor.Controls.Enum e = new MetaEditor.Controls.Enum((byte)fi.GetValue(list[chunk]), System.Enum.GetNames(fi.FieldType), fi.Name);
                        e.Dock = DockStyle.Top;
                        panel2.Controls.Add(e);
                        panel2.Controls[panel2.Controls.Count - 1].BringToFront();
                    }
                    else if (t == typeof(short))
                    {
                        MetaEditor.Controls.Enum e = new MetaEditor.Controls.Enum((short)fi.GetValue(list[chunk]), System.Enum.GetNames(fi.FieldType), fi.Name);
                        e.Dock = DockStyle.Top;
                        panel2.Controls.Add(e);
                        panel2.Controls[panel2.Controls.Count - 1].BringToFront();
                    }
                    else if (t == typeof(int))
                    {
                        MetaEditor.Controls.Enum e = new MetaEditor.Controls.Enum((int)fi.GetValue(list[chunk]), System.Enum.GetNames(fi.FieldType), fi.Name);
                        e.Dock = DockStyle.Top;
                        panel2.Controls.Add(e);
                        panel2.Controls[panel2.Controls.Count - 1].BringToFront();
                    }
                    else if (t == typeof(long))
                    {
                        MetaEditor.Controls.Enum e = new MetaEditor.Controls.Enum((long)fi.GetValue(list[chunk]), System.Enum.GetNames(fi.FieldType), fi.Name);
                        e.Dock = DockStyle.Top;
                        panel2.Controls.Add(e);
                        panel2.Controls[panel2.Controls.Count - 1].BringToFront();
                    }
                }
                if (fi.FieldType == typeof(char[]))
                {
                    MetaEditor.Controls.String s = new MetaEditor.Controls.String((char[])fi.GetValue(list[chunk]), fi.Name);
                    s.Dock = DockStyle.Top;
                    panel2.Controls.Add(s);
                    panel2.Controls[panel2.Controls.Count - 1].BringToFront();
                }
                else if (fi.FieldType == typeof(string))
                {
                    MetaEditor.Controls.String s = new MetaEditor.Controls.String((string)fi.GetValue(list[chunk]), fi.Name);
                    s.Dock = DockStyle.Top;
                    panel2.Controls.Add(s);
                    panel2.Controls[panel2.Controls.Count - 1].BringToFront();
                }
                else if (fi.FieldType == typeof(Halo3Map.Data.StringID))
                {
                    Halo3Map.Data.StringID si = (Halo3Map.Data.StringID)fi.GetValue(list[chunk]);
                    StringID s = new MetaEditor.Controls.StringID(si.Index, fi.Name, map);
                    s.Dock = DockStyle.Top;
                    panel2.Controls.Add(s);
                    panel2.Controls[panel2.Controls.Count - 1].BringToFront();
                }
                else if (fi.FieldType == typeof(TagReference))
                {
                    TagReference t = (TagReference)fi.GetValue(list[chunk]);
                    Ident i = new Ident(t.Ident, fi.Name, map);
                    i.Dock = DockStyle.Top;
                    panel2.Controls.Add(i);
                    panel2.Controls[panel2.Controls.Count - 1].BringToFront();
                }
                else if (fi.FieldType.IsGenericType && fi.FieldType.GetGenericTypeDefinition() == typeof(H3Reflexive<>))
                {
                    IList l = (IList)fi.GetValue(list[chunk]);
                    Reflexive r = new Reflexive(l, fi.Name, map);
                    r.Dock = DockStyle.Top;
                    panel2.Controls.Add(r);
                    panel2.Controls[panel2.Controls.Count - 1].BringToFront();
                }
            }
        }
        /// <summary>
        /// Loads a chunks values in the H3Reflexive control
        /// </summary>
        /// <param name="chunk">Chunk Load</param>
        public void LoadChunk(int chunk)
        {
            FieldInfo[] fields = list[chunk].GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);
            foreach (FieldInfo fi in fields)
            {
                foreach (Control c in panel2.Controls)
                {
                    if (c.GetType() == typeof(MetaEditor.Controls.Byte) && ((MetaEditor.Controls.Byte)c).ReturnName() == fi.Name)
                        ((Byte)c).Reload((byte)fi.GetValue(list[chunk]));
                    else if (c.GetType() == typeof(Short) && ((Short)c).ReturnName() == fi.Name)
                    {
                        if (((Short)c).type == typeof(short))
                            ((Short)c).Reload((short)fi.GetValue(list[chunk]));
                        else if (((Short)c).type == typeof(short))
                            ((Short)c).Reload((ushort)fi.GetValue(list[chunk]));
                    }
                    else if (c.GetType() == typeof(Int) && ((Int)c).ReturnName() == fi.Name)
                    {
                        if (((Int)c).type == typeof(int))
                            ((Int)c).Reload((int)fi.GetValue(list[chunk]));
                        else if (((Int)c).type == typeof(uint))
                            ((Int)c).Reload((uint)fi.GetValue(list[chunk]));
                        else if (((Int)c).type == typeof(long))
                            ((Int)c).Reload((long)fi.GetValue(list[chunk]));
                        else if (((Int)c).type == typeof(ulong))
                            ((Int)c).Reload((ulong)fi.GetValue(list[chunk]));
                    }
                    else if (c.GetType() == typeof(Float) && ((Float)c).ReturnName() == fi.Name)
                    {
                        if (((Float)c).type == typeof(float))
                            ((Float)c).Reload((float)fi.GetValue(list[chunk]));
                        else if (((Float)c).type == typeof(double))
                            ((Float)c).Reload((double)fi.GetValue(list[chunk]));
                    }
                    else if (c.GetType() == typeof(MetaEditor.Controls.Enum) && ((MetaEditor.Controls.Enum)c).ReturnName() == fi.Name)
                    {
                        Type t = System.Enum.GetUnderlyingType(fi.FieldType);
                        if (((MetaEditor.Controls.Enum)c).type == typeof(byte))
                            ((MetaEditor.Controls.Enum)c).Reload((byte)fi.GetValue(list[chunk]), System.Enum.GetNames(fi.FieldType));
                        else if (((MetaEditor.Controls.Enum)c).type == typeof(short))
                            ((MetaEditor.Controls.Enum)c).Reload((short)fi.GetValue(list[chunk]), System.Enum.GetNames(fi.FieldType));
                        else if (((MetaEditor.Controls.Enum)c).type == typeof(int))
                            ((MetaEditor.Controls.Enum)c).Reload((int)fi.GetValue(list[chunk]), System.Enum.GetNames(fi.FieldType));
                        else if (((MetaEditor.Controls.Enum)c).type == typeof(long))
                            ((MetaEditor.Controls.Enum)c).Reload((long)fi.GetValue(list[chunk]), System.Enum.GetNames(fi.FieldType));
                    }
                    else if (c.GetType() == typeof(MetaEditor.Controls.String) && ((MetaEditor.Controls.String)c).ReturnName() == fi.Name)
                    {
                        if (((MetaEditor.Controls.String)c).t == typeof(string))
                            ((MetaEditor.Controls.String)c).Reload((string)fi.GetValue(list[chunk]));
                        else if (((MetaEditor.Controls.String)c).t == typeof(char))
                            ((MetaEditor.Controls.String)c).Reload((char)fi.GetValue(list[chunk]));
                        else if (((MetaEditor.Controls.String)c).t == typeof(char[]))
                            ((MetaEditor.Controls.String)c).Reload((char[])fi.GetValue(list[chunk]));
                    }
                    else if (c.GetType() == typeof(Ident) && ((Ident)c).ReturnName() == fi.Name)
                    {
                        TagReference t = (TagReference)fi.GetValue(list[chunk]);
                        ((Ident)c).Reload(t.Ident);
                    }
                    else if (c.GetType() == typeof(Reflexive) && ((Reflexive)c).ReturnName() == fi.Name)
                    {
                        IList l = (IList)fi.GetValue(list[chunk]);
                        ((Reflexive)c).Reload(l);
                    }
                }
            }
        }
        /// <summary>
        /// Returns the name of the reflexive
        /// </summary>
        public string ReturnName()
        {
            return label1.Text.Replace(' ', '_');
        }
        /// <summary>
        /// Returns a list of the reflexives chunks
        /// </summary>
        /// <returns></returns>
        public IList ReturnValue()
        {
            if (cmbChunkSelect.SelectedIndex != -1)
            {
                Save(cmbChunkSelect.SelectedIndex);
            }
            return list;
        }
        /// <summary>
        /// Saves values of controls
        /// </summary>
        /// <param name="chunk"></param>
        private void Save(int chunk)
        {
            FieldInfo[] fields = list[chunk].GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);
            foreach (FieldInfo fi in fields)
            {
                foreach (Control c in panel2.Controls)
                {
                    if (c.GetType() == typeof(MetaEditor.Controls.Byte) && ((MetaEditor.Controls.Byte)c).ReturnName() == fi.Name)
                    {
                        fi.SetValue(list[chunk], ((MetaEditor.Controls.Byte)c).ReturnValue());
                    }
                    else if (c.GetType() == typeof(Short) && ((Short)c).ReturnName() == fi.Name)
                    {
                        fi.SetValue(list[chunk], ((Short)c).ReturnValue());
                    }
                    else if (c.GetType() == typeof(Int) && ((Int)c).ReturnName() == fi.Name)
                    {
                        fi.SetValue(list[chunk], ((Int)c).ReturnValue());
                    }
                    else if (c.GetType() == typeof(Float) && ((Float)c).ReturnName() == fi.Name)
                    {
                        fi.SetValue(list[chunk], ((Float)c).ReturnValue());
                    }
                    else if (c.GetType() == typeof(MetaEditor.Controls.Enum) && ((MetaEditor.Controls.Enum)c).ReturnName() == fi.Name)
                    {
                        if (((MetaEditor.Controls.Enum)c).type == typeof(byte))
                        {
                            fi.SetValue(list[chunk], ((MetaEditor.Controls.Enum)c).ReturnByteValue());
                        }
                        if (((MetaEditor.Controls.Enum)c).type == typeof(short))
                        {
                            fi.SetValue(list[chunk], ((MetaEditor.Controls.Enum)c).ReturnShortValue());
                        }
                        if (((MetaEditor.Controls.Enum)c).type == typeof(int))
                        {
                            fi.SetValue(list[chunk], ((MetaEditor.Controls.Enum)c).ReturnIntValue());
                        }
                        if (((MetaEditor.Controls.Enum)c).type == typeof(long))
                        {
                            fi.SetValue(list[chunk], ((MetaEditor.Controls.Enum)c).ReturnLongValue());
                        }
                    }
                    else if (c.GetType() == typeof(MetaEditor.Controls.String) && ((MetaEditor.Controls.String)c).ReturnName() == fi.Name)
                    {
                        if (((MetaEditor.Controls.String)c).t == typeof(string))
                            fi.SetValue(list[chunk], ((MetaEditor.Controls.String)c).ReturnStringValue());
                        else if (((MetaEditor.Controls.String)c).t == typeof(char))
                            fi.SetValue(list[chunk], ((MetaEditor.Controls.String)c).ReturnCharValue());
                        else if (((MetaEditor.Controls.String)c).t == typeof(char[]))
                            fi.SetValue(list[chunk], ((MetaEditor.Controls.String)c).ReturnCharArrayValue());

                    }
                    else if (c.GetType() == typeof(Ident) && ((Ident)c).ReturnName() == fi.Name)
                    {
                        fi.SetValue(list[chunk], ((Ident)c).ReturnValue());
                    }
                    else if (c.GetType() == typeof(Reflexive) && ((Reflexive)c).ReturnName() == fi.Name)
                    {
                        fi.SetValue(list[chunk], ((Reflexive)c).ReturnValue());
                    }
                }
            }
        }
        /// <summary>
        /// Expands and Contracts the control
        /// </summary>
        private void btnExpandContract_Click_1(object sender, EventArgs e)
        {
            if (btnExpandContract.Text == "+")
            {
                btnExpandContract.Text = "-";
                this.Height = this.PreferredSize.Height;
            }
            else if (btnExpandContract.Text == "-")
            {
                btnExpandContract.Text = "+";
                this.Height = 41;
            }
            RecursiveResize(false);
        }

        public void RecursiveResize(bool expand)
        {
            // Lengthen if needed.
            if (expand)
                this.Height = this.PreferredSize.Height;

            // Now figure the parent and call the resize again.
            System.Type pType = this.Parent.GetType();
            if (pType == typeof(Panel))
            {
                (this.Parent.Parent as Reflexive).
                    RecursiveResize(true);
            }
            else if (pType == typeof(DevComponents.DotNetBar.Ribbon.RibbonClientPanel))
            {
                (this.Parent.Parent as MetaEditorPanel).
                    MetaEditorPanel_Resize(null, EventArgs.Empty);
            }
        }

    }
}
