using Aitex.Core.RT.Log;
using Aitex.Core.RT.SCCore;
using Aitex.Core.Util;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace MECF.Framework.Common.Device.BarcodeReader
{
    public class BarcodeReaderSerialDevice
    {
        #region Delegate
        public delegate void BarcodeReaderDataChanged(string name, string lstContent);
        #endregion
        #region 常量
        private const string CONSTANT_COMMAND = "LON\r";
        private const char SPLIT_CHARACTER = '\t';
        #endregion
        #region 内部变量
        /// 
        /// 连接状态
        /// 
        private bool _connected;
        /// 
        /// 串口
        /// 
        private SerialPort _serialPort;
        /// 
        /// 模块名称
        /// 
        private string _name;
        /// 
        /// 接收超时
        /// 
        private int _receiveTimeout = 2000;
        /// 
        /// 错误信息
        /// 
        private string _errmsg = "";
        /// 
        /// 重连
        /// 
        private bool _reconnected;
        /// 
        /// 离线时间
        /// 
        private DateTime _offlineDateTime;
        #endregion
        #region 公共变量
        
        //发布者 定义事件
        public event BarcodeReaderDataChanged OnDataChanged;
        #endregion
        #region 属性
        /// 
        /// 连接状态
        /// 
        public bool Connected
        {
            get { return _connected; }
            set { _connected = value; }
        }
        #endregion
        /// 
        /// 构造函数
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public BarcodeReaderSerialDevice(string name, string portName, int baudRate = 9600, StopBits stopBits = StopBits.One, int dataBits = 8, Parity parity = Parity.None, bool reconnected = false, int receiveTimeout = 2000)
        {
            _serialPort = new SerialPort();
            _serialPort.BaudRate = baudRate;
            _serialPort.StopBits = stopBits;
            _serialPort.DataBits = dataBits;
            _serialPort.Parity = parity;
            _serialPort.PortName = portName;
            _serialPort.ErrorReceived += SerialPort_ErrorReceived;
            _serialPort.WriteTimeout = receiveTimeout;
            _serialPort.ReadTimeout = receiveTimeout;
            _receiveTimeout = receiveTimeout;
            _name = name;
            _reconnected = reconnected;
        }
        /// 
        /// 启动
        /// 
        public void Start()
        {
            Open();
        }
        /// 
        /// 打开串口
        /// 
        private void Open()
        {
            if (!_connected)
            {
                try
                {
                    if (!_serialPort.IsOpen)
                    {
                        _serialPort.Open();
                    }
                    _connected = true;
                    LOG.WriteLog(eEvent.INFO_BARCODEREADER, _name, $"connect port[{_serialPort.PortName}] success");
                }
                catch (Exception ex)
                {
                    WriteErrorMsg(ex.Message);
                }
            }
        }
        /// 
        /// 关闭
        /// 
        public void Close()
        {
            try
            {
                _connected = false;
                _serialPort.Close();
            }
            catch (Exception ex)
            {
                WriteErrorMsg(ex.Message);
            }
        }
        
        #region 事件
        /// 
        /// 串口错误
        /// 
        /// 
        /// 
        private void SerialPort_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
        {
            LOG.WriteLog(eEvent.ERR_BARCODEREADER, _name, e.EventType.ToString());
        }
        #endregion
        /// 
        /// 读取数据
        /// 
        public string ReadData()
        {
            try
            {
                _serialPort.WriteLine(CONSTANT_COMMAND);
                DateTime dt = DateTime.Now;
                string str = "";
                while (DateTime.Now.Subtract(dt).TotalMilliseconds <= _receiveTimeout)
                {
                    if (_serialPort.BytesToRead > 0)
                    {
                        string tmp = _serialPort.ReadExisting();
                        if (!string.IsNullOrEmpty(tmp))
                        {
                            str = tmp;
                            WriteInfoMsg(0, tmp);
                            break;
                        }
                    }
                    else
                    {
                        Thread.Sleep(100);
                    }
                }
                if (!string.IsNullOrEmpty(str))
                {
           
                    if (OnDataChanged != null)
                    {
                        OnDataChanged(_name, str);
                    }
                    return str;
                }
                else
                {
                    LOG.WriteLog(eEvent.WARN_BARCODEREADER, _name, "No barcode Information received");
                    return "";
                }
            }
            catch (Exception ex)
            {
                WriteErrorMsg(ex.Message);
                LOG.WriteLog(eEvent.WARN_BARCODEREADER, _name, "Read barcode failed, Try to Reconnect");
                Open();
                return "";
            }
        }
        /// 
        /// 记录错误信息
        /// 
        /// 
        private void WriteErrorMsg(string msg, bool disConnected = true)
        {
            if (disConnected)
            {
                _connected = false;
                _offlineDateTime = DateTime.Now;
            }
            if (_errmsg != msg)
            {
                _errmsg = msg;
                LOG.WriteLog(eEvent.ERR_BARCODEREADER, _name, msg);
            }
        }
        /// 
        /// 写日志
        /// 
        /// 
        private void WriteInfoMsg(int logType, string str)
        {
            bool enableLog = false;
            if (SC.ContainsItem("Log.EnableBarcodeReaderLog"))
            {
                enableLog = SC.GetValue("Log.EnableBarcodeReaderLog");
            }
            if (enableLog)
            {
                string type = logType == 0 ? "receive" : "send";
                LOG.WriteBackgroundLog(eEvent.ERR_BARCODEREADER, _name, $"{type} {str}");
            }
        }
    }
}