using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Linq;
using System.Windows.Forms;
using Toolbox.Library;
using Toolbox.Library.IO;
using Toolbox.Library.Forms;
using System.ComponentModel;
using Bfres.Structs;

namespace FirstPlugin
{
    public class BFLIM : STGenericTexture, IEditor<ImageEditorBase>, IFileFormat
    {
        public FileType FileType { get; set; } = FileType.Image;

        public override TEX_FORMAT[] SupportedFormats
        {
            get
            {
                return new TEX_FORMAT[]
                {
                        TEX_FORMAT.BC1_UNORM,
                        TEX_FORMAT.BC1_UNORM_SRGB,
                        TEX_FORMAT.BC2_UNORM,
                        TEX_FORMAT.BC2_UNORM_SRGB,
                        TEX_FORMAT.BC3_UNORM,
                        TEX_FORMAT.BC3_UNORM_SRGB,
                        TEX_FORMAT.BC4_UNORM,
                        TEX_FORMAT.BC4_SNORM,
                        TEX_FORMAT.BC5_UNORM,
                        TEX_FORMAT.BC5_SNORM,
                        TEX_FORMAT.R8G8B8A8_UNORM_SRGB,
                        TEX_FORMAT.R8G8B8A8_UNORM,
                        TEX_FORMAT.A8_UNORM,
                        TEX_FORMAT.R8G8_UNORM,
                        TEX_FORMAT.R8G8_SNORM,
                        TEX_FORMAT.B5G6R5_UNORM,
                        TEX_FORMAT.R10G10B10A2_UNORM,
                        TEX_FORMAT.B4G4R4A4_UNORM,
                };
            }
        }

        public override bool CanEdit { get; set; } = true;

        public bool CanSave { get; set; }
        public string[] Description { get; set; } = new string[] { "Layout Image" };
        public string[] Extension { get; set; } = new string[] { "*.bflim" };
        public string FileName { get; set; }
        public string FilePath { get; set; }
        public IFileInfo IFileInfo { get; set; }

        public bool Identify(System.IO.Stream stream)
        {
            using (var reader = new Toolbox.Library.IO.FileReader(stream, true))
            {
                return reader.CheckSignature(4, "FLIM", reader.BaseStream.Length - 0x28);
            }
        }


        public Type[] Types
        {
            get
            {
                List<Type> types = new List<Type>();
                types.Add(typeof(MenuExt));
                return types.ToArray();
            }
        }

        private ImageEditorBase form;
        public ImageEditorBase OpenForm()
        {
            form = new ImageEditorBase();
            return form;
        }

        public void UpdateForm()
        {
            UpdateForm(form);
        }

        public void FillEditor(UserControl control)
        {
            form = (ImageEditorBase)control;
            UpdateForm((ImageEditorBase)control);
        }

        private void UpdateForm(ImageEditorBase form)
        {
            if (form == null) return;

            if (image != null)
            {
                Properties prop = new Properties();
                prop.Width = Width;
                prop.Height = Height;
                prop.Depth = Depth;
                prop.MipCount = MipCount;
                prop.ArrayCount = ArrayCount;
                prop.ImageSize = (uint)ImageData.Length;
                prop.Format = Format;
                prop.TileMode = image.TileMode;
                prop.Swizzle = image.Swizzle;

                form.Text = Text;
                form.Dock = DockStyle.Fill;
                form.ResetMenus();
                form.AddFileContextEvent("Save", Save);
                form.AddFileContextEvent("Replace", Replace);
                form.LoadProperties(prop);
                form.LoadImage(this);

                Console.WriteLine("UpdateForm LoadImage");
            }
        }

        class MenuExt : IFileMenuExtension
        {
            public STToolStripItem[] NewFileMenuExtensions => null;
            public STToolStripItem[] NewFromFileMenuExtensions => newFileExt;
            public STToolStripItem[] ToolsMenuExtensions => toolExt;
            public STToolStripItem[] TitleBarExtensions => null;
            public STToolStripItem[] CompressionMenuExtensions => null;
            public STToolStripItem[] ExperimentalMenuExtensions => null;
            public STToolStripItem[] EditMenuExtensions => null;
            public ToolStripButton[] IconButtonMenuExtensions => null;

