using System;
using System.Collections.Generic;
using global::System.IO.Pipes;
using System.Threading.Tasks;

namespace Pilz.IO
{
    public class ManagedPipeServer : ManagedPipe
    {

        // Pro Verbindung (Anfrage) wird ein Client-Objekt generiert, das den Datenaustausch dieser Verbindung abwickelt
        public List<ManagedPipeClient> Clients { get; private set; } = new List<ManagedPipeClient>();

        private readonly string pipeName = "";
        private readonly int maxNumbersOfServerInstances;
        private int numberOfStartedServerInstances = 0;

        public ManagedPipeServer(string pipeName) : this(pipeName, 1)
        {
        }

        public ManagedPipeServer(string pipeName, int maxNumbersOfServerInstances)
        {
            this.pipeName = pipeName;
            this.maxNumbersOfServerInstances = maxNumbersOfServerInstances;
            CreateWaitingStream();
        }

        private void CreateWaitingStream()
        {
            if (numberOfStartedServerInstances < maxNumbersOfServerInstances)
            {
                var strm = new NamedPipeServerStream(pipeName, PipeDirection.InOut, maxNumbersOfServerInstances, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
                numberOfStartedServerInstances += 1;
                strm.BeginWaitForConnection(EndAccept, strm);
            }
        }

        private void EndAccept(IAsyncResult ar)
        {
            NamedPipeServerStream strm = (NamedPipeServerStream)ar.AsyncState;
            strm.EndWaitForConnection(ar);
            if (IsDisposed)
            {
                strm.Dispose();
                return;
            }

            {
                var withBlock = new ManagedPipeClient(strm);
                withBlock.RetriveData += Client_RetriveData;
                withBlock.StatusMessage += Client_StatusMessage;
                withBlock.Disposed += Client_Disposed;
                withBlock.AddTo(Clients);
            }

            CreateWaitingStream();
        }

        /* TODO ERROR: Skipped RegionDirectiveTrivia */
        private void Client_Disposed(ManagedPipe Sender)
        {
            // den Client für die beendete Verbindung entfernen
            Sender.RemoveFrom(Clients);
            numberOfStartedServerInstances -= 1;
            CreateWaitingStream();
        }

        private void Client_RetriveData(object sender, DataEventArgs e)
        {
            // einkommende ChatMessages anzeigen, und an alle versenden
            OnRetriveData(e);
        }

        private void Client_StatusMessage(object sender, DataEventArgs e)
        {
            // einkommende StatusMessages durchreichen (zur Anzeige)
            OnStatusMessage(e);
        }

        /* TODO ERROR: Skipped EndRegionDirectiveTrivia */
        public override Task SendAsnyc(byte[] bytes)
        {
            return Task.Run(() => Send(bytes));
        }

        public override void Send(byte[] data)
        {
            foreach (ManagedPipeClient client in Clients) // an alle versenden
                client.Send(data);
        }

        protected override void Dispose(bool disposing)
        {
            if (numberOfStartedServerInstances < maxNumbersOfServerInstances)
            {
                using (var clnt = new NamedPipeClientStream(pipeName))
                {
                    // Herstellen einer Dummi-Verbindung, damit der ServerStream aus dem Wartezustand herauskommt.
                    clnt.Connect();
                }
            }

            for (int i = Clients.Count - 1; i >= 0; i -= 1)
                Clients[i].Dispose();
        }
    }
}