using Apewer.Network;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace Apewer.Internals
{

    internal class TcpInstance
    {

        private TcpServer _parent;
        private Socket _server;
        private Socket _client;
        private IPEndPoint _ep;

        private string _ip;
        private int _port;

        private ManualResetEvent _done = new ManualResetEvent(false);
        private int _length = 0;
        private byte[] _data;

        public TcpInstance(TcpServer argParent, Socket argServer, Socket argClient)
        {
            _parent = argParent;
            _server = argServer;
            _client = argClient;
            _ep = (IPEndPoint)_client.RemoteEndPoint;
            _ip = _ep.Address.ToString();
            _port = _ep.Port;
        }

        public void Process()
        {
            try
            {
                var vm = new TcpBuffer();
                vm.Socket = _client;
                vm.Socket.BeginReceive(vm.Buffer, 0, vm.Buffer.Length, SocketFlags.None, Callback, vm);
                _done.WaitOne();
            }
            catch (Exception argex) { _parent.RaiseExcepted(argex); }
        }

        private void Callback(IAsyncResult argAr)
        {
            try
            {
                var vm = (TcpBuffer)argAr.AsyncState;
                if (vm.Socket.Connected)
                {
                    _length = vm.Socket.EndReceive(argAr);
                    if (_length > 0)
                    {
                        _data = new byte[_length];
                        Array.Copy(vm.Buffer, 0, _data, 0, _length);
                        _parent.RaiseReceived(_ip, _port, _data);
                        vm.Socket.BeginReceive(vm.Buffer, 0, vm.Buffer.Length, SocketFlags.None, Callback, vm);
                    }
                    else
                    {
                        if (_client != null)
                        {
                            if (_client.Connected) _client.Close();
                            _client = null;
                        }
                        if (_ep != null)
                        {
                            _parent.Remove(_ip + ":" + _port.ToString());
                            _parent.RaiseClosed(_ip, _port);
                        }
                    }
                }
                else
                {
                    if (!string.IsNullOrEmpty(_ip)) _parent.Close(_ip, _port);
                }
            }
            catch (Exception argex)
            {
                _parent.RaiseExcepted(argex);
                if (_client != null)
                {
                    if (_client.Connected) _client.Close();
                    _client = null;
                }
                _parent.Close(_ip, _port);
            }
            _done.Set();
        }

    }

}