using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HaloObjects;
using System.IO;
using System.Windows.Forms;
using System.Collections;
using DevExpress.XtraTab;
using System.Diagnostics;
using Global;

namespace HaloControls
{
    public class Plugin
    {
        public Meta Layout;
        public XtraTabControl tabs;

        public Plugin(string Class, XtraTabControl Tabs)
        {
            tabs = Tabs;

            #region Tags
            // Get Default Class and Layout
            switch (Class)
            {
                case "sound_effect_template":
                case "(<fx>) Sound Effect Template":
                    Layout = new Meta(new HaloPlugins.Xbox.fx().Fields.ToArray(), "<fx>", "sound_effect_template", 28);
                    break;
                case "ai_dialogue_globals":
                case "(adlg) AI Dialogue Globals":
                    Layout = new Meta(new HaloPlugins.Xbox.adlg().Fields.ToArray(), "adlg", "ai_dialogue_globals", 44);
                    break;
                case "antenna":
                case "(ant!) Antenna":
                    Layout = new Meta(new HaloPlugins.Xbox.ant().Fields.ToArray(), "ant!", "antenna", 160);
                    break;
                case "biped":
                case "(bipd) Biped":
                    Layout = new Meta(new HaloPlugins.Xbox.bipd().Fields.ToArray(), "bipd", "biped", 788);
                    break;
                case "bitmap":
                case "(bitm) Bitmap":
                    Layout = new Meta(new HaloPlugins.Xbox.bitm().Fields.ToArray(), "bitm", "bitmap", 76);
                    break;
                case "crate":
                case "(bloc) Crate":
                    Layout = new Meta(new HaloPlugins.Xbox.bloc().Fields.ToArray(), "bloc", "crate", 192);
                    break;
                case "breakable_surface":
                case "(bsdt) Breakable Surface":
                    Layout = new Meta(new HaloPlugins.Xbox.bsdt().Fields.ToArray(), "bsdt", "breakable_surface", 32);
                    break;
                case "character":
                case "(char) Character":
                    Layout = new Meta(new HaloPlugins.Xbox.Char().Fields.ToArray(), "char", "character", 236);
                    break;
                case "cloth":
                case "(clwd) Cloth":
                    Layout = new Meta(new HaloPlugins.Xbox.clwd().Fields.ToArray(), "clwd", "cloth", 108);
                    break;
                case "collision_model":
                case "(coll) Collision Model":
                    Layout = new Meta(new HaloPlugins.Xbox.coll().Fields.ToArray(), "coll", "collision_model", 52);
                    break;
                case "color_table":
                case "(colo) Color Table":
                    Layout = new Meta(new HaloPlugins.Xbox.colo().Fields.ToArray(), "colo", "color_table", 8);
                    break;
                case "contrail":
                case "(cont) Contrail":
                    Layout = new Meta(new HaloPlugins.Xbox.cont().Fields.ToArray(), "cont", "contrail", 240);
                    break;
                case "creature":
                case "(crea) Creature":
                    Layout = new Meta(new HaloPlugins.Xbox.crea().Fields.ToArray(), "crea", "creature", 384);
                    break;
                case "control":
                case "(ctrl) Control":
                    Layout = new Meta(new HaloPlugins.Xbox.ctrl().Fields.ToArray(), "ctrl", "control", 320);
                    break;
                case "decal":
                case "(deca) Decal":
                    Layout = new Meta(new HaloPlugins.Xbox.deca().Fields.ToArray(), "deca", "decal", 172);
                    break;
                case "decorator":
                case "(DECR) Decorator":
                    Layout = new Meta(new HaloPlugins.Xbox.DECR().Fields.ToArray(), "DECR", "decorator", 108);
                    break;
                case "effect":
                case "(effe) Effect":
                    Layout = new Meta(new HaloPlugins.Xbox.effe().Fields.ToArray(), "effe", "effect", 48);
                    break;
                case "screen_effect":
                case "(egor) Screen Effect":
                    Layout = new Meta(new HaloPlugins.Xbox.egor().Fields.ToArray(), "egor", "screen_effect", 144);
                    break;
                case "equipment":
                case "(eqip) Equipment":
                    Layout = new Meta(new HaloPlugins.Xbox.eqip().Fields.ToArray(), "eqip", "equipment", 316);
                    break;
                case "fog":
                case "(fog) Fog":
                    Layout = new Meta(new HaloPlugins.Xbox.fog().Fields.ToArray(), "fog ", "fog", 96);
                    break;
                case "material_effect":
                case "(foot) Material Effect":
                    Layout = new Meta(new HaloPlugins.Xbox.foot().Fields.ToArray(), "foot", "material_effect", 8);
                    break;
                case "fog_patch":
                case "(fpch) Fog Path":
                    Layout = new Meta(new HaloPlugins.Xbox.fpch().Fields.ToArray(), "fpch", "fog_patch", 80);
                    break;
                case "garbage":
                case "(garb) Garbage":
                    Layout = new Meta(new HaloPlugins.Xbox.garb().Fields.ToArray(), "garb", "garbage", 468);
                    break;
                case "global_lighting":
                case "(gldf) Global Lighting":
                    Layout = new Meta(new HaloPlugins.Xbox.gldf().Fields.ToArray(), "gldf", "global_lighting", 8);
                    break;
                case "multiplayer_variant_settings":
                case "(goof) Multiplayer Variant Settings":
                    Layout = new Meta(new HaloPlugins.Xbox.goof().Fields.ToArray(), "goof", "multiplayer_variant_settings", 368);
                    break;
                case "object_properties":
                case "(hlmt) Object Properties":
                    Layout = new Meta(new HaloPlugins.Xbox.hlmt().Fields.ToArray(), "hlmt", "object_properties", 252);
                    break;
                case "hud_globals":
                case "(hudg) HUD Globals":
                    Layout = new Meta(new HaloPlugins.Xbox.hudg().Fields.ToArray(), "hudg", "hud_globals", 1160);
                    break;
                case "item_collection":
                case "(itmc) Item Collection":
                    Layout = new Meta(new HaloPlugins.Shared.ItemCollection().Fields.ToArray(), "itmc", "item_collection", 12);
                    break;
                case "model_animation_graph":
                case "(jmad) Model Animation Graph":
                    Layout = new Meta(new HaloPlugins.Xbox.jmad().Fields.ToArray(), "jmad", "model_animation_graph", 188);
                    break;
                case "damage_effect":
                case "(jpt!) Damage Effect":
                    Layout = new Meta(new HaloPlugins.Xbox.jpt().Fields.ToArray(), "jpt!", "damage_effect", 200);
                    break;
                case "lens_flare":
                case "(lens) Lens Flare":
                    Layout = new Meta(new HaloPlugins.Xbox.lens().Fields.ToArray(), "lens", "lens_flare", 100);
                    break;
                case "light":
                case "(ligh) Light":
                    Layout = new Meta(new HaloPlugins.Xbox.ligh().Fields.ToArray(), "ligh", "light", 228);
                    break;
                case "looping_sound":
                case "(lsnd) Looping Sound":
                    Layout = new Meta(new HaloPlugins.Xbox.lsnd().Fields.ToArray(), "lsnd", "looping_sound", 44);
                    break;
                case "lightmap":
                case "(ltmp) Lightmap":
                    Layout = new Meta(new HaloPlugins.Xbox.ltmp().Fields.ToArray(), "ltmp", "lightmap", 260);
                    break;
                case "machine":
                case "(mach) Machine":
                    Layout = new Meta(new HaloPlugins.Xbox.mach().Fields.ToArray(), "mach", "machine", 308);
                    break;
                case "match_globals":
                case "(matg) Match Globals":
                    Layout = new Meta(new HaloPlugins.Xbox.matg().Fields.ToArray(), "matg", "match_globals", 644);
                    break;
                case "ai_mission_dialogue":
                case "(mdlg) AI Mission Dialogue":
                    Layout = new Meta(new HaloPlugins.Xbox.mdlg().Fields.ToArray(), "mdlg", "ai_mission_dialogue", 8);
                    break;
                case "light_volume":
                case "(MGS2) Light Volume":
                    Layout = new Meta(new HaloPlugins.Xbox.MGS2().Fields.ToArray(), "MGS2", "light_volume", 16);
                    break;
                case "render_model":
                case "(mode) Render Model":
                    Layout = new Meta(new HaloPlugins.Xbox.mode().Fields.ToArray(), "mode", "render_model", 132);
                    break;
                case "multiplayer_globals":
                case "(mulg) Multiplayer Globals":
                    Layout = new Meta(new HaloPlugins.Xbox.mulg().Fields.ToArray(), "mulg", "multiplayer_globals", 16);
                    break;
                case "hud_interface":
                case "(nhdt) HUD Interface":
                    Layout = new Meta(new HaloPlugins.Xbox.nhdt().Fields.ToArray(), "nhdt", "hud_interface", 40);
                    break;
                case "physics_model":
                case "(phmo) Physics Model":
                    Layout = new Meta(new HaloPlugins.Xbox.phmo().Fields.ToArray(), "phmo", "physics_model", 272);
                    break;
                case "physics":
                case "(phys) Physics":
                    Layout = new Meta(new HaloPlugins.Xbox.phys().Fields.ToArray(), "phys", "physics", 116);
                    break;
                case "particle_physics":
                case "(pmov) Particle Physics":
                    Layout = new Meta(new HaloPlugins.Xbox.pmov().Fields.ToArray(), "pmov", "particle_physics", 20);
                    break;
                case "point_physics":
                case "(pphy) Point Physics":
                    Layout = new Meta(new HaloPlugins.Xbox.pphy().Fields.ToArray(), "pphy", "point_physics", 64);
                    break;
                case "projectile":
                case "(proj) Projectile":
                    Layout = new Meta(new HaloPlugins.Xbox.proj().Fields.ToArray(), "proj", "projectile", 420);
                    break;
                case "particle":
                case "(prt3) Particle":
                    Layout = new Meta(new HaloPlugins.Xbox.prt3().Fields.ToArray(), "prt3", "particle", 188);
                    break;
                case "particle_model":
                case "(PRTM) Particle Model":
                    Layout = new Meta(new HaloPlugins.Xbox.PRTM().Fields.ToArray(), "PRTM", "particle_model", 220);
                    break;
                case "scenario_structure_bsp":
                case "(sbsp) Scenario Structure Bsp":
                    Layout = new Meta(new HaloPlugins.Xbox.sbsp().Fields.ToArray(), "sbsp", "scenario_structure_bsp", 588);
                    break;
                case "scenery":
                case "(scen) Scenery":
                    Layout = new Meta(new HaloPlugins.Xbox.scen().Fields.ToArray(), "scen", "scenery", 196);
                    break;
                case "scenario":
                case "(scnr) Scenario":
                    Layout = new Meta(new HaloPlugins.Xbox.scnr().Fields.ToArray(), "scnr", "scenario", 992);
                    break;
                case "sound_effect_collection":
                case "(sfx+) Sound Effect Collection":
                    Layout = new Meta(new HaloPlugins.Xbox.sfx().Fields.ToArray(), "sfx+", "sound_effect_collection", 8);
                    break;
                case "shader":
                case "(shad) Shader":
                    Layout = new Meta(new HaloPlugins.Xbox.shad().Fields.ToArray(), "shad", "shader", 84);//84
                    break;
                case "ui_option":
                case "(sily) UI Option":
                    Layout = new Meta(new HaloPlugins.Xbox.sily().Fields.ToArray(), "sily", "ui_option", 36);
                    break;
                case "user_interface_list_skin_definition":
                case "(skin) User Interface List Skin Definition":
                    Layout = new Meta(new HaloPlugins.Xbox.skin().Fields.ToArray(), "skin", "user_interface_list_skin_definition", 60);
                    break;
                case "sky":
                case "(sky) Sky":
                    Layout = new Meta(new HaloPlugins.Xbox.sky().Fields.ToArray(), "sky ", "sky", 172);
                    break;
                case "sound_class":
                case "(sncl) Sound Class":
                    Layout = new Meta(new HaloPlugins.Xbox.sncl().Fields.ToArray(), "sncl", "sound_class", 8);
                    break;
                case "sound":
                case "(snd!) Sound":
                    Layout = new Meta(new HaloPlugins.Xbox.snd().Fields.ToArray(), "snd!", "sound", 20);
                    break;
                case "sound_environment":
                case "(snde) Sound Environment":
                    Layout = new Meta(new HaloPlugins.Xbox.snde().Fields.ToArray(), "snde", "sound_environment", 72);
                    break;
                case "sound_mixture":
                case "(snmx) Sound Mixture":
                    Layout = new Meta(new HaloPlugins.Xbox.snmx().Fields.ToArray(), "snmx", "sound_mixture", 88);
                    break;
                case "shader_pass":
                case "(spas) Shader Pass":
                    Layout = new Meta(new HaloPlugins.Xbox.spas().Fields.ToArray(), "spas", "shader_pass", 36);
                    break;
                case "speak":
                case "(spk!) Speak":
                    Layout = new Meta(new HaloPlugins.Xbox.spk().Fields.ToArray(), "spk!", "speak", 40);
                    break;
                case "sound_scenery":
                case "(ssce) Sound Scenery":
                    Layout = new Meta(new HaloPlugins.Xbox.ssce().Fields.ToArray(), "ssce", "sound_scenery", 204);
                    break;
                case "shader_template":
                case "(stem) Shader Template":
                    Layout = new Meta(new HaloPlugins.Xbox.stem().Fields.ToArray(), "stem", "shader_template", 96);
                    break;
                case "style":
                case "(styl) Style":
                    Layout = new Meta(new HaloPlugins.Xbox.styl().Fields.ToArray(), "styl", "style", 92);
                    break;
                case "beam_trail":
                case "(tdtl) Beam Trail":
                    Layout = new Meta(new HaloPlugins.Xbox.tdtl().Fields.ToArray(), "tdtl", "beam_trail", 112);
                    break;
                case "camera_track":
                case "(trak) Camera Track":
                    Layout = new Meta(new HaloPlugins.Xbox.trak().Fields.ToArray(), "trak", "camera_track", 12);
                    break;
                case "unit_dialog":
                case "(udlg) Unit Dialog":
                    Layout = new Meta(new HaloPlugins.Xbox.udlg().Fields.ToArray(), "udlg", "unit_dialog", 24);
                    break;
                case "sound_diagnostics":
                case "(ugh!) Sound Diagnostics":
                    Layout = new Meta(new HaloPlugins.Xbox.ugh().Fields.ToArray(), "ugh!", "sound_diagnostics", 88);
                    break;
                case "unicode_string_list":
                case "(unic) Unicode String List":
                    Layout = new Meta(new HaloPlugins.Xbox.unic().Fields.ToArray(), "unic", "unicode_string_list", 52);
                    break;
                case "vehicle_collection":
                case "(vehc) Vehicle Collection":
                    Layout = new Meta(new HaloPlugins.Xbox.vehc().Fields.ToArray(), "vehc", "vehicle_collection", 12);
                    break;
                case "vehicle":
                case "(vehi) Vehicle":
                    Layout = new Meta(new HaloPlugins.Xbox.vehi().Fields.ToArray(), "vehi", "vehicle", 768);
                    break;
                case "vertex_shader":
                case "(vrtx) Vertex Shader":
                    Layout = new Meta(new HaloPlugins.Xbox.vrtx().Fields.ToArray(), "vrtx", "vertex_shader", 12);
                    break;
                case "weapon":
                case "(weap) Weapon":
                    Layout = new Meta(new HaloPlugins.Xbox.weap().Fields.ToArray(), "weap", "weapon", 796);
                    break;
                case "weather_system":
                case "(weat) Weather System":
                    Layout = new Meta(new HaloPlugins.Xbox.weat().Fields.ToArray(), "weat", "weather_system", 176);
                    break;
                case "user_interface_screen_widget_definition":
                case "(wgit) User Interface Screen Widget Definition":
                    Layout = new Meta(new HaloPlugins.Xbox.wgit().Fields.ToArray(), "wgit", "user_interface_screen_widget_definition", 104);
                    break;
                case "user_interface_globals_definition":
                case "(wgtz) User Interface Globals Definition":
                    Layout = new Meta(new HaloPlugins.Xbox.wgtz().Fields.ToArray(), "wgtz", "user_interface_globals_definition", 32);
                    break;
                case "user_interface_shared_globals_definition":
                case "(wigl) User Interface Shared Globals Definition":
                    Layout = new Meta(new HaloPlugins.Xbox.wigl().Fields.ToArray(), "wigl", "user_interface_shared_globals_definition", 452);
                    break;
                default:
                    Layout = null;
                    break;
            }
            #endregion
        }

