using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper.Scraper;

namespace skyscraper5.Skyscraper
{
    internal class TcpTsProxy : IDisposable, ITsPacketProcessor
    {
        private bool disposing;
        private Thread listenerThread;
        private TcpListener listener;
        private List<TcpClient> tcpClients;

        //ffmpeg -i tcp://172.20.20.198:6969 -frames:v 1 -c:v png -f image2pipe -map 0:p:28726:v - >28726.png
        public TcpTsProxy()
        {
            tcpClients = new List<TcpClient>();
            listener = new TcpListener(IPAddress.Any, 0);
            listener.Start();
            Debug.WriteLine("Listening at {0}", GetEndPoint());
            listenerThread = new Thread(Listener);
            listenerThread.Start();
        }

        private void Listener()
        {
            while (true)
            {
                try
                {
                    if (disposing)
                        return;
                    if (listener.Server == null)
                        return;
                    if (listener.Server.SafeHandle.IsClosed)
                        return;
                    if (listener.Server.SafeHandle.IsInvalid)
                        return;
                    TcpClient tcpClient = listener.AcceptTcpClient();
                    lock (tcpClients)
                    {
                        tcpClients.Add(tcpClient);
                    }

                    Debug.WriteLine("accepted tcp client {0}", tcpClient);
                }
                catch (SocketException e)
                {
                    if (disposing)
                        return;
                    else
                        throw e;
                }
            }
        }
        
        public void Dispose()
        {
            while (tcpClients.Count > 0)
            {
                TcpClient tcpClient = tcpClients[0];
                tcpClients.RemoveAt(0);
            }
            disposing = true;
            listener.Stop();
            Debug.WriteLine("disposed tcp proxy");
        }

        public IPEndPoint GetEndPoint()
        {
            return listener.LocalEndpoint as IPEndPoint;
        }

        public void PushPacket(TsPacket packet)
        {
            lock (tcpClients)
            {
                foreach (TcpClient tcpClient in tcpClients)
                {
                    if (!tcpClient.Client.Connected)
                    {
                        tcpClients.Remove(tcpClient);
                        PushPacket(packet);
                        Debug.WriteLine("A TCP Client disconnected");
                        return;
                    }

                    try
                    {
                        byte[] packetRawPacket = packet.GetRawPacket();
                        tcpClient.Client.Send(packetRawPacket);
                    }
                    catch (SocketException se)
                    {
                    }
                }
            }
        }
    }
}
