﻿using System;
using System.IO;
using System.Xml;
using Oni.Imaging;
using Oni.Metadata;
using Oni.Xml;

namespace Oni.Motoko
{
    internal sealed class TextureXmlExporter : RawXmlExporter
    {
        private InstanceDescriptor txmp;
        private string outputDirPath;
        private string baseFileName;

        private TextureXmlExporter(BinaryReader reader, XmlWriter writer)
            : base(reader, writer)
        {
        }

        public static void Export(InstanceDescriptor txmp, XmlWriter writer, string outputDirPath, string baseFileName)
        {
            using (var reader = txmp.OpenRead(128))
            {
                var exporter = new TextureXmlExporter(reader, writer) {
                    txmp = txmp,
                    outputDirPath = outputDirPath,
                    baseFileName = baseFileName
                };

                exporter.Export();
            }
        }

        private void Export()
        {
            var flags = (InstanceMetadata.TXMPFlags)Reader.ReadInt32();
            int width = Reader.ReadInt16();
            int height = Reader.ReadInt16();
            var format = (InstanceMetadata.TXMPFormat)Reader.ReadInt32();
            var txan = Reader.ReadInstance();
            var envmap = Reader.ReadInstance();
            int dataOffset = Reader.ReadInt32();

            //
            // Cleanup unwanted/unneeded flags.
            //

            flags &= ~(InstanceMetadata.TXMPFlags.Unknown0010
                | InstanceMetadata.TXMPFlags.SwapBytes
                | InstanceMetadata.TXMPFlags.HasEnvMap);

            Xml.WriteStartElement("Texture");

            string name = txmp.FullName;

            if (name.StartsWith("TXMP", StringComparison.Ordinal))
                name = name.Substring(4);

            Xml.WriteElementString("Flags", flags.ToString().Replace(",", " "));
            Xml.WriteElementString("Format", format.ToString());

            if (envmap != null)
                Xml.WriteElementString("EnvMap", envmap.FullName);

            if (txan == null)
            {
                string fileName = baseFileName + ".tga";
                TgaWriter.Write(TextureDatReader.Read(txmp).Surfaces[0], Path.Combine(outputDirPath, fileName));

                Xml.WriteElementString("Image", fileName);
            }
            else
            {
                WriteAnimationFrames2(txan);
            }

            Xml.WriteEndElement();
        }

        private void WriteAnimationFrames2(InstanceDescriptor txan)
        {
            using (var txanReader = txan.OpenRead(12))
            {
                int speed = txanReader.ReadInt16();
                txanReader.Skip(6);
                int count = txanReader.ReadInt32();

                Xml.WriteElementString("Speed", XmlConvert.ToString(speed));

                for (int i = 0; i < count; i++)
                {
                    InstanceDescriptor frame;

                    if (i == 0)
                    {
                        txanReader.Skip(4);
                        frame = txmp;
                    }
                    else
                    {
                        frame = txanReader.ReadInstance();
                    }

                    string fileName = string.Format("{0}_{1:d3}.tga", baseFileName, i);
                    TgaWriter.Write(TextureDatReader.Read(frame).Surfaces[0], Path.Combine(outputDirPath, fileName));

                    Xml.WriteElementString("Image", fileName);
                }
            }
        }
    }
}