        public void Load(ref Panel p, BinaryReader br)
        {
            // Load the Meta
            if (br != null)
            {
                Stopwatch sw = new Stopwatch();
                sw.Start();
                Layout.Read(br);
                sw.Stop();
                MessageBox.Show(sw.Elapsed.ToString());
            }

            // Load Controls
            List<Control> Controls = new List<Control>();
            for (int i = 0; i < Layout.Fields.Length; i++)
            {
                if (Layout.Fields[i].GetType() == typeof(HaloObjects.Value))
                {
                    Value v = new Value(((HaloObjects.Value)Layout.Fields[i]).GetName(), ((HaloObjects.Value)Layout.Fields[i]).GetValue(), i);
                    v.Dock = DockStyle.Top;
                    Controls.Add(v);
                }
                else if (Layout.Fields[i].GetType() == typeof(HaloObjects.Bitmask))
                {
                    Bitmask b = new Bitmask(((HaloObjects.Bitmask)Layout.Fields[i]).GetName(), ((HaloObjects.Bitmask)Layout.Fields[i]).GetOptions(), ((HaloObjects.Bitmask)Layout.Fields[i]).GetValue(), ((HaloObjects.Bitmask)Layout.Fields[i]).GetBitCount(), i);
                    b.Dock = DockStyle.Top;
                    Controls.Add(b);
                }
                else if (Layout.Fields[i].GetType() == typeof(HaloObjects.Enum))
                {
                    Enum b = new Enum(((HaloObjects.Enum)Layout.Fields[i]).GetName(), ((HaloObjects.Enum)Layout.Fields[i]).GetOptions(), ((HaloObjects.Enum)Layout.Fields[i]).GetValue(), ((HaloObjects.Enum)Layout.Fields[i]).GetBitCount(), i);
                    b.Dock = DockStyle.Top;
                    Controls.Add(b);
                }
                else if (Layout.Fields[i].GetType() == typeof(String32))
                {
                    String s = new String(((HaloObjects.String32)Layout.Fields[i]).GetName(), ((HaloObjects.String32)Layout.Fields[i]).GetValue(), 32, i);
                    s.Dock = DockStyle.Top;
                    Controls.Add(s);
                }
                else if (Layout.Fields[i].GetType() == typeof(String256))
                {
                    String s = new String(((HaloObjects.String256)Layout.Fields[i]).GetName(), ((HaloObjects.String256)Layout.Fields[i]).GetValue(), 256, i);
                    s.Dock = DockStyle.Top;
                    Controls.Add(s);
                }
                else if (Layout.Fields[i].GetType() == typeof(Unicode64))
                {
                    String s = new String(((HaloObjects.Unicode64)Layout.Fields[i]).GetName(), ((HaloObjects.Unicode64)Layout.Fields[i]).GetValue(), 32, i);
                    s.Dock = DockStyle.Top;
                    Controls.Add(s);
                }
                else if (Layout.Fields[i].GetType() == typeof(Unicode256))
                {
                    String s = new String(((HaloObjects.Unicode256)Layout.Fields[i]).GetName(), ((HaloObjects.Unicode256)Layout.Fields[i]).GetValue(), 128, i);
                    s.Dock = DockStyle.Top;
                    Controls.Add(s);
                }
                else if (Layout.Fields[i].GetType() == typeof(StringID))
                {
                    String s = new String(((HaloObjects.StringID)Layout.Fields[i]).GetName(), ((HaloObjects.StringID)Layout.Fields[i]).GetValue(), 128, i);
                    s.Dock = DockStyle.Top;
                    Controls.Add(s);
                }
                else if (Layout.Fields[i].GetType() == typeof(HaloObjects.TagReference))
                {
                    TagReference t = new TagReference(((HaloObjects.TagReference)Layout.Fields[i]).GetName(), (string)((HaloObjects.TagReference)Layout.Fields[i]).GetValue(), i);
                    t.Dock = DockStyle.Top;
                    Controls.Add(t);
                }
                else if (Layout.Fields[i].GetType() == typeof(HaloObjects.Ident))
                {
                    TagReference t = new TagReference(((HaloObjects.Ident)Layout.Fields[i]).GetName(), (string)((HaloObjects.Ident)Layout.Fields[i]).GetValue(), i);
                    t.Dock = DockStyle.Top;
                    Controls.Add(t);
                }
                else if (Layout.Fields[i].GetType() == typeof(HaloObjects.Reflexive))
                {
                    Reflexive r = new Reflexive(((HaloObjects.Reflexive)Layout.Fields[i]).GetName(), ((HaloObjects.Reflexive)Layout.Fields[i]), i);
                    r.Dock = DockStyle.Top;
                    Controls.Add(r);
                }
            }

            //Load them in Reverse
            Controls.Reverse();
            p.Controls.AddRange(Controls.ToArray());
        }