            STToolStripItem[] newFileExt = new STToolStripItem[1];
            STToolStripItem[] toolExt = new STToolStripItem[1];

            public MenuExt()
            {
                toolExt[0] = new STToolStripItem("Textures");
                toolExt[0].DropDownItems.Add(new STToolStripItem("Batch Export (Wii U Textures)", Export));
                newFileExt[0] = new STToolStripItem("BFLIM From Image", CreateNew);
            }
            private void Export(object sender, EventArgs args)
            {
                string formats = FileFilters.GTX;

                string[] forms = formats.Split('|');

                List<string> Formats = new List<string>();
                for (int i = 0; i < forms.Length; i++)
                {
                    if (i > 1 || i == (forms.Length - 1)) //Skip lines with all extensions
                    {
                        if (!forms[i].StartsWith("*"))
                            Formats.Add(forms[i]);
                    }
                }

                BatchFormatExport form = new BatchFormatExport(Formats);
                if (form.ShowDialog() == DialogResult.OK)
                {
                    string Extension = form.GetSelectedExtension();

                    OpenFileDialog ofd = new OpenFileDialog();
                    ofd.Multiselect = true;
                    ofd.Filter = Utils.GetAllFilters(new Type[] { typeof(BFLIM), typeof(BXFNT), typeof(BFRES), typeof(PTCL), typeof(SARC) });

                    if (ofd.ShowDialog() == DialogResult.OK)
                    {
                        FolderSelectDialog folderDialog = new FolderSelectDialog();
                        if (folderDialog.ShowDialog() == DialogResult.OK)
                        {
                            foreach (string file in ofd.FileNames)
                            {
                                var FileFormat = STFileLoader.OpenFileFormat(file, new Type[] { typeof(BFLIM), typeof(PTCL), typeof(BFRES), typeof(BXFNT), typeof(SARC) });
                                if (FileFormat == null)
                                    continue;


                                if (FileFormat is SARC)
                                {
                                    string ArchiveFilePath = Path.Combine(folderDialog.SelectedPath, Path.GetFileNameWithoutExtension(file));
                                    ArchiveFilePath = Path.GetDirectoryName(ArchiveFilePath);

                                    if (!Directory.Exists(ArchiveFilePath))
                                        Directory.CreateDirectory(ArchiveFilePath);

                                    SearchBinary(FileFormat, ArchiveFilePath, Extension);
                                }
                                else
                                    SearchBinary(FileFormat, folderDialog.SelectedPath, Extension);
                            }
                        }
                    }
                }
            }

            private void SearchBinary(IFileFormat FileFormat, string Folder, string Extension)
            {
                if (FileFormat is SARC)
                {
                    string ArchiveFilePath = Path.Combine(Folder, Path.GetFileNameWithoutExtension(FileFormat.FileName));
                    if (!Directory.Exists(ArchiveFilePath))
                        Directory.CreateDirectory(ArchiveFilePath);

                    foreach (var file in ((SARC)FileFormat).Files)
                    {
                        var archiveFile = STFileLoader.OpenFileFormat(file.FileName, new Type[] { typeof(BFLIM), typeof(BXFNT), typeof(PTCL), typeof(BFRES), typeof(SARC) }, file.FileData);
                        if (archiveFile == null)
                            continue;

                        SearchBinary(archiveFile, ArchiveFilePath, Extension);
                    }
                }
                if (FileFormat is BXFNT)
                {
                    foreach (STGenericTexture texture in ((BXFNT)FileFormat).bffnt.FontSection.TextureGlyph.Textures)
                        texture.Export(Path.Combine(Folder, $"{texture.Text}{Extension}"));
                }
                if (FileFormat is BFRES)
                {
                    var FtexContainer = ((BFRES)FileFormat).GetFTEXContainer;
                    if (FtexContainer != null)
                    {
                        foreach (var texture in FtexContainer.ResourceNodes.Values)
                            ((FTEX)texture).Export(Path.Combine(Folder, $"{texture.Text}{Extension}"));
                    }
                }

                if (FileFormat is PTCL)
                {
                    if (((PTCL)FileFormat).headerU != null)
                    {
                        foreach (STGenericTexture texture in ((PTCL)FileFormat).headerU.Textures)
                            texture.Export(Path.Combine(Folder, $"{texture.Text}{Extension}"));
                    }
                }

                if (FileFormat is BFLIM)
                {
                    ((BFLIM)FileFormat).Export(Path.Combine(Folder, $"{FileFormat.FileName}{Extension}"));
                }

                FileFormat.Unload();
            }

