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

namespace FLY.Modbus
{
    /// <summary>
    /// PLC寄存器 与 C# 类型数据 转换， 不含bool
    /// </summary>
    public class RegTypeConverter
    {

        /// <summary>
        /// PLC寄存器 或线圈 转 C# 类型数据
        /// </summary>
        /// <param name="plc_value">PLC 寄存器数据 ushort[] 或 bool </param>
        /// <param name="type">PLC 数据类型</param>
        /// <param name="scale">PLC数据放大倍数</param>
        /// <returns></returns>
        public static object ToObject(object plc_value, REG_TYPE type, double scale)
        {
            if(type == REG_TYPE.BOOL)
            {
                var v = (bool)plc_value;
                if (scale < 0)
                    return !v;
                else
                    return v;
            }

            ushort[] data = (ushort[])plc_value;

            switch (type)
            {
                //case REG_TYPE.BOOL:
                //    {
                //        return data[0] != 0 ? true : false;
                //    }
                case REG_TYPE.INT16:
                    {
                        float v = (Int16)data[0];
                        v = (float)(v * scale);
                        return v;
                    }
                case REG_TYPE.UINT16:
                    {
                        float v = (UInt16)data[0];
                        v = (float)(v * scale);
                        return v;
                    }
                case REG_TYPE.UINT32:
                    {
                        float v = (UInt32)(data[0] | (data[1] << 16));
                        v = (float)(v * scale);
                        return v;
                    }
                case REG_TYPE.INT32:
                    {
                        float v = (Int32)(data[0] | (data[1] << 16));
                        v = (float)(v * scale);
                        return v;
                    }
                case REG_TYPE.FLOAT:
                    {

                        byte[] dat = new byte[] { (byte)data[0], (byte)(data[0] >> 8), (byte)data[1], (byte)(data[1] >> 8) };
                        float v = BitConverter.ToSingle(dat, 0);

                        if ((v > 1000000) || (v < -1000000))
                            v = 0;

                        v = (float)(v * scale);
                        return v;
                    }
                default:
                    {
                        throw new Exception("ToObject type=" + type + "不支持的类型");
                    }
            }
        }

        /// <summary>
        /// C# 类型数据 转 PLC寄存器 或线圈
        /// </summary>
        /// <param name="value">C#中数值 只能是 float or bool</param>
        /// <param name="type">PLC 数据类型</param>
        /// <param name="scale">PLC数据放大倍数</param>
        /// <returns>ushort[] or bool </returns>
        public static object ToRegs(object value, REG_TYPE type, double scale)
        {

            if (type == REG_TYPE.BOOL)
            {
                bool v = (bool)value;
                if (scale < 0)
                    return !v;
                else
                    return v;
            }

            byte[] bs;
            float f = (float)value;
            f = (float)(f / scale);
            switch (type)
            {
                case REG_TYPE.INT16:
                    {
                        short v = (short)f;
                        return new ushort[] { (ushort)v };
                    }
                case REG_TYPE.UINT16:
                    {
                        ushort v = (ushort)f;
                        return new ushort[] { v };
                    }
                case REG_TYPE.FLOAT:
                    {
                        float v = (float)f;
                        bs = BitConverter.GetBytes(v);
                        return new ushort[] {
                            (ushort)((bs[1] << 8) | bs[0]),
                            (ushort)((bs[3] << 8) | bs[2]) };
                    }
                case REG_TYPE.INT32:
                    {
                        Int32 v = (Int32)f;
                        bs = BitConverter.GetBytes(v);
                        return new ushort[] {
                            (ushort)((bs[1] << 8) | bs[0]),
                            (ushort)((bs[3] << 8) | bs[2]) };
                    }
                case REG_TYPE.UINT32:
                    {
                        UInt32 v = (UInt32)f;
                        bs = BitConverter.GetBytes(v);
                        return new ushort[] {
                            (ushort)((bs[1] << 8) | bs[0]),
                            (ushort)((bs[3] << 8) | bs[2]) };
                    }
                default:
                    {
                        throw new Exception("ToObject type=" + type + "不支持的类型");
                    }
            }
            return null;
        }
    }

    /// <summary>
    /// C# 类型枚举
    /// </summary>
    public enum REG_TYPE
    {
        /// <summary>
        /// 出错
        /// </summary>
        Unknown = 0,
        /// <summary>
        /// float
        /// </summary>
        FLOAT = 1,
        /// <summary>
        /// uint16
        /// </summary>
        UINT16 = 2,
        /// <summary>
        /// int16
        /// </summary>
        INT16 = 3,
        /// <summary>
        /// uint32
        /// </summary>
        UINT32 = 4,

        /// <summary>
        /// int32
        /// </summary>
        INT32 = 5,

        /// <summary>
        /// bool
        /// </summary>
        BOOL = 6,
    }
}
