using System;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using Renci.SshNet.Channels;
namespace Renci.SshNet
{
    /// 
    /// Provides functionality for local port forwarding
    /// 
    public partial class ForwardedPortLocal
    {
        private TcpListener _listener;
        partial void ExecuteThread(Action action)
        {
            ThreadPool.QueueUserWorkItem((o) => { action(); });
        }
        partial void InternalStart()
        {
            //  If port already started don't start it again
            if (this.IsStarted)
                return;
            var ep = new IPEndPoint(Dns.GetHostAddresses(this.BoundHost)[0], (int)this.BoundPort);
            this._listener = new TcpListener(ep);
            this._listener.Start();
            this._listenerTaskCompleted = new ManualResetEvent(false);
            this.ExecuteThread(() =>
            {
                try
                {
                    while (true)
                    {
                        var socket = this._listener.AcceptSocket();
                        this.ExecuteThread(() =>
                        {
                            try
                            {
                                IPEndPoint originatorEndPoint = socket.RemoteEndPoint as IPEndPoint;
                                this.RaiseRequestReceived(originatorEndPoint.Address.ToString(), (uint)originatorEndPoint.Port);
                                var channel = this.Session.CreateChannel();
                                channel.Bind(this.Host, this.Port, socket);
                            }
                            catch (Exception exp)
                            {
                                this.RaiseExceptionEvent(exp);
                            }
                        });
                    }
                }
                catch (SocketException exp)
                {
                    if (!(exp.SocketErrorCode == SocketError.Interrupted))
                    {
                        this.RaiseExceptionEvent(exp);
                    }
                }
                catch (Exception exp)
                {
                    this.RaiseExceptionEvent(exp);
                }
                finally
                {
                    this._listenerTaskCompleted.Set();
                }
            });
            this.IsStarted = true;
        }
        partial void InternalStop()
        {
            //  If port not started you cant stop it
            if (!this.IsStarted)
                return;
            this._listener.Stop();
            this._listenerTaskCompleted.WaitOne(this.Session.ConnectionInfo.Timeout);
            this._listenerTaskCompleted.Dispose();
            this._listenerTaskCompleted = null;
            this.IsStarted = false;
        }
    }
}