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 HaloMap;
using Global;
using HaloControls;
using HaloObjects;
using System.Diagnostics;

namespace Mutation
{
    public partial class Updater : Form
    {
        Map map, TargetMap;
        Project p;
        string Location, Target;
        bool[] Options;

        public Updater(Map map, string Location)
        {
            this.map = map;
            this.Location = Location;
            InitializeComponent();
        }

        public Updater(Project p, string Location)
        {
            this.p = p;
            this.Location = Location;
            InitializeComponent();
        }

        public Updater(bool[] Options, string BaseMap, string TargetMap)
        {
            this.Options = Options;
            this.Location = BaseMap;
            this.Target = TargetMap;
            InitializeComponent();
        }

        private void Updater_Load(object sender, EventArgs e)
        {
            if (p != null)
            {
                // Set Maximum
                this.Show();
                progressBarControl1.Text = "0";
                progressBarControl2.Text = "0";

                // Compile Map
                Stopwatch watch = new Stopwatch();
                watch.Start();
                map = new Map(p, Location, lblStatus, lblTag, progressBarControl1, progressBarControl2);
                watch.Stop();
                MessageBox.Show(watch.Elapsed.ToString());

                // Done
                map.Close();
                this.Close();
            }
            else if (Options != null)
            {
                // Set Maximum
                this.Show();
                progressBarControl1.Text = "0";
                progressBarControl2.Text = "0";

                // Open Maps
                map = new Map(Location);
                TargetMap = new Map(Target);

                // Read
                lblStatus.Text = "Reading Base Map...";
                Application.DoEvents();
                map.Read(null);
                lblStatus.Text = "Reading Target Map...";
                Application.DoEvents();
                TargetMap.Read(null);

                // Setup Analyzer Form
                Analyzer a = new Analyzer();

                #region Sound Raw
                if (Options[0])
                {
                    lblStatus.Text = "Analyzing Sound Raw...";
                    progressBarControl1.Properties.Maximum = map.Coconuts.SoundChunks.Count;
                    Application.DoEvents();
                    for (int i = 0; i < map.Coconuts.SoundChunks.Count; i++)
                    {
                        // UI
                        progressBarControl1.Text = i.ToString();
                        Application.DoEvents();

                        // Compare
                        if (map.Coconuts.SoundChunks[i].RawLocation == RawLocation.Internal)
                        {
                            // Navigate
                            map.br.BaseStream.Position = map.Coconuts.SoundChunks[i].Offset;
                            TargetMap.br.BaseStream.Position = TargetMap.Coconuts.SoundChunks[i].Offset;

                            // Compare
                            for (int x = 0; x < map.Coconuts.SoundChunks[i].Size; x++)
                            {
                                if (map.br.ReadByte() != TargetMap.br.ReadByte())
                                {
                                    // Add Block
                                    DataBlock b = new DataBlock();
                                    b.Name = TargetMap.Tags[TargetMap.Tags.Count - 1].Path;
                                    b.Offset = TargetMap.Coconuts.SoundChunks[i].Offset;
                                    b.Size = TargetMap.Coconuts.SoundChunks[i].Size;
                                    b.Type = DataType.SoundRaw;
                                    a.AddBlock(b);
                                }
                            }
                        }
                    }
                }
                #endregion

                #region Model Raw
                /*
                if (Options[1])
                {
                    lblStatus.Text = "Analyzing Model Raw...";
                    progressBarControl1.Properties.Maximum = map.Tags.Count;
                    Application.DoEvents();
                    for (int i = 0; i < map.Tags.Count; i++)
                    {
                        // UI
                        progressBarControl1.Text = i.ToString();
                        Application.DoEvents();

                        // Compare
                        int BaseOffset = map.br.ReadInt32();
                        int BaseSize = map.br.ReadInt32();
                        if (map.Coconuts.SoundChunks[i].RawLocation == RawLocation.Internal)
                        {
                            // Navigate
                            map.br.BaseStream.Position = map.Coconuts.SoundChunks[i].Offset;
                            TargetMap.br.BaseStream.Position = TargetMap.Coconuts.SoundChunks[i].Offset;

                            // Compare
                            for (int x = 0; x < map.Coconuts.SoundChunks[i].Size; x++)
                            {
                                if (map.br.ReadByte() != TargetMap.br.ReadByte())
                                {
                                    // Add Block
                                    DataBlock b = new DataBlock();
                                    b.Name = TargetMap.Tags[TargetMap.Tags.Count - 1].Path;
                                    b.Offset = TargetMap.Coconuts.SoundChunks[i].Offset;
                                    b.Size = TargetMap.Coconuts.SoundChunks[i].Size;
                                    a.AddBlock(b);
                                }
                            }
                        }
                    }
                }*/
                #endregion

                #region BSP & Lightmap Meta
                // Read BSP Tags
                Plugin BaseBsp = new Plugin("scenario_structure_bsp", null);
                map.br.BaseStream.Position = map.BSPs[0].BSPOffset;
                BaseBsp.Layout.Read(map.br, map.BSPs[0].Magic);
                for (int i = 0; i < map.Tags.Count; i++)
                    BaseBsp.Layout.TagReferences.Add(map.Tags[i].Path);
                BaseBsp.Layout.TagStringIds.AddRange(map.SIDs);

                Plugin TargetBsp = new Plugin("scenario_structure_bsp", null);
                TargetMap.br.BaseStream.Position = TargetMap.BSPs[0].BSPOffset;
                TargetBsp.Layout.Read(TargetMap.br, TargetMap.BSPs[0].Magic);
                for (int i = 0; i < TargetMap.Tags.Count; i++)
                    TargetBsp.Layout.TagReferences.Add(TargetMap.Tags[i].Path);
                TargetBsp.Layout.TagStringIds.AddRange(TargetMap.SIDs);

                lblStatus.Text = "Analyzing BSP Meta...";
                progressBarControl1.Properties.Maximum = BaseBsp.Layout.Fields.Length;
                Application.DoEvents();

                // Compare
                for (int i = 0; i < BaseBsp.Layout.Fields.Length; i++)
                {
                    // UI
                    progressBarControl1.Text = i.ToString();
                    Application.DoEvents();

                    // Compare
                    if (BaseBsp.Layout.Fields[i].GetType() == typeof(HaloObjects.Value) ||
                        BaseBsp.Layout.Fields[i].GetType() == typeof(HaloObjects.Bitmask) ||
                        BaseBsp.Layout.Fields[i].GetType() == typeof(HaloObjects.Enum) ||
                        BaseBsp.Layout.Fields[i].GetType() == typeof(HaloObjects.String256) ||
                        BaseBsp.Layout.Fields[i].GetType() == typeof(HaloObjects.String32) ||
                        BaseBsp.Layout.Fields[i].GetType() == typeof(HaloObjects.Unicode256) ||
                        BaseBsp.Layout.Fields[i].GetType() == typeof(HaloObjects.Unicode64))
                    {
                        if (BaseBsp.Layout.Fields[i].GetValue().ToString() !=
                            TargetBsp.Layout.Fields[i].GetValue().ToString())
                        {
                            DataBlock b = new DataBlock();
                            b.Name = BaseBsp.Layout.Fields[i].GetName();
                            b.Type = DataType.BSPMeta;
                            a.AddBlock(b);
                        }
                    }
                    else if (BaseBsp.Layout.Fields[i].GetType() == typeof(HaloObjects.Ident) ||
                        BaseBsp.Layout.Fields[i].GetType() == typeof(HaloObjects.TagReference) ||
                        BaseBsp.Layout.Fields[i].GetType() == typeof(HaloObjects.StringID))
                    {
                        Globals.Plugin = BaseBsp.Layout;
                        string BaseVal = (string)BaseBsp.Layout.Fields[i].GetValue();
                        Globals.Plugin = TargetBsp.Layout;
                        string TargetVal = (string)TargetBsp.Layout.Fields[i].GetValue();

                        if (BaseVal != TargetVal)
                        {
                            DataBlock b = new DataBlock();
                            b.Name = BaseBsp.Layout.Fields[i].GetName();
                            b.Type = DataType.BSPMeta;
                            a.AddBlock(b);
                        }
                    }
                    else if (BaseBsp.Layout.Fields[i].GetType() == typeof(HaloObjects.Reflexive))
                    {
                        if (((HaloObjects.Reflexive)BaseBsp.Layout.Fields[i]).GetChunkCount() !=
                            ((HaloObjects.Reflexive)TargetBsp.Layout.Fields[i]).GetChunkCount())
                        {
                            DataBlock b = new DataBlock();
                            b.Name = BaseBsp.Layout.Fields[i].GetName();
                            b.Type = DataType.BSPMeta;
                            a.AddBlock(b);
                        }
                        CompareReflexive(a, BaseBsp, TargetBsp, (HaloObjects.Reflexive)BaseBsp.Layout.Fields[i], (HaloObjects.Reflexive)TargetBsp.Layout.Fields[i]);
                    }
                }
                #endregion

                // Done
                map.Close();
                TargetMap.Close();
                this.Hide();
                a.ShowDialog();
                this.Close();
            }
            else
            {
                // Set Maximum
                this.Show();
                progressBarControl1.Text = "0";
                progressBarControl2.Text = "0";

                // Read Map
                lblStatus.Text = "Reading Map...";
                Application.DoEvents();
                progressBarControl1.Properties.Maximum = map.Tags.Count;
                progressBarControl2.Properties.Maximum = map.Tags.Count;


                // Decompile
                lblStatus.Text = "Decompiling:";
                Application.DoEvents();
                map.Decompile(Location, lblTag, progressBarControl1, progressBarControl2);

                // Done
                map.Close();
                this.Close();
            }
        }

