using Edge.Core.Parser.BinaryParser.Util;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace VeederRoot_ATG_Console
{
    public static class Util
    {
        /// <summary>
        /// Convert an ASCII string to a long value.
        /// </summary>
        /// <param name="hexAscIIStr">like: "A1" will return 161, "01" will return 1, "1101" will return 4353</param>
        /// <returns>e.g.:161</returns>
        public static double ConvertHexStrToLong(string hexAscIIStr)
        {
            hexAscIIStr = hexAscIIStr.Replace(" ", "").ToUpper();
            int iPos, iLimit;
            long lRetVal = 0;
            char chCurrent;
            iLimit = hexAscIIStr.Length;
            if ((iLimit < 1) || (iLimit > 8))
                return -1;
            for (iPos = iLimit; iPos >= 1; iPos--)
            {
                chCurrent = hexAscIIStr[iPos - 1];
                switch (chCurrent)
                {
                    case '0':
                    case '1':
                    case '2':
                    case '3':
                    case '4':
                    case '5':
                    case '6':
                    case '7':
                    case '8':
                    case '9':
                        lRetVal += (chCurrent - 48) * (long)Math.Pow(16.0, (double)(iLimit - iPos));
                        break;
                    case 'A':
                    case 'a':
                    case 'B':
                    case 'b':
                    case 'C':
                    case 'c':
                    case 'D':
                    case 'd':
                    case 'E':
                    case 'e':
                    case 'F':
                    case 'f':
                        lRetVal += (chCurrent - 65 + 10) * (long)Math.Pow(16.0, (double)(iLimit - iPos));
                        break;
                    default:
                        return -1;
                }
            }

            return lRetVal;
        }

        /// <summary>
        /// Convert bytes of ascii encoded value to its real hex value bytes.
        /// </summary>
        /// <param name="hexAscIIStr">like: 0x31, 0x33 will return byte[0] = 0x13, 
        ///     0x30, 0x33 will return byte[0]=0x03, 
        ///     0x34, 0x33, 0x42, 0x41 will return byte[0]=0x43, byte[1]=0xBA,
        /// </param>
        /// <returns></returns>
        public static byte[] ConvertHexBcdStrToBytes(byte[] hexAscIIBytes)
        {
            if (hexAscIIBytes.Length % 2 != 0)
                throw new ArgumentException("Input hexStr length must be even, but now is: " + hexAscIIBytes.Length);
            var hexStr = Encoding.ASCII.GetString(hexAscIIBytes);
            return hexStr.ToBytes();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="raw">must be length of 4</param>
        /// <returns>with 6 fractional digits</returns>
        public static double ConvertIEEEWith4BytesToDouble(byte[] raw)
        {
            if (raw == null || raw.Length != 4)
                throw new ArgumentException("The target for convert from IEEE to float must be length 4");
            var r = BitConverter.ToSingle(raw.Reverse().ToArray());
            return r;
            //0 is positive, 1 is negative.
            //byte signBit = raw[0].GetBit(0);

            //return 0;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="raw">must be length of 4</param>
        /// <returns>with 6 fractional digits</returns>
        public static double ConvertIEEEWith8BytesToDouble(byte[] raw)
        {
            if (raw == null || raw.Length != 8)
                throw new ArgumentException("The target for convert from IEEE to double must be length 8");
            var r = BitConverter.ToDouble(raw.Reverse().ToArray());
            return r;
            //0 is positive, 1 is negative.
            //byte signBit = raw[0].GetBit(0);

            //return 0;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="raw"></param>
        /// <param name="roundTo">rounding to keep how many decimal points</param>
        /// <returns></returns>
        public static double ConvertIEEEWith4BytesToDouble(byte[] raw, int roundTo)
        {
            if (raw == null || raw.Length != 4)
                throw new ArgumentException("The target for convert from IEEE to float must be length 4");
            var r = Math.Round(BitConverter.ToSingle(raw.Reverse().ToArray()), roundTo);
            return r;
            //0 is positive, 1 is negative.
            //byte signBit = raw[0].GetBit(0);

            //return 0;
        }

        public static byte[] ConvertDoubleToIEEE4Bytes(double value)
        {
            var r = BitConverter.GetBytes((float)value);
            return r.Reverse().ToArray();
        }

        public static byte[] ConvertDoubleToIEEE8Bytes(double value)
        {
            var r = BitConverter.GetBytes(value);
            return r.Reverse().ToArray();
        }
    }
}