using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace ParticleFramework.Communication
{
    class TcpClient
    {

        #region Required Variables
            public Socket socket;
            public int index;
            private byte[] dataBuffer = new byte[0x400];
            private AsyncCallback ReceiveCallback;
            private AsyncCallback SendCallback;
        #endregion

        #region Mobiles Vars
            public Mobiles.Users.UserObject userObject;
            public string ip;
        #endregion

        public TcpClient(Socket sock, int num)
        {
            index = num;
            socket = sock;

            ip = socket.RemoteEndPoint.ToString().Split(new char[] { ':' })[0];

            //setup data callbacks
            ReceiveCallback = new AsyncCallback(this.ReceivedData);
            SendCallback = new AsyncCallback(this.sentData);

            this.WaitForData();
        }

        public void Disconnect()
        {
            if (socket.Connected)
            {
                socket.Close();
                if(userObject != null) userObject.remove();
                Particle.Server.removeClient(this);
                Log.Info("Client " + this.index + " disconnected and removed");
                Console.WriteLine("Client " + this.index + " disconnected");
            }
        }

        private void ReceivedData(IAsyncResult iAr)
        {
            try
            {
                int count = 0;
                try
                {
                    count = socket.EndReceive(iAr);
                }
                catch
                {
                    Disconnect();
                }

                StringBuilder builder = new StringBuilder();
                builder.Append(System.Text.Encoding.Default.GetString(this.dataBuffer, 0, count));
                string str = System.Text.Encoding.Default.GetString(this.dataBuffer, 0, count);

                if (!(str.ToString() == ""))
                {
                    Log.Info("Got " + str + " from client " + this.index);
                    Console.WriteLine("Got " + str + " from client " + this.index);

                    Particle.packetClass.handle(str, this);
                }
                else
                { 
                    Disconnect();
                }
            }
            catch (Exception exception)
            {
                Log.Info("Data recieve error: " + exception.ToString() + " " + exception.Source);
                Disconnect();
            }
            finally
            {
                this.WaitForData();
            }
        }

        private void WaitForData()
        {
            try
            {
                socket.BeginReceive(this.dataBuffer, 0, this.dataBuffer.Length, SocketFlags.None, this.ReceiveCallback, socket);
            }
            catch
            {
                Disconnect();
            }
        }

        public void sendData(string Data)
        {
            Console.WriteLine("Sent " + Data + " to client " + this.index);
            //Data = Mobiles.Security.Encryption.encrypt(Data);
            Data = "#" + Data + "##";
            rawSend(Data);
        }

        internal void rawSend(string Data)
        {
            try
            {
                byte[] bytes = System.Text.Encoding.Default.GetBytes(Data);
                
                socket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, new AsyncCallback(this.sentData), null);
                Log.Info("Sent " + Data + " to client " + this.index);
            }
            catch
            {
                Disconnect();
            }
        }

        private void sentData(IAsyncResult iAr)
        {
            try
            {
                socket.EndSend(iAr);
            }
            catch
            {
                Disconnect();
            }
        }
    }
}
