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

namespace CPF
{
    class Conversions
    {
        public  const uint      MAX_SIGNED          = 2147483647;
        private const byte      _PERIOD             = (byte) '.';
        private const byte      _UPPER_CASE_A       = (byte) 'A';
        private const byte      _UPPER_CASE_F       = (byte) 'F';
        private const byte      _LOWER_CASE_A       = (byte) 'a';
        private const byte      _LOWER_CASE_F       = (byte) 'f';
        private const byte      _ZERO               = (byte) '0';
        private const byte      _NINE               = (byte) '9';
        private const byte      _MINUS              = (byte) '-';
        private const byte      _PLUS               = (byte) '+';
        private const byte      _SPACE              = (byte) ' ';

        public static readonly byte[] Digits = Encoding.UTF8.GetBytes("0123456789");

        public static bool IsDigit(byte ch)
        {
            return ((ch >= _ZERO) && (ch <= _NINE));
        }

        public static bool IsSpace(byte ch)
        {
            return (ch == _SPACE);
        }

        public static byte HexCharacterToInteger(byte ch)
        {
           if (ch >= _UPPER_CASE_A && ch <= _UPPER_CASE_F)
                return (byte) (ch - _UPPER_CASE_A + 10);
            else if (ch >= _LOWER_CASE_A && ch <= _LOWER_CASE_F)
                return (byte) (ch - _LOWER_CASE_A + (byte) 10);
            else
                return (byte) (ch - _ZERO);
        }

        public static int IntegerToByteString(ref ByteString 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 long ByteStringToInteger(ByteString s)
        {
            long result = 0;
            byte ch;
            bool sign;

            // Skip leading blanks
            while (IsSpace(s.Deref()))
                s.Advance(1);

            // Check for a sign
            sign = ((s.Deref() == _MINUS));
            if (sign || (s.Deref() == _PLUS))
                s.Advance(1);

            for (ch = s.Deref(); IsDigit(ch); s.Advance(1), ch = s.Deref())
                result = (10 * result) + (uint) (ch - _ZERO);

            if (sign)
	            return -result;
            else
                return result;
        }

        // Parse a (potentially negative) number with up to 2 decimal digits -xxxx.yy
        public static int ParseDecimal(ByteString s)
        {
            bool negative = (s.Deref() == _MINUS);
            if (negative)
                s.Advance(1);
            int result = 100 * (int) ByteStringToInteger(s);
            if ((s[0] == _PERIOD) && IsDigit(s[1]))
            {
                result += 10 * (s[1] - _ZERO);
                if (IsDigit(s[2]))
                    result += (s[2] - _ZERO);
            }
            return negative ? -result : result;
        }
    }
}
