#if !NETFX_CORE

using System;
using System.IO;
using System.Net.Sockets;
using System.Threading.Tasks;

namespace Plane.Communication
{
    /// <summary>
    /// 提供 TCP 通信的部分实现。
    /// </summary>
    public abstract class TcpConnectionBase : ExceptionThrownEventSource, IConnection
    {
        protected TcpClient _client;

        protected bool _isBroken;

        protected Stream _stream;

        public int Available
        {
            get
            {
                try
                {
                    return _client.Available;
                }
                catch (ObjectDisposedException ex)
                {
                    RaiseExceptionThrown(ex);
                    return 0;
                }
            }
        }

        public bool IsOpen
        {
            get
            {
                try
                {
                    return !_isBroken && _client.Connected;
                }
                catch (ObjectDisposedException)
                {
                    return false;
                }
            }
        }

        public void Close()
        {
            _stream.Close();
            _client.Close();
        }

        public abstract Task OpenAsync();

        public int Read(byte[] buffer, int offset, int count)
        {
            try
            {
                return _stream.Read(buffer, offset, count);
            }
            catch (ArgumentOutOfRangeException ex)
            {
                RaiseExceptionThrown(ex);
                return 0;
            }
            catch (Exception ex)    // 常见的是 IOException。
            {
                _isBroken = true;
                RaiseExceptionThrown(ex);
                return 0;
            }
        }

        public async Task<int> ReadAsync(byte[] buffer, int offset, int count)
        {
            try
            {
                while (Available < count)
                {
                    await Task.Delay(5).ConfigureAwait(false);
                }
                return await _stream.ReadAsync(buffer, offset, count);
            }
            catch (Exception ex)
            {
                _isBroken = true;
                RaiseExceptionThrown(ex);
                return 0;
            }
        }

        public void Write(byte[] buffer, int offset, int count)
        {
            try
            {
                _stream.Write(buffer, offset, count);
            }
            catch (ArgumentOutOfRangeException ex)
            {
                RaiseExceptionThrown(ex);
            }
            catch (Exception ex)
            {
                _isBroken = true;
                RaiseExceptionThrown(ex);
            }
        }

        public async Task WriteAsync(byte[] buffer, int offset, int count)
        {
            try
            {
                await _stream.WriteAsync(buffer, offset, count);
            }
            catch (Exception ex)
            {
                _isBroken = true;
                RaiseExceptionThrown(ex);
            }
        }
    }
}

#endif