            public void CreateNew(object sender, EventArgs args)
            {
                BFLIM bflim = CreateNewFromImage();
                if (bflim == null) return;

                var form = new GenericEditorForm(false, bflim.OpenForm());
                LibraryGUI.CreateMdiWindow(form);
                bflim.UpdateForm();
            }
        }


        public static BFLIM CreateNewFromImage()
        {
            BFLIM bflim = new BFLIM();
            bflim.CanSave = true;
            bflim.IFileInfo = new IFileInfo();
            bflim.header = new Header();

            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Multiselect = false;
            ofd.Filter = FileFilters.GTX;
            if (ofd.ShowDialog() != DialogResult.OK)
                return null;

            FTEX ftex = new FTEX();
            ftex.ReplaceTexture(ofd.FileName, TEX_FORMAT.BC3_UNORM_SRGB, 1, 0, bflim.SupportedFormats, true,  false, true, false);
            if (ftex.texture != null)
            {
                bflim.Text = $"{Path.GetFileNameWithoutExtension(ofd.FileName)}.bflim";
                bflim.image = new Image();
                bflim.image.Swizzle = (byte)ftex.texture.Swizzle;
                bflim.image.BflimFormat = FormatsWiiU.FirstOrDefault(x => x.Value == ftex.Format).Key;
                if (ftex.UseBc4Alpha)
                    bflim.image.BflimFormat = 16;

                bflim.image.Height = (ushort)ftex.texture.Height;
                bflim.image.Width = (ushort)ftex.texture.Width;

                bflim.Format = FormatsWiiU[bflim.image.BflimFormat];
                bflim.Width = bflim.image.Width;
                bflim.Height = bflim.image.Height;
                bflim.ImageData = ftex.texture.Data;

                bflim.LoadComponents(bflim.Format, ftex.UseBc4Alpha);
            }

            return bflim;
        }

        public override string ExportFilter => FileFilters.GTX;
        public override string ReplaceFilter => FileFilters.GTX;

        private void Replace(object sender, EventArgs args)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = ReplaceFilter;
            ofd.FileName = Text;

            ofd.Multiselect = false;

            if (ofd.ShowDialog() == DialogResult.OK)
            {
                Replace(ofd.FileName);
            }
        }

        public override void Replace(string FileName)
        {
            uint swizzle = (image.Swizzle >> 8) & 7;

            FTEX ftex = new FTEX();
            ftex.ReplaceTexture(FileName, Format, 1, swizzle, SupportedFormats, true, true, true, false);
            if (ftex.texture != null)
            {
                image.Swizzle = ftex.texture.Swizzle;
                image.BflimFormat = FormatsWiiU.FirstOrDefault(x => x.Value == ftex.Format).Key;
                image.Height = (ushort)ftex.texture.Height;
                image.Width = (ushort)ftex.texture.Width;

                if (ftex.UseBc4Alpha)
                    image.BflimFormat = 16;

                Format = FormatsWiiU[image.BflimFormat];
                Width = image.Width;
                Height = image.Height;

                ImageData = ftex.texture.Data;

                LoadComponents(Format, ftex.UseBc4Alpha);

                if (RenderableTex != null) //Reload bflim in opengl if used
                    LoadOpenGLTexture();

                UpdateForm();
            }
        }


        private void Save(object sender, EventArgs args)
        {
            List<IFileFormat> formats = new List<IFileFormat>();
            formats.Add(this);

            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Filter = Utils.GetAllFilters(formats);
            sfd.FileName = FileName;

            if (sfd.ShowDialog() == DialogResult.OK)
            {
                STFileSaver.SaveFileFormat(this, sfd.FileName);
            }
        }

        public class Properties
        {
            [Browsable(true)]
            [ReadOnly(true)]
            [Description("Height of the image.")]
            [Category("Image Info")]
            public uint Height { get; set; }

            [Browsable(true)]
            [ReadOnly(true)]
            [Description("Width of the image.")]
            [Category("Image Info")]
            public uint Width { get; set; }

