#if !NETFX_CORE

using System;
using System.IO.Ports;
using System.Threading;
using System.Threading.Tasks;

namespace Plane.Communication
{
    /// <summary>
    /// 提供通过串行端口通信的能力。
    /// </summary>
    public class SerialPortConnection : ExceptionThrownEventSource, IConnection
    {
        private bool _internalIsOpen;

        private SerialPort _port;

        public SerialPortConnection(string portName, int baudRate = 115200)
        {
            _port = new SerialPort(portName, baudRate)
            {
                PortName = portName,
                DataBits = 8,
                StopBits = StopBits.One,
                Parity = Parity.None,
                BaudRate = baudRate,
                DtrEnable = false,
                RtsEnable = false,
                ReadBufferSize = 40 * 1024,
                ReadTimeout = 2000
            };
        }

        public int Available { get { return _port.BytesToRead; } }

        public bool IsOpen { get { return _internalIsOpen && _port.IsOpen; } }

        public string PortName { get { return _port.PortName; } }

        public void Close()
        {
            _internalIsOpen = false;
            try
            {
                _port.Close();
            }
            catch (Exception ex)
            {
                RaiseExceptionThrown(ex);
            }
        }

        public void Open()
        {
            _port.Open();
            _internalIsOpen = true;
        }

        public Task OpenAsync()
        {
            Open();
            return TaskUtils.CompletedTask;
        }

        public int Read(byte[] buffer, int offset, int count)
        {
            while (Available < count)
            {
                if (!IsOpen)
                {
                    return 0;
                }
                Thread.Sleep(5);
            }
            try
            {
                return _port.Read(buffer, offset, count);
            }
            catch (Exception ex)
            {
                Close();
                RaiseExceptionThrown(ex);
                return 0;
            }
        }

        public virtual async Task<int> ReadAsync(byte[] buffer, int offset, int count)
        {
            while (Available < count)
            {
                if (!IsOpen)
                {
                    return 0;
                }
                await TaskUtils.Delay(5).ConfigureAwait(false);
            }
            try
            {
                return _port.Read(buffer, offset, count);
            }
            catch (Exception ex)
            {
                Close();
                RaiseExceptionThrown(ex);
                return 0;
            }
        }

        public void Write(byte[] buffer, int offset, int count)
        {
            try
            {
                _port.Write(buffer, offset, count);
            }
            catch (Exception ex)
            {
                Close();
                RaiseExceptionThrown(ex);
            }
        }

        public Task WriteAsync(byte[] buffer, int offset, int count)
        {
            try
            {
                _port.Write(buffer, offset, count);
            }
            catch (Exception ex)
            {
                Close();
                RaiseExceptionThrown(ex);
            }
            return TaskUtils.CompletedTask;
        }
    }
}

#endif
