using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
using System.Threading;
using MECF.Framework.RT.Core.ThreadLock;
using log4net.Core;
namespace MECF.Framework.RT.Core.IoProviders.Siemens.Serial
{
    /// 
    /// 所有串行通信类的基类,提供了一些基础的服务
    /// 
    public class SerialBase
    {
        #region Constructor
        /// 
        /// 实例化一个无参的构造方法
        /// 
        public SerialBase( )
        {
            SP_ReadData = new SerialPort( );
            hybirdLock = new SimpleHybirdLock( );
        }
        #endregion
        #region Public Method
        /// 
        /// 初始化串口信息,9600波特率,8位数据位,1位停止位,无奇偶校验
        /// 
        /// 端口号信息,例如"COM3"
        public void SerialPortInni( string portName )
        {
            SerialPortInni( portName, 9600 );
        }
        /// 
        /// 初始化串口信息,波特率,8位数据位,1位停止位,无奇偶校验
        /// 
        /// 端口号信息,例如"COM3"
        /// 波特率
        public void SerialPortInni( string portName, int baudRate )
        {
            SerialPortInni( portName, baudRate, 8, StopBits.One, Parity.None );
        }
        /// 
        /// 初始化串口信息,波特率,数据位,停止位,奇偶校验需要全部自己来指定
        /// 
        /// 端口号信息,例如"COM3"
        /// 波特率
        /// 数据位
        /// 停止位
        /// 奇偶校验
        public void SerialPortInni( string portName, int baudRate, int dataBits, StopBits stopBits, Parity parity )
        {
            if (SP_ReadData.IsOpen)
            {
                return;
            }
            SP_ReadData.PortName     = portName;    // 串口
            SP_ReadData.BaudRate     = baudRate;    // 波特率
            SP_ReadData.DataBits     = dataBits;    // 数据位
            SP_ReadData.StopBits     = stopBits;    // 停止位
            SP_ReadData.Parity       = parity;      // 奇偶校验
        }
        /// 
        /// 根据自定义初始化方法进行初始化串口信息
        /// 
        /// 初始化的委托方法
        public void SerialPortInni( Action initi )
        {
            if (SP_ReadData.IsOpen)
            {
                return;
            }
            SP_ReadData.PortName = "COM5";
            SP_ReadData.BaudRate = 9600;
            SP_ReadData.DataBits = 8;
            SP_ReadData.StopBits = StopBits.One;
            SP_ReadData.Parity = Parity.None;
            initi.Invoke( SP_ReadData );
        }
        /// 
        /// 打开一个新的串行端口连接
        /// 
        public void Open( )
        {
            if (!SP_ReadData.IsOpen)
            {
                SP_ReadData.Open( );
                InitializationOnOpen( );
            }
        }
        /// 
        /// 获取一个值,指示串口是否处于打开状态
        /// 
        /// 是或否
        public bool IsOpen( )
        {
            return SP_ReadData.IsOpen;
        }
        /// 
        /// 关闭端口连接
        /// 
        public void Close( )
        {
            if(SP_ReadData.IsOpen)
            {
                ExtraOnClose( );
                SP_ReadData.Close( );
            }
        }
        /// 
        /// 读取串口的数据
        /// 
        /// 发送的原始字节数据
        /// 带接收字节的结果对象
        public OperateResult ReadBase(byte[] send)
        {
            hybirdLock.Enter( );
            if (IsClearCacheBeforeRead) ClearSerialCache( );
            OperateResult sendResult = SPSend( SP_ReadData, send );
            if (!sendResult.IsSuccess)
            {
                hybirdLock.Leave( );
                return OperateResult.CreateFailedResult( sendResult );
            }
            OperateResult receiveResult = SPReceived( SP_ReadData, true );
            hybirdLock.Leave( );
            return receiveResult;
        }
        /// 
        /// 清除串口缓冲区的数据,并返回该数据,如果缓冲区没有数据,返回的字节数组长度为0
        /// 
        /// 是否操作成功的方法
        public OperateResult ClearSerialCache( )
        {
            return SPReceived( SP_ReadData, false );
        }
        #endregion
        #region virtual Method
        /// 
        /// 检查当前接收的字节数据是否正确的
        /// 
        /// 输入字节
        /// 检查是否正确
        protected virtual bool CheckReceiveBytes(byte[] rBytes )
        {
            return true;
        }
        #endregion
        #region Initialization And Extra
        /// 
        /// 在打开端口时的初始化方法,按照协议的需求进行必要的重写
        /// 
        /// 是否初始化成功
        protected virtual OperateResult InitializationOnOpen( )
        {
            return OperateResult.CreateSuccessResult( );
        }
        /// 
        /// 在将要和服务器进行断开的情况下额外的操作,需要根据对应协议进行重写
        /// 
        /// 当断开连接时额外的操作结果
        protected virtual OperateResult ExtraOnClose( )
        {
            return OperateResult.CreateSuccessResult( );
        }
        #endregion
        #region Private Method
        