            [Browsable(true)]
            [ReadOnly(true)]
            [Description("Format of the image.")]
            [Category("Image Info")]
            public TEX_FORMAT Format { get; set; }

            [Browsable(true)]
            [ReadOnly(true)]
            [Description("Depth of the image (3D type).")]
            [Category("Image Info")]
            public uint Depth { get; set; }

            [Browsable(true)]
            [ReadOnly(true)]
            [Description("Mip map count of the image.")]
            [Category("Image Info")]
            public uint MipCount { get; set; }

            [Browsable(true)]
            [ReadOnly(true)]
            [Description("Array count of the image for multiple surfaces.")]
            [Category("Image Info")]
            public uint ArrayCount { get; set; }

            [Browsable(true)]
            [ReadOnly(true)]
            [Description("The image size in bytes.")]
            [Category("Image Info")]
            public uint ImageSize { get; set; }

            [Browsable(true)]
            [ReadOnly(true)]
            [Description("The image tilemode.")]
            [Category("Image Info")]
            public GX2.GX2TileMode TileMode { get; set; }

            [Browsable(true)]
            [ReadOnly(true)]
            [Category("Image Info")]
            public uint Swizzle { get; set; }
        }

        Header header;
        Image image;
        byte[] ImageData;

        public void Load(System.IO.Stream stream)
        {
            CanSave = true;

            Text = FileName;

            using (var reader = new FileReader(stream))
            {
                uint FileSize = (uint)reader.BaseStream.Length;
                reader.Seek(FileSize - 0x28, SeekOrigin.Begin);

                header = new Header();
                header.Read(reader);

                bool Is3DS = reader.ByteOrder == Syroot.BinaryData.ByteOrder.LittleEndian;

                reader.Seek(header.HeaderSize + FileSize - 0x28, SeekOrigin.Begin);
                image = new Image(Is3DS);
                image.Read(reader);

                bool isBc4Alpha = image.BflimFormat == 16;

                if (Is3DS)
                    Format = Formats3DS[image.BflimFormat];
                else
                    Format = FormatsWiiU[image.BflimFormat];


                Width = image.Width;
                Height = image.Height;

                LoadComponents(Format, isBc4Alpha);

                uint ImageSize = reader.ReadUInt32();

                reader.Position = 0;
                ImageData = reader.ReadBytes((int)ImageSize);

                if (!PluginRuntime.bflimTextures.ContainsKey(Text))
                    PluginRuntime.bflimTextures.Add(Text, this);
            }
        }

        private void LoadComponents(TEX_FORMAT Format, bool isBc4Alpha)
        {
            switch (Format)
            {
                case TEX_FORMAT.BC5_SNORM:
                case TEX_FORMAT.BC5_UNORM:
                    RedChannel = STChannelType.Red;
                    GreenChannel = STChannelType.Red;
                    BlueChannel = STChannelType.Red;
                    AlphaChannel = STChannelType.Green;
                    break;
                case TEX_FORMAT.BC4_SNORM:
                case TEX_FORMAT.BC4_UNORM:
                    RedChannel = STChannelType.Red;
                    GreenChannel = STChannelType.Red;
                    BlueChannel = STChannelType.Red;
                    AlphaChannel = STChannelType.One;

                    if (isBc4Alpha)
                    {
                        RedChannel = STChannelType.One;
                        GreenChannel = STChannelType.One;
                        BlueChannel = STChannelType.One;
                        AlphaChannel = STChannelType.Red;
                    }
                    break;
            }
        }

        public static Dictionary<byte, TEX_FORMAT> Formats3DS = new Dictionary<byte, TEX_FORMAT>()
        {
            [0] = TEX_FORMAT.L8,
            [1] = TEX_FORMAT.A8_UNORM,
            [2] = TEX_FORMAT.LA4,
            [3] = TEX_FORMAT.LA8,
            [4] = TEX_FORMAT.HIL08,
            [5] = TEX_FORMAT.B5G6R5_UNORM,
            [6] = TEX_FORMAT.B8G8R8A8_UNORM,
            [7] = TEX_FORMAT.B5G5R5A1_UNORM,
            [8] = TEX_FORMAT.B4G4R4A4_UNORM,
            [9] = TEX_FORMAT.R8G8B8A8_UNORM,
            [10] = TEX_FORMAT.ETC1_UNORM,
            [11] = TEX_FORMAT.ETC1_A4,
            [12] = TEX_FORMAT.BC1_UNORM,
            [13] = TEX_FORMAT.BC2_UNORM,
            [14] = TEX_FORMAT.BC3_UNORM,
            [15] = TEX_FORMAT.BC4_UNORM, //BC4L_UNORM
            [16] = TEX_FORMAT.BC4_UNORM, //BC4A_UNORM
            [17] = TEX_FORMAT.BC5_UNORM,
            [18] = TEX_FORMAT.L4,
            [19] = TEX_FORMAT.A4,
        };