        private void CompareReflexive(Analyzer a, Plugin BaseBsp, Plugin TargetBsp, HaloObjects.Reflexive Base, HaloObjects.Reflexive Target)
        {
            for (int i = 0; i < Base.GetChunkCount(); i++)
            {
                Base.ChangeIndex(i);
                Target.ChangeIndex(i);

                MetaNode[] BaseFields = (MetaNode[])Base.GetValue();
                MetaNode[] TargetFields = (MetaNode[])Target.GetValue();

                for (int x = 0; x < BaseFields.Length; x++)
                {
                    if (BaseFields[x].GetType() == typeof(HaloObjects.Value) ||
                        BaseFields[x].GetType() == typeof(HaloObjects.Bitmask) ||
                        BaseFields[x].GetType() == typeof(HaloObjects.Enum) ||
                        BaseFields[x].GetType() == typeof(HaloObjects.String256) ||
                        BaseFields[x].GetType() == typeof(HaloObjects.String32) ||
                        BaseFields[x].GetType() == typeof(HaloObjects.Unicode256) ||
                        BaseFields[x].GetType() == typeof(HaloObjects.Unicode64))
                    {
                        if (BaseFields[x].GetValue().ToString() !=
                            TargetFields[x].GetValue().ToString())
                        {
                            DataBlock b = new DataBlock();
                            b.Name = Base.GetName() + ": " + BaseFields[x].GetName();
                            b.Type = DataType.BSPMeta;
                            a.AddBlock(b);
                        }
                    }
                    else if (BaseFields[x].GetType() == typeof(HaloObjects.Ident) ||
                        BaseFields[x].GetType() == typeof(HaloObjects.TagReference) ||
                        BaseFields[x].GetType() == typeof(HaloObjects.StringID))
                    {
                        Globals.Plugin = BaseBsp.Layout;
                        string BaseVal = (string)BaseFields[x].GetValue();
                        Globals.Plugin = TargetBsp.Layout;
                        string TargetVal = (string)TargetFields[x].GetValue();

                        if (BaseVal != TargetVal)
                        {
                            DataBlock b = new DataBlock();
                            b.Name = Base.GetName() + ": " + BaseFields[x].GetName();
                            b.Type = DataType.BSPMeta;
                            a.AddBlock(b);
                        }
                    }
                    else if (BaseFields[x].GetType() == typeof(HaloObjects.Reflexive))
                    {
                        if (((HaloObjects.Reflexive)BaseFields[x]).GetChunkCount() !=
                            ((HaloObjects.Reflexive)TargetFields[x]).GetChunkCount())
                        {
                            DataBlock b = new DataBlock();
                            b.Name = Base.GetName() + ": " + BaseFields[x].GetName();
                            b.Type = DataType.BSPMeta;
                            a.AddBlock(b);
                        }
                        CompareReflexive(a, BaseBsp, TargetBsp, (HaloObjects.Reflexive)BaseFields[x], (HaloObjects.Reflexive)TargetFields[x]);
                    }
                }
            }
        }
    }
}
