using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace MKDS_Course_Editor.NSBTP
{
    public class NSBTP
    {
        public struct NSBTP_File
        {
            public header Header;
            public struct header
            {
                public string ID;
                public byte[] Magic;
                public Int32 file_size;
                public Int16 header_size;
                public Int16 nSection;
                public Int32[] Section_Offset;
            }
            public pat0 PAT0;
            public struct pat0 //Scale Rotation and Translation
            {
                public string ID;
                public Int32 Size;
                //3D Info Structure
                public byte dummy;
                public byte num_objs;
                public short section_size;
                public UnknownBlock unknownBlock;
                public Info infoBlock;
                public string[] names;

                public struct UnknownBlock
                {
                    public short header_size;
                    public short section_size;
                    public int constant; // 0x017F

                    public short[] unknown1;
                    public short[] unknown2;
                }
                public struct Info
                {
                    public short header_size;
                    public short data_size;

                    public info[] Data;

                    public struct info
                    {
                        public Int32 MPToffset;
                    }
                }
            }
            public M_PT MPT;
            public struct M_PT
            {
                public string ID;
                public Int16 NoFrames;
                public byte NoTex;
                public byte NoPal;
                public Int16 Texoffset;
                public Int16 Paloffset;
                //3D Info Structure
                public byte dummy;
                public byte num_objs;
                public short section_size;
                public UnknownBlock unknownBlock;
                public Info infoBlock;
                public string[] names;

                public struct UnknownBlock
                {
                    public short header_size;
                    public short section_size;
                    public int constant; // 0x017F

                    public short[] unknown1;
                    public short[] unknown2;
                }
                public struct Info
                {
                    public short header_size;
                    public short data_size;

                    
                    public info[] Data;

                    public struct info
                    {
                        public Int32 KeyFrames;
                        public short Unknown1;
                        public short Offset;
                    }
                }
            }
            public animData[] AnimData;
            public struct animData
            {
                public keyFrame[] KeyFrames;
                public struct keyFrame
                {
                    public short Start;
                    public byte texId;
                    public byte palId;
                    public string texName;
                    public string palName;
                }
            }
        }
        public static NSBTP_File Read(string Filename)
        {
            EndianBinaryReader er = new EndianBinaryReader(File.OpenRead(Filename), Endianness.LittleEndian);
            NSBTP_File ns = new NSBTP_File();
            ns.Header.ID = er.ReadString(Encoding.ASCII, 4);
            if (ns.Header.ID == "BTP0")
            {
                ns.Header.Magic = er.ReadBytes(4);
                ns.Header.file_size = er.ReadInt32();
                ns.Header.header_size = er.ReadInt16();
                ns.Header.nSection = er.ReadInt16();
                ns.Header.Section_Offset = new Int32[ns.Header.nSection];
                for (int i = 0; i < ns.Header.nSection; i++)
                {
                    ns.Header.Section_Offset[i] = er.ReadInt32();
                }
                ns.PAT0.ID = er.ReadString(Encoding.ASCII, 4);
                if (ns.PAT0.ID == "PAT0")
                {
                    ns.PAT0.Size = er.ReadInt32();
                    //3D Info Structure
                    ns.PAT0.dummy = er.ReadByte();
                    ns.PAT0.num_objs = er.ReadByte();
                    ns.PAT0.section_size = er.ReadInt16();
                    ns.PAT0.unknownBlock.header_size = er.ReadInt16();
                    ns.PAT0.unknownBlock.section_size = er.ReadInt16();
                    ns.PAT0.unknownBlock.constant = er.ReadInt32();
                    ns.PAT0.unknownBlock.unknown1 = new short[ns.PAT0.num_objs];
                    ns.PAT0.unknownBlock.unknown2 = new short[ns.PAT0.num_objs];
                    for (int i = 0; i < ns.PAT0.num_objs; i++)
                    {
                        ns.PAT0.unknownBlock.unknown1[i] = er.ReadInt16();
                        ns.PAT0.unknownBlock.unknown2[i] = er.ReadInt16();
                    }

                    ns.PAT0.infoBlock.header_size = er.ReadInt16();
                    ns.PAT0.infoBlock.data_size = er.ReadInt16();
                    ns.PAT0.infoBlock.Data = new NSBTP_File.pat0.Info.info[ns.PAT0.num_objs];
                    for (int i = 0; i < ns.PAT0.num_objs; i++)
                    {
                        ns.PAT0.infoBlock.Data[i].MPToffset = er.ReadInt32();
                    }
                    ns.PAT0.names = new string[ns.PAT0.num_objs];
                    for (int i = 0; i < ns.PAT0.num_objs; i++)
                    {
                        ns.PAT0.names[i] = er.ReadString(Encoding.ASCII, 16).Replace("\0", "");
                    }

                    ns.MPT.ID = er.ReadString(Encoding.ASCII, 4);
                    if (ns.MPT.ID == "M" + (char)0x00 + "PT")
                    {
                        ns.MPT.NoFrames = er.ReadInt16();
                        ns.MPT.NoTex = er.ReadByte();
                        ns.MPT.NoPal = er.ReadByte();
                        ns.MPT.Texoffset = er.ReadInt16();
                        ns.MPT.Paloffset = er.ReadInt16();
                        //3D Info Structure
                        ns.MPT.dummy = er.ReadByte();
                        ns.MPT.num_objs = er.ReadByte();
                        ns.MPT.section_size = er.ReadInt16();
                        ns.MPT.unknownBlock.header_size = er.ReadInt16();
                        ns.MPT.unknownBlock.section_size = er.ReadInt16();
                        ns.MPT.unknownBlock.constant = er.ReadInt32();
                        ns.MPT.unknownBlock.unknown1 = new short[ns.MPT.num_objs];
                        ns.MPT.unknownBlock.unknown2 = new short[ns.MPT.num_objs];
                        for (int i = 0; i < ns.MPT.num_objs; i++)
                        {
                            ns.MPT.unknownBlock.unknown1[i] = er.ReadInt16();
                            ns.MPT.unknownBlock.unknown2[i] = er.ReadInt16();
                        }

                        ns.MPT.infoBlock.header_size = er.ReadInt16();
                        ns.MPT.infoBlock.data_size = er.ReadInt16();
                        ns.MPT.infoBlock.Data = new NSBTP_File.M_PT.Info.info[ns.MPT.num_objs];
                        ns.AnimData = new NSBTP_File.animData[ns.MPT.num_objs];
                        for (int i = 0; i < ns.MPT.num_objs; i++)
                        {
                            ns.MPT.infoBlock.Data[i].KeyFrames = er.ReadInt32();
                            ns.MPT.infoBlock.Data[i].Unknown1 = er.ReadInt16();
                            ns.MPT.infoBlock.Data[i].Offset = er.ReadInt16();
                            ns.AnimData[i].KeyFrames = new NSBTP_File.animData.keyFrame[ns.MPT.infoBlock.Data[i].KeyFrames];
                            for (int j = 0; j < ns.MPT.infoBlock.Data[i].KeyFrames; j++)
                            {
                                long curpos = er.BaseStream.Position;
                                er.BaseStream.Position = ns.Header.Section_Offset[0] + ns.PAT0.section_size + ns.MPT.infoBlock.Data[i].Offset + j*4 + 8;
                                ns.AnimData[i].KeyFrames[j].Start = er.ReadInt16();
                                ns.AnimData[i].KeyFrames[j].texId = er.ReadByte();
                                ns.AnimData[i].KeyFrames[j].palId = er.ReadByte();
                                er.BaseStream.Position = ns.Header.Section_Offset[0] + ns.PAT0.section_size + ns.MPT.Texoffset + ns.AnimData[i].KeyFrames[j].texId * 16 + 8;
                                ns.AnimData[i].KeyFrames[j].texName = LibNDSFormats.Utils.ReadNSBMDString(er);
                                er.BaseStream.Position = ns.Header.Section_Offset[0] + ns.PAT0.section_size + ns.MPT.Paloffset + ns.AnimData[i].KeyFrames[j].palId * 16 + 8;
                                ns.AnimData[i].KeyFrames[j].palName = LibNDSFormats.Utils.ReadNSBMDString(er);
                                er.BaseStream.Position = curpos;
                            }
                        }
                        ns.MPT.names = new string[ns.MPT.num_objs];
                        for (int i = 0; i < ns.MPT.num_objs; i++)
                        {
                            ns.MPT.names[i] = LibNDSFormats.Utils.ReadNSBMDString(er);
                        }
                    }
                    else
                    {
                        MessageBox.Show("NSBTP Error");
                        er.Close();
                        return ns;
                    }
                }
                else
                {
                    MessageBox.Show("NSBTP Error");
                    er.Close();
                    return ns;
                }
            }
            else
            {
                MessageBox.Show("NSBTP Error");
                er.Close();
                return ns;
            }
            er.Close();
            return ns;
        }
    }
}