        public static Dictionary<byte, TEX_FORMAT> FormatsWiiU = new Dictionary<byte, TEX_FORMAT>()
        {
            [0] = TEX_FORMAT.L8,
            [1] = TEX_FORMAT.A8_UNORM,
            [2] = TEX_FORMAT.LA4,
            [3] = TEX_FORMAT.LA8,
            [4] = TEX_FORMAT.R8G8_UNORM, //HILO8
            [5] = TEX_FORMAT.B5G6R5_UNORM,
            [6] = TEX_FORMAT.B8G8R8A8_UNORM,
            [7] = TEX_FORMAT.B5G5R5A1_UNORM,
            [8] = TEX_FORMAT.B4G4R4A4_UNORM,
            [9] = TEX_FORMAT.R8G8B8A8_UNORM,
            [10] = TEX_FORMAT.ETC1_UNORM,
            [11] = TEX_FORMAT.ETC1_A4,
            [12] = TEX_FORMAT.BC1_UNORM,
            [13] = TEX_FORMAT.BC2_UNORM,
            [14] = TEX_FORMAT.BC3_UNORM,
            [15] = TEX_FORMAT.BC4_UNORM, //BC4L_UNORM
            [16] = TEX_FORMAT.BC4_UNORM, //BC4A_UNORM
            [17] = TEX_FORMAT.BC5_UNORM,
            [18] = TEX_FORMAT.L4,
            [19] = TEX_FORMAT.A4,
            [20] = TEX_FORMAT.R8G8B8A8_UNORM_SRGB,
            [21] = TEX_FORMAT.BC1_UNORM_SRGB,
            [22] = TEX_FORMAT.BC2_UNORM_SRGB,
            [23] = TEX_FORMAT.BC3_UNORM_SRGB,
            [24] = TEX_FORMAT.R10G10B10A2_UNORM,
            [25] = TEX_FORMAT.R5G5B5_UNORM,
        };

        public override void SetImageData(System.Drawing.Bitmap bitmap, int ArrayLevel)
        {
            if (bitmap == null || image == null)
                return; //Image is likely disposed and not needed to be applied

            MipCount = 1;
            var Gx2Format = FTEX.ConvertToGx2Format(Format);

            uint swizzle = (image.Swizzle >> 8) & 7;

            try
            {
                //Create image block from bitmap first
                var data = GenerateMipsAndCompress(bitmap, MipCount, Format);

                //Swizzle and create surface
                var surface = GX2.CreateGx2Texture(data, Text,
                    (uint)image.TileMode,
                    (uint)0,
                    (uint)image.Width,
                    (uint)image.Height,
                    (uint)1,
                    (uint)Gx2Format,
                    (uint)swizzle,
                    (uint)1,
                    (uint)MipCount
                    );

                image.Swizzle = surface.swizzle;
                image.BflimFormat = FormatsWiiU.FirstOrDefault(x => x.Value == Format).Key;
                image.Height = (ushort)surface.height;
                image.Width = (ushort)surface.width;

                Width = image.Width;
                Height = image.Height;

                ImageData = surface.data;

                IsEdited = true;
                LoadOpenGLTexture();
                LibraryGUI.UpdateViewport();
            }
            catch (Exception ex)
            {
                STErrorDialog.Show("Failed to swizzle and compress image " + Text, "Error", ex.ToString());
            }
        }

