using System;
using System.Collections.Generic;
using System.Text;

namespace WSPOSInitiative.Common
{
    public class BinaryConversionHelper
    {
        public static string ConvertUnicodeStringToUnicodeARTSBinary(string str)
        {
            StringBuilder sb = new StringBuilder();
            foreach (ushort c in str)
            {
                sb.AppendFormat("\\u{0,0:x4}", c);
            }
            return sb.ToString();
        }
        public static string ConvertUnicodeARTSBinaryToUnicodeString(string bin)
        {
            string[] tokens = bin.Split(new string[] { "\\u" }, StringSplitOptions.None);
            if (tokens.Length < 2)
            {
                throw new ArgumentException("Bad ARTSBinary format.");
            }
            if (tokens[0] != string.Empty)
            {
                throw new ArgumentException("Bad ARTSBinary format. ARTSBinary must be begun \\u");
            }

            StringBuilder sb = new StringBuilder();
            for (int i = 1; i < tokens.Length; i++)
            {
                var token = tokens[i];

                if (token.Length != 4)
                {
                    throw new ArgumentException("Bad ARTSBinary format.");
                }
                if (ValidateARTSBinaryToken(token) == false)
                {
                    throw new ArgumentException("Bad ARTSBinary format.");
                }

                int value = Convert.ToInt32(token, 16);
                char c = (char)value;

                sb.Append(c);
            }

            return sb.ToString();
        }

        public static string ConvertUnicodeARTSBinaryToUnicodeNIBBLE(string bin)
        {
            string[] tokens = bin.Split(new string[] { "\\u" }, StringSplitOptions.None);
            if (tokens.Length < 2)
            {
                throw new ArgumentException("Bad ARTSBinary format.");
            }
            if (tokens[0] != string.Empty)
            {
                throw new ArgumentException("Bad ARTSBinary format. ARTSBinary must be begun \\u");
            }

            StringBuilder unicodeSb = new StringBuilder();
            for (int i = 1; i < tokens.Length; i++)
            {
                var token = tokens[i];

                if (token.Length != 4)
                {
                    throw new ArgumentException("Bad ARTSBinary format.");
                }
                if (ValidateARTSBinaryToken(token) == false)
                {
                    throw new ArgumentException("Bad ARTSBinary format.");
                }

                int unicodeValue = Convert.ToInt32(token, 16);
                char unicodeChar = (char)unicodeValue;
                unicodeSb.Append(unicodeChar);
            }
            string unicodeString = unicodeSb.ToString();

            byte[] unicodeBytes = Encoding.Unicode.GetBytes(unicodeString);

            return ConvertBytesToNIBBLE(unicodeBytes);
        }

        public static string ConvertUnicodeARTSBinaryToSJISNIBBLE(string bin)
        {
            string[] tokens = bin.Split(new string[] { "\\u" }, StringSplitOptions.None);
            if (tokens.Length < 2)
            {
                throw new ArgumentException("Bad ARTSBinary format.");
            }
            if (tokens[0] != string.Empty)
            {
                throw new ArgumentException("Bad ARTSBinary format. ARTSBinary must be begun \\u");
            }

            StringBuilder unicodeSb = new StringBuilder();
            for (int i = 1; i < tokens.Length; i++)
            {
                var token = tokens[i];

                if (token.Length != 4)
                {
                    throw new ArgumentException("Bad ARTSBinary format.");
                }
                if (ValidateARTSBinaryToken(token) == false)
                {
                    throw new ArgumentException("Bad ARTSBinary format.");
                }

                int unicodeValue = Convert.ToInt32(token, 16);
                char unicodeChar = (char)unicodeValue;
                unicodeSb.Append(unicodeChar);
            }
            string unicodeString = unicodeSb.ToString();

            byte[] sjisBytes = Encoding.GetEncoding(932).GetBytes(unicodeString);

            return ConvertBytesToNIBBLE(sjisBytes);
        }

        public static string ConvertBytesToNIBBLE(byte[] bytes)
        {
            StringBuilder nibbleSb = new StringBuilder();
            for (int i = 0; i < bytes.Length; i++)
            {
                byte oneByte = bytes[i];

                int lower4bits = (oneByte >> 4) | 0x30;
                int upper4bits = (oneByte & 0x0F) | 0x30;
                char c1 = (char)lower4bits;
                char c2 = (char)upper4bits;
                nibbleSb.Append(c1);
                nibbleSb.Append(c2);
            }

            return nibbleSb.ToString();

        }

        public static string ConvertSJISNIBBLEToUnicodeARTSBinary(string nibble)
        {
            char[] nibbleArray = nibble.ToCharArray();

            byte[] sjisBytes = new byte[nibbleArray.Length / 2];
            for (int i = 0; i < nibbleArray.Length; i += 2)
            {
                ushort upper4Bits = (ushort)(((ushort)(nibbleArray[i]) & 0x000F) << 4);
                ushort lower4Bits = (ushort)((ushort)(nibbleArray[i + 1]) & 0x000F);
                byte oneByte = (byte)(upper4Bits | lower4Bits);
                sjisBytes[i / 2] = oneByte;
            }

            string unicodeString = Encoding.GetEncoding(932).GetString(sjisBytes);

            return ConvertUnicodeStringToUnicodeARTSBinary(unicodeString);
        }

        public static string ConvertUnicodeNIBBLEToUnicodeARTSBinary(string nibble)
        {
            char[] nibbleArray = nibble.ToCharArray();

            byte[] unicodeBytes = ConvertNIBBLEToBytes(nibble);

            string unicodeString = Encoding.Unicode.GetString(unicodeBytes);

            return ConvertUnicodeStringToUnicodeARTSBinary(unicodeString);
        }

        
        static bool ValidateARTSBinaryToken(string token)
        {
            foreach (char c in token)
            {
                if (c != '0' && c != '1' && c != '2' && c != '3' && c != '4' && c != '5' && c != '6' && c != '7' && c != '8' && c != '9' &&
                    c != 'a' && c != 'b' && c != 'c' && c != 'd' && c != 'e' && c != 'f')
                {
                    return false;
                }
            }
            return true;
        }

        public static byte[] ConvertNIBBLEToBytes(string nibble)
        {
            char[] nibbleArray = nibble.ToCharArray();

            byte[] bytes = new byte[nibbleArray.Length / 2];
            for (int i = 0; i < nibbleArray.Length; i += 2)
            {
                ushort upper4Bits = (ushort)(((ushort)(nibbleArray[i]) & 0x000F) << 4);
                ushort lower4Bits = (ushort)((ushort)(nibbleArray[i + 1]) & 0x000F);
                byte oneByte = (byte)(upper4Bits | lower4Bits);
                bytes[i / 2] = oneByte;
            }

            return bytes;
        }

        
    }
}
