﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using Oni.Xml;

namespace Oni.Sound
{
    internal class SabdXmlExporter : RawXmlExporter
    {
        private SabdXmlExporter(BinaryReader reader, XmlWriter xml)
            : base(reader, xml)
        {
        }

        public static void Export(BinaryReader reader, XmlWriter xml)
        {
            var exporter = new SabdXmlExporter(reader, xml);
            exporter.Export();
        }

        private void Export()
        {
            var data = new SoundAnimationData(Reader);
            data.Write(Xml);
        }

        private class SoundAnimationData
        {
            private readonly string variant;
            private readonly List<SoundAssignment> assignments;

            private enum Tag
            {
                SAFT = 0x54464153,
                SAVT = 0x54564153,
                SASA = 0x41534153
            }

            public SoundAnimationData(BinaryReader reader)
            {
                int dataEnd = reader.ReadInt32() + reader.Position;

                int tag = reader.ReadInt32();

                if ((Tag)tag != Tag.SAFT)
                    throw new InvalidDataException(string.Format("Unknown tag {0:X} found in sound animation", tag));

                int size = reader.ReadInt32();
                int unknown = reader.ReadInt32();

                tag = reader.ReadInt32();

                if ((Tag)tag != Tag.SAVT)
                    throw new InvalidDataException(string.Format("Unknown tag {0:X} found in sound animation", tag));

                size = reader.ReadInt32();
                variant = reader.ReadString(32);

                assignments = new List<SoundAssignment>();

                while (reader.Position < dataEnd)
                {
                    tag = reader.ReadInt32();

                    if ((Tag)tag != Tag.SASA)
                        throw new InvalidDataException(string.Format("Unknown tag {0:X} found in sound animation", tag));

                    size = reader.ReadInt32();
                    assignments.Add(new SoundAssignment(reader));
                }
            }

            public void Write(XmlWriter xml)
            {
                xml.WriteStartElement("SoundAnimation");
                xml.WriteAttributeString("Variant", variant);

                foreach (var assignment in assignments)
                    assignment.Write(xml);

                xml.WriteEndElement();
            }
        }

        private class SoundAssignment
        {
            private readonly int frame;
            private readonly string modifier;
            private readonly string type;
            private readonly string animationName;
            private readonly string soundName;

            public SoundAssignment(BinaryReader reader)
            {
                frame = reader.ReadInt32();
                modifier = reader.ReadString(32);
                type = reader.ReadString(32);
                animationName = reader.ReadString(32);
                soundName = reader.ReadString(32);
            }

            public void Write(XmlWriter xml)
            {
                xml.WriteStartElement("Assignment");
                xml.WriteStartElement("Target");

                if (type != "Animation")
                    xml.WriteElementString("Type", type.Replace(" ", ""));
                else
                    xml.WriteElementString("Animation", animationName);

                if (modifier != "Any")
                    xml.WriteElementString("Modifier", modifier.Replace(" ", ""));

                xml.WriteElementString("Frame", XmlConvert.ToString(frame));
                xml.WriteEndElement();

                xml.WriteElementString("Sound", soundName);
                xml.WriteEndElement();
            }
        }
    }
}