        /// 
        /// 发送数据到串口里去
        /// 
        /// 串口对象
        /// 字节数据
        /// 是否发送成功
        protected virtual OperateResult SPSend( SerialPort serialPort, byte[] data )
        {
            if (data != null && data.Length > 0)
            {
                try
                {
                    serialPort.Write( data, 0, data.Length );
                    return OperateResult.CreateSuccessResult( );
                }
                catch(Exception ex)
                {
                    return new OperateResult( ex.Message );
                }
            }
            else
            {
                return OperateResult.CreateSuccessResult( );
            }
        }
        /// 
        /// 从串口接收一串数据信息,可以指定是否一定要接收到数据
        /// 
        /// 串口对象
        /// 是否必须要等待数据返回
        /// 结果数据对象
        protected virtual OperateResult SPReceived( SerialPort serialPort, bool awaitData )
        {
            byte[] buffer = new byte[1024];
            System.IO.MemoryStream ms = new System.IO.MemoryStream( );
            DateTime start = DateTime.Now;                                  // 开始时间,用于确认是否超时的信息
            while (true)
            {
                System.Threading.Thread.Sleep( sleepTime );
                try
                {
                    if (serialPort.BytesToRead < 1)
                    {
                        if ((DateTime.Now - start).TotalMilliseconds > ReceiveTimeout)
                        {
                            ms.Dispose( );
                            return new OperateResult( $"Time out: {ReceiveTimeout}" );
                        }
                        else if (ms.Length > 0)
                        {
                            break;
                        }
                        else if (awaitData)
                        {
                            continue;
                        }
                        else
                        {
                            break;
                        }
                    }
                    // 继续接收数据
                    int sp_receive = serialPort.Read( buffer, 0, buffer.Length );
                    ms.Write( buffer, 0, sp_receive );
                }
                catch (Exception ex)
                {
                    ms.Dispose( );
                    return new OperateResult( ex.Message );
                }
            }
            // resetEvent.Set( );
            byte[] result = ms.ToArray( );
            ms.Dispose( );
            return OperateResult.CreateSuccessResult( result );
        }
        
        #endregion
        #region Object Override
        /// 
        /// 返回表示当前对象的字符串
        /// 
        /// 字符串
        public override string ToString()
        {
            return "SerialBase";
        }
        #endregion
        #region Public Properties
        /// 
        /// 接收数据的超时时间,默认5000ms
        /// 
        public int ReceiveTimeout
        {
            get { return receiveTimeout; }
            set { receiveTimeout = value; }
        }
        /// 
        /// 连续串口缓冲数据检测的间隔时间,默认20ms
        /// 
        public int SleepTime
        {
            get { return sleepTime; }
            set { if (value > 0) sleepTime = value; }
        }
        /// 
        /// 是否在发送数据前清空缓冲数据,默认是false
        /// 
        public bool IsClearCacheBeforeRead
        {
            get { return isClearCacheBeforeRead; }
            set { isClearCacheBeforeRead = value; }
        }
        #endregion
        #region Private Member
        
        private SerialPort SP_ReadData = null;                    // 串口交互的核心
        private SimpleHybirdLock hybirdLock;                      // 数据交互的锁
        private int receiveTimeout = 5000;                        // 接收数据的超时时间
        private int sleepTime = 20;                               // 睡眠的时间
        private bool isClearCacheBeforeRead = false;              // 是否在发送前清除缓冲
        #endregion
    }
}