using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Resources;
using System.Reflection;
using System.Windows.Forms;
using DSPRE.Resources;
using static DSPRE.RomInfo;
using DSPRE.MessageEnc;

namespace DSPRE.ROMFiles
{
    /// <summary>
    /// Class to store message data from DS Pokémon games
    /// </summary>
    public class TextArchive : RomFile
    {
        #region Fields (2)

        public List<string> messages;
        public int initialKey;

        #endregion Fields (2)

        #region Constructors (1)

        public TextArchive(FileStream messageStream, List<string> msg, bool discardLines = false)
        {
            messages = msg ?? EncryptText.ReadMessageArchive(messageStream, discardLines);
        }

        public TextArchive(int ID, List<string> msg = null, bool discardLines = false) : this(new FileStream($"{gameDirs[DirNames.textArchives].unpackedDir}\\{ID:D4}", FileMode.Open), msg, discardLines)
        {
        }

        #endregion Constructors (1)

        #region Methods (2)

        public int[] EncodeString(string currentMessage, int stringIndex, int stringSize)
        { // Converts string to hex characters
            ResourceManager GetByte = new ResourceManager("DSPRE.Resources.WriteText", Assembly.GetExecutingAssembly());

            int[] pokemonMessage = new int[stringSize - 1];
            var charArray = currentMessage.ToCharArray();
            int count = 0;
            try
            {
                for (int i = 0; i < currentMessage.Length; i++)
                {
                    if (charArray[i] == '\\')
                    {
                        if (charArray[i + 1] == 'r')
                        {
                            pokemonMessage[count] = 0x25BC;
                            i++;
                        }
                        else
                        {
                            if (charArray[i + 1] == 'n')
                            {
                                pokemonMessage[count] = 0xE000;
                                i++;
                            }
                            else
                            {
                                if (charArray[i + 1] == 'f')
                                {
                                    pokemonMessage[count] = 0x25BD;
                                    i++;
                                }
                                else
                                {
                                    if (charArray[i + 1] == 'v')
                                    {
                                        pokemonMessage[count] = 0xFFFE;
                                        count++;
                                        string characterID = ((char)charArray[i + 2]).ToString() + ((char)charArray[i + 3]).ToString() + ((char)charArray[i + 4]).ToString() + ((char)charArray[i + 5]).ToString();
                                        pokemonMessage[count] = (int)Convert.ToUInt32(characterID, 16);
                                        i += 5;
                                    }
                                    else
                                    {
                                        //This looks like it can be optimized
                                        if (charArray[i + 1] == 'x' && charArray[i + 2] == '0' && charArray[i + 3] == '0' && charArray[i + 4] == '0' && charArray[i + 5] == '0')
                                        {
                                            pokemonMessage[count] = 0x0000;
                                            i += 5;
                                        }
                                        else
                                        {
                                            if (charArray[i + 1] == 'x' && charArray[i + 2] == '0' && charArray[i + 3] == '0' && charArray[i + 4] == '0' && charArray[i + 5] == '1')
                                            {
                                                pokemonMessage[count] = 0x0001;
                                                i += 5;
                                            }
                                            else
                                            {
                                                string characterID = ((char)charArray[i + 2]).ToString() + ((char)charArray[i + 3]).ToString() + ((char)charArray[i + 4]).ToString() + ((char)charArray[i + 5]).ToString();
                                                pokemonMessage[count] = (int)Convert.ToUInt32(characterID, 16);
                                                i += 5;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        if (charArray[i] == '[')
                        {
                            if (charArray[i + 1] == 'P')
                            {
                                pokemonMessage[count] = 0x01E0;
                                i += 3;
                            }
                            if (charArray[i + 1] == 'M')
                            {
                                pokemonMessage[count] = 0x01E1;
                                i += 3;
                            }
                        }
                        else
                        {
                            pokemonMessage[count] = (int)Convert.ToUInt32(GetByte.GetString(((int)charArray[i]).ToString()), 16);
                        }
                    }
                    count++;
                }
            }
            catch (FormatException)
            {
                MessageBox.Show("Format exception. Assembled so far: " + Environment.NewLine + pokemonMessage);
            }
            return pokemonMessage;
        }

        public int GetStringLength(string currentMessage)
        { // Calculates string length
            int count = 0;
            var charArray = currentMessage.ToCharArray();
            for (int i = 0; i < currentMessage.Length; i++)
            {
                if (charArray[i] == '\\')
                {
                    if (charArray[i + 1] == 'r')
                    {
                        count++;
                        i++;
                    }
                    else
                    {
                        if (charArray[i + 1] == 'n')
                        {
                            count++;
                            i++;
                        }
                        else
                        {
                            if (charArray[i + 1] == 'f')
                            {
                                count++;
                                i++;
                            }
                            else
                            {
                                if (charArray[i + 1] == 'v')
                                {
                                    count += 2;
                                    i += 5;
                                }
                                else
                                {
                                    if (charArray[i + 1] == 'x' && charArray[i + 2] == '0' && charArray[i + 3] == '0' && charArray[i + 4] == '0' && charArray[i + 5] == '0')
                                    {
                                        count++;
                                        i += 5;
                                    }
                                    else
                                    {
                                        if (charArray[i + 1] == 'x' && charArray[i + 2] == '0' && charArray[i + 3] == '0' && charArray[i + 4] == '0' && charArray[i + 5] == '1')
                                        {
                                            count++;
                                            i += 5;
                                        }
                                        else
                                        {
                                            count++;
                                            i += 5;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                else
                {
                    if (charArray[i] == '[')
                    {
                        if (charArray[i + 1] == 'P')
                        {
                            count++;
                            i += 3;
                        }
                        if (charArray[i + 1] == 'M')
                        {
                            count++;
                            i += 3;
                        }
                    }
                    else
                    {
                        count++;
                    }
                }
            }
            count++;
            return count;
        }

        private byte[] ToByteArray(List<string> msgSource)
        {
            MemoryStream newData = new MemoryStream();
            using (BinaryWriter writer = new BinaryWriter(newData))
            {
                writer.Write((ushort)msgSource.Count);
                writer.Write((ushort)initialKey);

                int key = (initialKey * 0x2FD) & 0xFFFF;
                int key2 = 0;
                int realKey = 0;
                int offset = 0x4 + (msgSource.Count * 8);
                int[] stringSize = new int[msgSource.Count];

                for (int i = 0; i < msgSource.Count; i++)
                { // Reads and stores string offsets and sizes
                    key2 = (key * (i + 1) & 0xFFFF);
                    realKey = key2 | (key2 << 16);
                    writer.Write(offset ^ realKey);
                    int length = GetStringLength(msgSource[i]);
                    stringSize[i] = length;
                    writer.Write(length ^ realKey);
                    offset += length * 2;
                }

                for (int i = 0; i < msgSource.Count; i++)
                { // Encodes strings and writes them to file
                    key = (0x91BD3 * (i + 1)) & 0xFFFF;
                    int[] currentString = EncodeString(msgSource[i], i, stringSize[i]);

                    for (int j = 0; j < stringSize[i] - 1; j++)
                    {
                        writer.Write((ushort)(currentString[j] ^ key));
                        key += 0x493D;
                        key &= 0xFFFF;
                    }
                    writer.Write((ushort)(0xFFFF ^ key));
                }
            }
            return newData.ToArray();
        }

        public override string ToString()
        {
            return string.Join(Environment.NewLine, messages);
        }

        public override byte[] ToByteArray()
        {
            return this.ToByteArray(messages);
        }

        public void SaveToFileDefaultDir(int IDtoReplace, bool showSuccessMessage = true)
        {
            bool success = EncryptText.WriteMessageArchive(IDtoReplace, messages, IDtoReplace == trainerNamesMessageNumber);
            if (showSuccessMessage && success)
            {
                MessageBox.Show("Saved successfully!", "", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        public void SaveToFileExplorePath(string suggestedFileName, bool showSuccessMessage = true)
        {
            SaveToFileExplorePath("Gen IV Text Archive", "msg", suggestedFileName, showSuccessMessage);
        }

        #endregion Methods (2)
    }
}