        public void Write(string Location, ref Panel p)
        {
            // Get new Values
            for (int x = 0; x < p.Controls.Count; x++)
            {
                // Update
                int Index = GetIndex(p.Controls[x]);

                // Save
                if (Index != -1)
                    Layout.Fields[Index].SetValue(GetSave(p.Controls[x]));
            }

            // Delete
            if (File.Exists(Location))
                File.Delete(Location);

            // Save
            BinaryWriter bw = new BinaryWriter(new FileStream(Location, FileMode.Create, FileAccess.Write, FileShare.Write));

            // Write
            Layout.Write(bw);

            // Close
            bw.Close();
        }

        private int GetIndex(Control c)
        {
            if (c.GetType() == typeof(Value))
                return ((Value)c).Index;
            else if (c.GetType() == typeof(Bitmask))
                return ((Bitmask)c).Index;
            else if (c.GetType() == typeof(Enum))
                return ((Enum)c).Index;
            else if (c.GetType() == typeof(Reflexive))
                return ((Reflexive)c).Index;
            else if (c.GetType() == typeof(String))
                return ((String)c).Index;
            else if (c.GetType() == typeof(TagReference))
                return ((TagReference)c).Index;
            else
                return -1;
        }

        private object GetSave(Control c)
        {
            if (c.GetType() == typeof(Value))
                return ((Value)c).Save();
            else if (c.GetType() == typeof(Bitmask))
                return ((Bitmask)c).Save();
            else if (c.GetType() == typeof(Enum))
                return ((Enum)c).Save();
            else if (c.GetType() == typeof(Reflexive))
                return ((Reflexive)c).Save();
            else if (c.GetType() == typeof(String))
                return ((String)c).Save();
            else if (c.GetType() == typeof(TagReference))
                return ((TagReference)c).Save();
            else
                return null;
        }
    }
}
