using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace BroadcastModule
{
    public class BroadcastBoard
    {
        private UdpClient DUCP_NetSocket;
        private IPAddress DeviceIP;
        private IPEndPoint RPoint = null;
        private IPEndPoint TPoint = null;
        private int volume = 10;
        //*********************************************** 动态引用dll ******************************************
        //实现协议栈数据输出回调函数
        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        unsafe delegate byte cbDUCP_DataOutType(byte* Data, int Size);
        [DllImport("DUCP.dll", CallingConvention = CallingConvention.Cdecl)]
        extern static void MB_STK_SetOutCallback(cbDUCP_DataOutType cb);
        [DllImport("DUCP.dll", CallingConvention = CallingConvention.Cdecl)]
        unsafe extern static sbyte MB_STK_In(byte* Data, int Size);
        //回调对象
        private cbDUCP_DataOutType cbDuCP_dataout;
        //回调函数实现
        unsafe byte cbDUCP_DataOut(byte* Data, int Size)
        {
            sbyte Ret;
            byte[] buff = new byte[256];
            byte[] RxBuff = new byte[256];
            for (int i = 0; i < Size; i++)
            {
                buff[i] = Data[i];
            }

            /*发送数据到显示屏*/
            DUCP_NetSocket.Send(buff, Size, TPoint);

            /*接收显示屏回复的数据*/
            RxBuff = DUCP_NetSocket.Receive(ref RPoint);

            /*将显示屏的回复的数据传输给协议栈*/
            unsafe
            {
                fixed (byte* pArray = RxBuff)
                    Ret = MB_STK_In(pArray, RxBuff.Length);
            }
            return (byte)Ret;
        }
        //调节音量
        [DllImport("DUCP.dll", CallingConvention = CallingConvention.Cdecl)]
        unsafe extern static byte DUCP_HOST_SYS_SetVol(int vol);
        //播放语音
        [DllImport("DUCP.dll", CallingConvention = CallingConvention.Cdecl)]
        unsafe extern static byte DUCP_HOST_TTS_Play(byte* pText, byte Opt);
        //停止播放语音
        [DllImport("DUCP.dll", CallingConvention = CallingConvention.Cdecl)]
        unsafe extern static byte DUCP_HOST_TTS_Stop();
        //重启系统
        [DllImport("DUCP.dll", CallingConvention = CallingConvention.Cdecl)]
        unsafe extern static byte DUCP_HOST_SYS_Reset();
        //显示已存文件
        [DllImport("DUCP.dll", CallingConvention = CallingConvention.Cdecl)]
        unsafe extern static byte DUCP_HOST_TWIN_DisFile(int WinID, int FileID);
        //显示文本
        [DllImport("DUCP.dll", CallingConvention = CallingConvention.Cdecl)]
        unsafe extern static byte DUCP_HOST_TWIN_DisText(int WinID,
                                                            byte* pText,
                                                            int EnterMode,
                                                            int EnterSpeed,
                                                            int DelayMode,
                                                            int DelayTime,
                                                            int EixtMode,
                                                            int EixtSpeed,
                                                            int FontIndex,
                                                            int TextColor,
                                                            int BkColor,
                                                            int DisTimes);
        //创建文本控件
        [DllImport("DUCP.dll", CallingConvention = CallingConvention.Cdecl)]
        extern static byte DUCP_HOST_TWIN_Create(int WinID, int Stile, int x0, int y0, int xSize, int ySize);
        //删除文本控件中文本文件
        [DllImport("DUCP.dll", CallingConvention = CallingConvention.Cdecl)]
        extern static byte DUCP_HOST_TWIN_DelFile(int WinID, int FileID);
        //删除文本控件
        [DllImport("DUCP.dll", CallingConvention = CallingConvention.Cdecl)]
        extern static byte DUCP_HOST_TWIN_Del(int WinID);
        //删除图片控件
        [DllImport("DUCP.dll", CallingConvention = CallingConvention.Cdecl)]
        extern static byte DUCP_HOST_PIC_Del(int WinID);
        //设置绘图颜色
        [DllImport("DUCP.dll", CallingConvention = CallingConvention.Cdecl)]
        extern static byte DUCP_HOST_2D_SetColor(int Color);
        //填充矩形
        [DllImport("DUCP.dll", CallingConvention = CallingConvention.Cdecl)]
        extern static byte DUCP_HOST_2D_FillRect(int x0, int y0, int x1, int y1);
        //绘制系统自带位图
        [DllImport("DUCP.dll", CallingConvention = CallingConvention.Cdecl)]
        extern static byte DUCP_HOST_2D_DrawSysIcon(int x0, int y0, int Num, int Denom, int IconIndex);
        //创建图片控件
        [DllImport("DUCP.dll", CallingConvention = CallingConvention.Cdecl)]
        extern static byte DUCP_HOST_PIC_Create(int WinID, int x0, int y0, int xSize, int ySize);
        //图片控件追加图片
        [DllImport("DUCP.dll", CallingConvention = CallingConvention.Cdecl)]
        extern static byte DUCP_HOST_PIC_Add(int WinID, int FID, byte EnterMode, byte EnterSpeed,
                                            byte StopMode, byte StopTime, byte ExitMode, byte ExitSpeed);
        //更新本地时间
        [DllImport("DUCP.dll", CallingConvention = CallingConvention.Cdecl)]
        extern static byte DUCP_HOST_SYS_UpdateTime(short Year, byte Month, byte Day, byte Week, byte Hour, byte Minute, byte Second);
        //更新端口(更新ip方法异常，手动更新)
        [DllImport("DUCP.dll", CallingConvention = CallingConvention.Cdecl)]
        unsafe extern static byte DUCP_HOST_SYS_SetPort(int port);
        //下载文本文件并与文本控件关联
        [DllImport("DUCP.dll", CallingConvention = CallingConvention.Cdecl)]
        unsafe extern static byte DUCP_HOST_TWIN_DownTextFile(int WinID,
                                                                int FileID,
                                                                byte* pText,
                                                                int EnterMode,
                                                                int EnterSpeed,
                                                                int DelayMode,
                                                                int DelayTime,
                                                                int EixtMode,
                                                                int EixtSpeed,
                                                                int FontIndex,
                                                                int TextColor,
                                                                int BkColor);

        //************************************************ 方法块 **************************************************
        //构造函数
        public BroadcastBoard(string ip, int port, int volume = 10)
        {
            //初始化网络连接配置
            DeviceIP = IPAddress.Parse(ip);
            RPoint = new IPEndPoint(DeviceIP, port);
            TPoint = new IPEndPoint(DeviceIP, port);

            //设置协议栈的回调函数
            unsafe
            {
                cbDuCP_dataout = new cbDUCP_DataOutType(cbDUCP_DataOut);
                MB_STK_SetOutCallback(cbDuCP_dataout);
            }
            //GC.KeepAlive(cbDuCP_dataout);
            /*#2.创建UDP网络套接字*/
            DUCP_NetSocket = new UdpClient();
            this.volume = volume;
            DUCP_HOST_SYS_SetVol(volume);

            //Refresh();
        }
        public void UpdateTime()
        {
            DateTime dt = DateTime.Now;
            DUCP_HOST_SYS_UpdateTime((short)dt.Year, (byte)dt.Month, (byte)dt.Day, (byte)dt.DayOfWeek, (byte)dt.Hour, (byte)dt.Minute, (byte)dt.Second);
        }
        /// <summary>
        /// 刷新屏幕
        /// </summary>
        public void Refresh()
        {
            DUCP_HOST_TWIN_Del(0);
            DUCP_HOST_TWIN_Del(1);
            DUCP_HOST_TWIN_Del(2);
            DUCP_HOST_TWIN_Del(3);
            DUCP_HOST_TWIN_Create(0, 0, 0, 0, 64, 16);
            DUCP_HOST_TWIN_Create(1, 0, 0, 16, 64, 16);
            DUCP_HOST_TWIN_Create(2, 0, 0, 32, 64, 16);
            DUCP_HOST_TWIN_Create(3, 0, 0, 48, 64, 16);
        }
        /// <summary>
        /// 显示特定行文字
        /// </summary>
        /// <param name="winID"></param>
        /// <param name="str"></param>
        /// <returns></returns>
        public bool DispString(int winID, string str, int time)
        {
            byte[] buffer = Encoding.Default.GetBytes(str);
            if (winID < 0 || winID > 3) { return false; }
            unsafe
            {
                fixed (byte* pArray = buffer)
                {
                    try
                    {
                        if (time >= 0 && time <= 255)
                        {
                            DUCP_HOST_TWIN_DisText(winID, pArray,
                                0X15, 1,
                                0X00, time,
                                0X15, 1,
                                3, 0Xff, 0X00, 0);
                        }
                        else
                        {
                            DUCP_HOST_TWIN_DisText(winID, pArray,
                                0X15, 1,
                                0X02, 255,
                                0X15, 1,
                                3, 0Xff, 0X00, 0);
                        }
                    }
                    catch (Exception ex) { Console.WriteLine(ex.Message); return false; }
                }
            }
            return true;
        }
        /// <summary>
        /// 显示多行文字
        /// </summary>
        /// <param name="strs"></param>
        /// <returns></returns>
        public bool DispString(string[] strs, bool refresh)
        {
            bool normal = true;
            for (int i = 0; i < 4; i++)
            {
                normal = DispString(i, strs[i], 0);
                if (!normal)
                {
                    break;
                }
            }
            return normal;
        }
        /// <summary>
        /// 配置需循环显示的文字，将导致存储器擦写，请勿频繁调用
        /// </summary>
        /// <param name="winID"></param>
        /// <param name="str"></param>
        public void DownloadString(int winID, string str, int index)
        {
            unsafe
            {
                byte[] Buff;
                if (str.Equals("time"))
                {
                    Buff = Encoding.Default.GetBytes("`H:`N:`S");
                    fixed (byte* pArray = Buff)
                        DUCP_HOST_TWIN_DownTextFile(winID,
                                                    index >= 0 ? (index <= 15 ? index : 15) : 0,
                                                    pArray,
                                                    0X15,
                                                    1,
                                                    0X08,
                                                    255,
                                                    0X15,
                                                    1,
                                                    3,
                                                    0XFF,
                                                    0);
                }
                else if (str.Equals("date"))
                {
                    Buff = Encoding.Default.GetBytes("`M月`D日");
                    fixed (byte* pArray = Buff)
                        DUCP_HOST_TWIN_DownTextFile(winID,
                                                    index >= 0 ? (index <= 15 ? index : 15) : 0,
                                                    pArray,
                                                    0X15,
                                                    1,
                                                    0X09,
                                                    255,
                                                    0X15,
                                                    1,
                                                    3,
                                                    0XFF,
                                                    0);
                }
                else
                {
                    Buff = Encoding.Default.GetBytes(str);
                    fixed (byte* pArray = Buff)
                        DUCP_HOST_TWIN_DownTextFile(winID,
                                                    index >= 0 ? (index <= 15 ? index : 15) : 0,
                                                    pArray,
                                                    0X15,
                                                    1,
                                                    0X02,
                                                    255,
                                                    0X15,
                                                    1,
                                                    3,
                                                    0XFF,
                                                    0);
                }

            }
        }
        /// <summary>
        /// 配置需循环显示的文字，将导致存储器擦写，请勿频繁调用。写入多个字符串
        /// </summary>
        /// <param name="winID"></param>
        /// <param name="strs"></param>
        public void DownloadString(int winID, string[] strs)
        {
            for (int i = 0; i < Math.Min(16, strs.Length) && strs[i] != ""; i++)
            {
                DownloadString(winID, strs[i], i);
            }
        }
        /// <summary>
        /// 显示已载入文本文件
        /// </summary>
        /// <param name="winID"></param>
        /// <param name="fieldID"></param>
        public void DispDownStr(int winID, int fieldID)
        {
            DUCP_HOST_TWIN_DisFile(winID, fieldID);
        }
        /// <summary>
        /// 播放语音
        /// </summary>
        /// <param name="str"></param>
        public void AudioPlay(string str)
        {
            unsafe
            {
                try
                {
                    byte[] Buff = System.Text.Encoding.Default.GetBytes(str);
                    fixed (byte* pArray = Buff)
                    {
                        DUCP_HOST_TTS_Stop();
                        DUCP_HOST_TTS_Play(pArray, 0x01);
                    }
                }
                catch (Exception ex)
                { Console.WriteLine(ex.Message); }
            }
        }
        /// <summary>
        /// 音量控制
        /// </summary>
        /// <param name="offset"></param>
        public void VolumeControl(int offset, out int vol)
        {
            volume += offset;
            DUCP_HOST_SYS_SetVol(volume);
            vol = volume;
        }
        public void VolumeControl(int vol)
        {
            DUCP_HOST_SYS_SetVol(volume >= 0 ? (volume <= 50 ? volume : 50) : 0);
        }
        /// <summary>
        /// 重启机器
        /// </summary>
        public void Restart()
        {
            DUCP_HOST_SYS_Reset();
        }
        /// <summary>
        /// 删除已下载文本文件
        /// </summary>
        /// <param name="winID"></param>
        /// <param name="startIndex"></param>
        /// <param name="endIndex"></param>
        public void DelFile(int winID, int startIndex, int endIndex)
        {
            if (winID >= 0 && winID < 4)
            {
                for (int i = (startIndex >= 0 ? startIndex : 0); i < (endIndex >= 15 ? 15 : endIndex); i++)
                {
                    DUCP_HOST_TWIN_DelFile(winID, i);
                }
            }
        }
        /// <summary>
        /// CRC16 
        /// </summary>
        /// <param name="data">要进行计算的数组</param>
        /// <returns>计算后的数组</returns>
        private static byte[] CRC16(byte[] crcbuf)
        {
            int crc = 0xffff;
            int len = crcbuf.Length;
            byte[] redata = new byte[2];
            for (int n = 0; n < len; n++)
            {
                byte i;
                crc = crc ^ crcbuf[n];
                for (i = 0; i < 8; i++)
                {
                    int TT;
                    TT = crc & 1;
                    crc = crc >> 1;
                    crc = crc & 0x7fff;
                    if (TT == 1)
                    {
                        crc = crc ^ 0xa001;
                    }
                    crc = crc & 0xffff;
                }
            }
            redata[1] = (byte)((crc >> 8) & 0xff);
            redata[0] = (byte)((crc & 0xff));
            return redata;
        }
        /// <summary>
        /// 配置ip与端口
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        public void IpConfig(string ip, int port)
        {
            IPAddress ipa = null;
            try
            {
                ipa = IPAddress.Parse(ip);
                if (ipa != null)
                {
                    unsafe
                    {
                        try
                        {
                            byte[] protocol = new byte[] {
                            0x00,0x64,0xff,0xff,0x08,0x04,
                            0x00,0x00,0x00,0x00,
                            0xE6,0x17
                        };
                            byte[] Buff = ipa.GetAddressBytes();
                            Buff.CopyTo(protocol, 6);

                            byte[] temp = new byte[10];
                            Array.Copy(protocol, temp, 10);
                            byte[] crc = CRC16(temp);
                            Array.Copy(crc, 0, protocol, 10, 2);
                            fixed (byte* pArray = protocol)
                            {
                                cbDUCP_DataOut(pArray, 12);
                            }
                        }
                        catch (Exception ex)
                        { Console.WriteLine(ex.Message); }
                    }
                    DUCP_HOST_SYS_SetPort(port);
                }
            }
            catch (Exception ex) { Console.WriteLine(ex.Message); }
        }
    }
}
