using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Plane.Communication
{
    /// <summary>
    /// 组合多个潜在的连接。
    /// </summary>
    public class CompositeConnection : IConnection
    {
        private List<IConnection> _candidateConnections;

        public CompositeConnection(params IConnection[] candidateConnections)
        {
            _candidateConnections = new List<IConnection>(candidateConnections);
        }

        public event EventHandler<ExceptionThrownEventArgs> ExceptionThrown;

        public bool IsOpen
        {
            get
            {
                return _candidateConnections.Any(c => c.IsOpen);
            }
        }

        public void Close()
        {
            foreach (var connection in _candidateConnections)
            {
                connection.Close();
            }
        }

        public async Task OpenAsync()
        {
            bool anyOk = false;
            var message = new StringBuilder();
            for (int i = _candidateConnections.Count - 1; i >= 0; i--)
            {
                try
                {
                    await _candidateConnections[i].OpenAsync();
                    if (!anyOk) anyOk = true;
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex);
                    message.AppendLine(ex.Message);
                    //_candidateConnections.RemoveAt(i);
                }
            }
            if (!anyOk)
            {
                throw new Exception(message.ToString());
            }
        }

        public async Task<int> ReadAsync(byte[] buffer, int offset, int count)
        {
            int result;
            for (int i = 0; i < _candidateConnections.Count; i++)
            {
                if (_candidateConnections[i].IsOpen)
                {
                    try
                    {
                        result = await _candidateConnections[i].ReadAsync(buffer, offset, count);
                        if (result != 0)
                        {
                            //if (i != 0)
                            //{
                            //    var tmp = _candidateConnections[i];
                            //    _candidateConnections[i] = _candidateConnections[0];
                            //    _candidateConnections[0] = tmp;
                            //}
                            //for (int j = _candidateConnections.Count - 1; j > 0; j--)
                            //{
                            //    _candidateConnections[j].Close();
                            //    _candidateConnections.RemoveAt(j);
                            //}
                            return result;
                        }
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine(ex);
                        ExceptionThrown?.Invoke(this, new ExceptionThrownEventArgs(ex));
                    }
                }
            }
            return 0;
        }

        public async Task WriteAsync(byte[] buffer, int offset, int count)
        {
            for (int i = 0; i < _candidateConnections.Count; i++)
            {
                if (_candidateConnections[i].IsOpen)
                {
                    try
                    {
                        await _candidateConnections[i].WriteAsync(buffer, offset, count);
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine(ex);
                        ExceptionThrown?.Invoke(this, new ExceptionThrownEventArgs(ex));
                    }
                }
            }
        }
    }
}