        public override byte[] GetImageData(int ArrayLevel = 0, int MipLevel = 0, int DepthLevel = 0)
        {
            if (image.Is3DS)
            {
                PlatformSwizzle = PlatformSwizzle.Platform_3DS;
                return ImageData;
            }
            else
            {
                uint bpp = GetBytesPerPixel(Format);

                GX2.GX2Surface surf = new GX2.GX2Surface();
                surf.bpp = bpp;
                surf.height = image.Height;
                surf.width = image.Width;
                surf.aa = (uint)GX2.GX2AAMode.GX2_AA_MODE_1X;
                surf.alignment = image.Alignment;
                surf.depth = 1;
                surf.dim = (uint)GX2.GX2SurfaceDimension.DIM_2D;
                surf.format = (uint)FTEX.ConvertToGx2Format(Format);
                surf.use = (uint)GX2.GX2SurfaceUse.USE_COLOR_BUFFER;
                surf.pitch = 0;
                surf.data = ImageData;
                surf.numMips = 1;
                surf.mipOffset = new uint[0];
                surf.mipData = ImageData;
                surf.tileMode = (uint)image.TileMode;
                surf.swizzle = image.Swizzle;
                surf.numArray = 1;

                return GX2.Decode(surf, ArrayLevel, MipLevel);
            }
        }

        public void Unload()
        {
        }

        public void Save(System.IO.Stream stream)
        {
            using (var writer = new FileWriter(stream, true))
            {
                writer.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian;

                writer.Write(ImageData);

                long headerPos = writer.Position;

                header.Write(writer);
                image.Write(writer);
                writer.Write(ImageData.Length);

                writer.Seek(headerPos + 0x0C, SeekOrigin.Begin);
                writer.Write((uint)writer.BaseStream.Length);
            }
        }

        public class Header
        {
            public ushort ByteOrderMark;
            public ushort HeaderSize;
            public uint Version;
            public ushort blockount;
            public ushort padding;

            public Header()
            {
                ByteOrderMark = 65279;
                HeaderSize = 20;
                blockount = 1;
                Version = 33685504;
            }

            public void Read(FileReader reader)
            {
                reader.ByteOrder = Syroot.BinaryData.ByteOrder.BigEndian;

                reader.ReadSignature(4, "FLIM");
                ByteOrderMark = reader.ReadUInt16();
                reader.CheckByteOrderMark(ByteOrderMark);
                HeaderSize = reader.ReadUInt16();
                Version = reader.ReadUInt32();
                uint fileSize = reader.ReadUInt32();
                blockount = reader.ReadUInt16();
                padding = reader.ReadUInt16();
            }

            public void Write(FileWriter writer)
            {
                writer.WriteSignature("FLIM");
                writer.Write((ushort)0xFEFF);
                writer.Write(HeaderSize);
                writer.Write(Version);
                writer.Write(uint.MaxValue);
                writer.Write(blockount);
                writer.Write(padding);
            }
        }
        public class Image
        {
            public uint Size;
            public ushort Width;
            public ushort Height;
            public ushort Alignment;
            public byte BflimFormat;
            public byte Flags;

            public bool Is3DS = false;

            public Image(bool is3DS)
            {
                Is3DS = is3DS;
            }

            public Image()
            {
                Alignment = 8192;
                Flags = 0xC4;
                Size = 16;
            }

            public GX2.GX2TileMode TileMode
            {
                get
                {
                    return (GX2.GX2TileMode) ((int)Flags & 31);
                }
                set
                {
                    Flags = (byte)((int)Flags & 224 | (int)(byte)value & 31);
                }
            }

            public uint Swizzle
            {
                get
                {
                    return (uint)(((int)((uint)Flags >> 5) & 7) << 8);
                }
                set
                {
                    Flags = (byte)((int)Flags & 31 | (int)(byte)(value >> 8) << 5);
                }
            }

            public void Read(FileReader reader)
            {
                reader.ReadSignature(4, "imag");
                Size = reader.ReadUInt32();
                Width = reader.ReadUInt16();
                Height = reader.ReadUInt16();
                Alignment = reader.ReadUInt16();
                BflimFormat = reader.ReadByte();
                Flags = reader.ReadByte();
            }

            public void Write(FileWriter writer)
            {
                writer.WriteSignature("imag");
                writer.Write(Size);
                writer.Write(Width);
                writer.Write(Height);
                writer.Write(Alignment);
                writer.Write(BflimFormat);
                writer.Write(Flags);
            }
        }
    }
}
