using System;
using System.Text;
using Microsoft.SPOT;

namespace CPF
{
    public static class NumberConversions
    {
        public const byte CarriageReturn = 0x0D;
        public const byte Zero = 0x00;
        public const byte Star = 0x2A;
        public const byte Plus = 0x2B;
        public const byte Minus = 0x2D;
        public const byte ZeroDigit = 0x30;
        public const byte NineDigit = 0x39;
        public const byte Point = 0x2E;
        public static readonly byte[] Digits = Encoding.UTF8.GetBytes("0123456789");

        // Converts two character strings to a byte
        public static byte HexStringToByte(string hex)
        {
            Debug.Assert(hex.Length == 2, "HexStringToByte only accepts two-character strings");
            char high_nibble = hex[0];
            char low_nibble = hex[1];
            return (byte)(HexCharToNibble(high_nibble) << 4 | HexCharToNibble(low_nibble));
        }

        // Converts a hexdecimal character into a byte, e.g.
        private static byte HexCharToNibble(char c)
        {
            if (c >= '0' && c <= '9')
                return (byte)(c - '0');
            else if (c >= 'a' && c <= 'f')
                return (byte)(c - 'a' + 10);
            else if (c >= 'A' && c <= 'F')
                return (byte)(c - 'A' + 10);

            throw new Exception("HexCharToNibble received invalid character: " + c.ToString());
        }

        // Converts a nibble to a hex character, e.g.
        private static char NibbleToHexChar(byte b)
        {
            if (b >= 0 && b <= 9)
                return (char)('0' + b);
            else if (b >= 10 && b <= 15)
                return (char)('A' + b - 10);

            throw new Exception("NibbleToHexChar received invalid nibble: " + b.ToString());
        }

        // Converts a byte to a two-character string
        public static string ByteToHexString(byte b)
        {
            return new String(ByteToCharArray(b));
        }

        // Converts a byte to a char array
        public static char[] ByteToCharArray(byte b)
        {
            char high_nibble = NibbleToHexChar((byte)((b & 0xF0) >> 4));
            char low_nibble = NibbleToHexChar((byte)(b & 0x0F));
            return new char[] { high_nibble, low_nibble };
        }

        // Converts a ushort to a char array
        public static char[] ShortToCharArray(ushort s)
        {
            byte msb = (byte)((s & 0xFF00) >> 8);
            char msb_high_nibble = NibbleToHexChar((byte)((msb & 0xF0) >> 4));
            char msb_low_nibble = NibbleToHexChar((byte)(msb & 0x0F));

            byte lsb = (byte)(s & 0x00FF);
            char lsb_high_nibble = NibbleToHexChar((byte)((lsb & 0xF0) >> 4));
            char lsb_low_nibble = NibbleToHexChar((byte)(lsb & 0x0F));

            return new char[] { msb_high_nibble, msb_low_nibble, lsb_high_nibble, lsb_low_nibble };
        }

        // Converts a string to a byte array
        public static byte[] StringToByteArray(string s)
        {
            // loop over each character in the string and convert each using ByteToCharArray
            System.Collections.ArrayList array = new System.Collections.ArrayList();
            foreach (char c in s)
            {
                char[] nibbles = ByteToCharArray((byte)c);
                array.Add((byte)nibbles[0]);
                array.Add((byte)nibbles[1]);
            }

            // add the null termination
            array.Add((byte)0x00);

            byte[] result = (byte[])array.ToArray(typeof(byte));
            return result;
        }

        public static int IntegerToByteArray(ref byte[] dst, int dstOffset, int value)
        {
            int digits = 0;
            int length;

            if (value < 0)
            {
                dst[dstOffset + digits++] = Minus;
                value = -value;
            }

            int shifted = value;
            do
            { 
                digits++;
                shifted = shifted / 10;
            }
            while (shifted != 0);

            length = digits;
            dst[dstOffset + digits] = Zero;
            // Move back, inserting digits
            do
            { 
                dst[dstOffset + --digits] = Digits[value % 10];
                value = value / 10;
            } 
            while(value != 0);
            return length;
        }

        public static void PrintByteArray(byte[] array)
        {
            string array_string = "=> ";
            int len = array.Length;
            for (int i = 0; i < len; i++)
            {
                array_string += ByteToHexString(array[i]);
                if (i < len - 1)
                    array_string += " ";
            }
            Debug.Print(array_string);
        }

         public static void PrintWordArray(ushort[] array)
        {
            string array_string = "";
            int len = array.Length;
            for (int i = 0; i < len; i++)
            {
                array_string += array[i] + "d";
                if (i < len - 1)
                    array_string += ", ";
            }
            Debug.Print(array_string);
        }
     }
}
