using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HaloPlugins;
using System.IO;
using IO;

namespace Utils
{
    public class ProjectHelper
    {
        public static void AddSoundRaw(string TagPath, string OldSoundDiagnostics, string NewSoundDiagnostics)
        {
            // Open our sound file
            FileStream fs = new FileStream(TagPath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
            EndianReader br = new EndianReader(Endianness.Little, fs);
            EndianWriter bw = new EndianWriter(Endianness.Little, fs);

            // Parse our sound tag
            TagDefinition Snd = EngineManager.GetEngine()["Halo2Xbox"].CreateInstance("sound");
            Snd.Read(br);

            // Open the input sound diagnostics tag
            fs.Close();
            fs = new FileStream(NewSoundDiagnostics, FileMode.Open, FileAccess.Read, FileShare.Read);
            br = new EndianReader(Endianness.Little, fs);

            // Parse it
            TagDefinition CocoSrc = EngineManager.GetEngine()["Halo2Xbox"].CreateInstance("sound_diagnostics");
            CocoSrc.Read(br);

            // Open the sound diagnostics tag from this project
            fs.Close();
            fs = new FileStream(OldSoundDiagnostics, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
            br = new EndianReader(Endianness.Little, fs);
            bw = new EndianWriter(Endianness.Little, fs);

            // Parse it
            TagDefinition Coco = EngineManager.GetEngine()["Halo2Xbox"].CreateInstance("sound_diagnostics");
            Coco.Read(br);

            #region Permutations

            // Pull out our permutation block
            int PermutationIndex = (short)Snd[4].GetValue();
            IMetaNode[] Permutation = (IMetaNode[])((TagBlock)CocoSrc[4])[PermutationIndex];

            // Check for a name index
            int NameIndex = (short)Permutation[0].GetValue();
            if (NameIndex != -1)
            {
                // Get our name block
                IMetaNode[] Name = (IMetaNode[])((TagBlock)CocoSrc[2])[NameIndex];

                // Add it to our sound diagnostics tag and relink
                Permutation[0].SetValue((short)((TagBlock)Coco[2]).BlockCount);
                ((TagBlock)Coco[2]).AddBlock(Name);
            }

            // Check for sound choice indices
            int ChoiceIndex = (short)Permutation[6].GetValue();
            int ChoiceCount = (short)Permutation[7].GetValue();
            if (ChoiceIndex != -1 && ChoiceCount > -0)
            {
                // Copy the choice blocks
                Permutation[6].SetValue((short)((TagBlock)Coco[5]).BlockCount);
                for (int i = 0; i < ChoiceCount; i++)
                {
                    // Get the choice block
                    IMetaNode[] Choice = (IMetaNode[])((TagBlock)CocoSrc[5])[ChoiceIndex + i];

                    // Check for name index
                    NameIndex = (int)Choice[0].GetValue();
                    if (NameIndex != -1)
                    {
                        // Get our name block
                        IMetaNode[] Name = (IMetaNode[])((TagBlock)CocoSrc[2])[NameIndex];

                        // Add it to our sound diagnostics tag and relink
                        Choice[0].SetValue((short)((TagBlock)Coco[2]).BlockCount);
                        ((TagBlock)Coco[2]).AddBlock(Name);
                    }

                    // Check for cache blocks
                    int CacheIndex = (short)Choice[3].GetValue();
                    int CacheCount = (short)Choice[4].GetValue();
                    if (CacheIndex != -1 && CacheCount > 0)
                    {
                        // Copy the cache blocks
                        Choice[3].SetValue((short)((TagBlock)Coco[8]).BlockCount);
                        for (int x = 0; x < ChoiceCount; x++)
                        {
                            // Get the cache block
                            IMetaNode[] Cache = (IMetaNode[])((TagBlock)CocoSrc[8])[CacheIndex + x];

                            // Check for internal sound raw
                            int Offset = (int)Cache[0].GetValue();
                            int Size = (int)Cache[1].GetValue() & 0x7FFFFFFF;
                            if ((Offset & 0xC0000000) == 0)
                            {
                                // Get the raw buffer
                                byte[] Buffer = new byte[Size];
                                CocoSrc.RawDef["SoundRaw"].Position = Offset;
                                CocoSrc.RawDef["SoundRaw"].Read(Buffer, 0, Size);

                                // Add it to this project's sound raw buffer
                                Cache[0].SetValue((int)Coco.RawDef["SoundRaw"].Length);
                                Coco.RawDef["SoundRaw"].Position = Coco.RawDef["SoundRaw"].Length;
                                Coco.RawDef["SoundRaw"].Write(Buffer, 0, Size);

                                // Write padding to the raw buffer
                                int PaddingSize = 512 - (Size % 512);
                                byte[] Padding = new byte[PaddingSize];
                                Coco.RawDef["SoundRaw"].Write(Padding, 0, PaddingSize);
                            }

                            // Add the cache block to this project
                            ((TagBlock)Coco[8]).AddBlock(Cache);
                        }
                    }

                    // Add the choice block to this project
                    ((TagBlock)Coco[5]).AddBlock(Choice);
                }
            }

            // Add our permutation block
            Snd[4].SetValue((short)((TagBlock)CocoSrc[4]).BlockCount);
            ((TagBlock)CocoSrc[4]).AddBlock(Permutation);

            #endregion

            #region Pitch Ranges

            // Check for pitch range indices
            int PitchRangeIndex = (short)Snd[5].GetValue();
            int PitchRangeCount = (byte)Snd[6].GetValue();
            if (PitchRangeIndex != -1 && PitchRangeCount > 0)
            {
                // Copy all pitch range blocks
                Snd[5].SetValue((short)((TagBlock)Coco[3]).BlockCount);
                for (int i = 0; i < PitchRangeCount; i++)
                {
                    // Get the pitch range block
                    //IMetaNode[] Pitch = (IMetaNode[])((TagBlock)CocoSrc[3])[PitchRangeIndex + i];

                    // Add to project
                    //((TagBlock)Coco[3]).AddBlock(Pitch);
                }
            }

            #endregion

            #region Scales

            // Check for scale indices
            int ScaleIndex = (byte)Snd[7].GetValue();
            if (ScaleIndex != -1)
            {
                // Get the scale block
                IMetaNode[] Scale = (IMetaNode[])((TagBlock)CocoSrc[1])[ScaleIndex];

                // Add to project
                Snd[7].SetValue((byte)((TagBlock)Coco[1]).BlockCount);
                ((TagBlock)Coco[1]).AddBlock(Scale);
            }

            #endregion

            #region Promotions

            // Check for promotions
            int PromotionIndex = (short)Snd[8].GetValue();
            if (PromotionIndex != -1)
            {
                // god dam it
            }

            #endregion

            #region Custom Playbacks

            // Check for custom playbacks
            int CustomPlayBackIndex = (short)Snd[9].GetValue();
            if (CustomPlayBackIndex != -1)
            {
                // Get the playback block
                IMetaNode[] Playback = (IMetaNode[])((TagBlock)CocoSrc[6])[CustomPlayBackIndex];

                // Add it to this project
                Snd[9].SetValue((short)((TagBlock)Coco[6]).BlockCount);
                ((TagBlock)Coco[6]).AddBlock(Playback);
            }

            #endregion

            // Save our modified sound diagnostics tag
            Coco.Write(bw);
            fs.Close();

            // Save our modified sound tag
            fs = new FileStream(TagPath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
            bw = new EndianWriter(Endianness.Little, fs);
            Snd.Write(bw);
        }
    }
}
