﻿using OpenVIII;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;

namespace DumpStrings
{
    internal class Program
    {
        #region Properties

        private static XmlWriterSettings XmlWriterSettings { get; } = new XmlWriterSettings()
        {
            Indent = true,
            IndentChars = "\t",
            NewLineOnAttributes = true,
            Encoding = Encoding.Unicode
        };

        private static IEnumerable<(Strings.FileID fileKey, int sectionKey, int id, FF8StringReference Value)> CollectionOfStrings
        {
            get
            {
                (Strings.FileID fileKey, int sectionKey, int id, FF8StringReference Value) Get(Strings.FileID fileID,
                    int sectionID, int inputID, FF8StringReference value)
                    => (fileID, sectionID, inputID, value); // this is for having a tuple instead of anonymous type

                var strings = (
                    from file in Memory.Strings
                    from section in file.Value
                    from ff8StringReference in section.Value.Select((x, i) => new { Key = i, Value = x })
                    where ff8StringReference.Value != null && ff8StringReference.Value.Length > 0
                    select
                        Get(file.Key, section.Key, ff8StringReference.Key, ff8StringReference.Value)
                ).ToList().AsReadOnly();
                return strings;
            }
        }

        #endregion Properties

        #region Methods

        [SuppressMessage("ReSharper", "PossibleMultipleEnumeration")]
        private static void DumpReverseStrings()
        {
            using (var w =
                XmlWriter.Create(
                    new FileStream($"reverse_strings_{Extended.GetLanguageShort().ToLower()}.xml", FileMode.Create, FileAccess.Write,
                        FileShare.ReadWrite),
                    XmlWriterSettings))
            {
                w.WriteStartDocument();
                w.WriteStartElement("ReverseStrings"); //<ReverseStrings>
                w.WriteAttributeString("lang", Extended.GetLanguageShort().ToUpper());

                var strings = CollectionOfStrings;

                w.WriteAttributeString("count", strings.Count().ToString("D"));
                foreach ((var fileID, var sectionID, var id, var value) in strings)
                {
                    w.WriteStartElement("String");
                    w.WriteAttributeString(nameof(fileID).ToLower(), fileID.ToString("D"));
                    w.WriteAttributeString(nameof(sectionID).ToLower(), sectionID.ToString("D"));
                    w.WriteAttributeString(nameof(id)+$"_{Extended.GetLanguageShort().ToLower()}", id.ToString("D"));
                    w.WriteAttributeString(nameof(value.Offset).ToLower() + $"_{Extended.GetLanguageShort().ToLower()}", value.Offset.ToString("X"));
                    w.WriteAttributeString(nameof(value.Length).ToLower() + $"_{Extended.GetLanguageShort().ToLower()}", value.Length.ToString("D"));
                    w.WriteAttributeString(nameof(value) + $"_{Extended.GetLanguageShort().ToLower()}", value);
                    w.WriteEndElement();
                }
                w.WriteEndElement(); //</ReverseStrings>
                w.WriteEndDocument();
            }
        }

        private static void DumpStrings()
        {
            using (var w =
                XmlWriter.Create(
                    new FileStream($"strings_{Extended.GetLanguageShort().ToLower()}.xml", FileMode.Create, FileAccess.Write,
                        FileShare.ReadWrite),
                    XmlWriterSettings))
            {
                w.WriteStartDocument();
                w.WriteStartElement("Strings"); //<Strings>
                w.WriteAttributeString("lang", Extended.GetLanguageShort().ToUpper());

                var strings = CollectionOfStrings;
                var fileGroups = strings.GroupBy(x => x.fileKey).ToList().AsReadOnly();
                //var fileGroupsCounts = fileGroups.Select(group => new {group.Key, Count = group.Count()});
                var fileGroupsCount = fileGroups.Count();
                w.WriteAttributeString("count", fileGroupsCount.ToString("D"));
                foreach (var fileGroup in fileGroups)
                {
                    w.WriteStartElement("File");
                    w.WriteAttributeString("id", fileGroup.Key.ToString());
                    var sectionGroups = fileGroup.GroupBy(x => x.sectionKey).ToList().AsReadOnly();
                    var sectionGroupsCount = sectionGroups.Count();
                    w.WriteAttributeString("count", sectionGroupsCount.ToString("D"));
                    foreach (var sectionGroup in sectionGroups)
                    {
                        w.WriteStartElement("Section");
                        w.WriteAttributeString("id", sectionGroup.Key.ToString());
                        w.WriteAttributeString("count", sectionGroup.Count().ToString("D"));
                        foreach (var ff8StringReference in sectionGroup)
                        {
                            w.WriteStartElement("String");
                            w.WriteAttributeString("id", ff8StringReference.id.ToString());
                            w.WriteAttributeString("offset", ff8StringReference.Value.Offset.ToString("X"));
                            w.WriteAttributeString("size", ff8StringReference.Value.Length.ToString("D"));
                            w.WriteString(ff8StringReference.Value);
                            w.WriteEndElement();
                        }

                        w.WriteEndElement();
                    }

                    w.WriteEndElement();
                }

                w.WriteEndElement(); //</Strings>
                w.WriteEndDocument();
            }
        }

        private static void Main(string[] args)
        {
            Memory.Init(null, null, null, args);
            DumpStrings();
            DumpReverseStrings();
        }

        #endregion Methods
    }
}