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

namespace FilterRest.RestNetworking
{
    internal class RestClient : IDisposable
    {
        private Socket ClientSocket;
        private IPEndPoint ClientEndPoint;

        private Byte[] ClientBuffer;

        private Int32 IsConnected;

        public RestClient(Socket AcceptedSocket, IPEndPoint AcceptedEndPoint)
        {
            ClientSocket = AcceptedSocket;
            ClientEndPoint = AcceptedEndPoint;

            ClientBuffer = new Byte[1024];

            try {
				ClientSocket.BeginReceive(ClientBuffer, 0, ClientBuffer.Length, SocketFlags.None, new AsyncCallback(TokenReceived), null);
			}
            catch {;
				Disconnect(); }
        }

        private void TokenReceived(IAsyncResult Result)
        {
            if (IsConnected != 0) { return; }

            Int32 ReceivedLength = 0;

            try { ReceivedLength = ClientSocket.EndReceive(Result); }
            catch
            {
                Disconnect();
				return;
            }

            if (ReceivedLength >= 1)
            {
				Array.Resize(ref ClientBuffer, ReceivedLength);

                String HTTPRequest = Encoding.ASCII.GetString(ClientBuffer).Split(new String[] { " HTTP/1.1" }, StringSplitOptions.None)[0].Replace("GET /user/v1/", "");

                String Type = HTTPRequest.Split('?')[0];

                HTTPRequest = HTTPRequest.Replace(String.Format("{0}?", Type), "");

                String[] HTTPRequestSplit = HTTPRequest.Split('&');

                Dictionary<String, String> HTTPParameters = new Dictionary<String, String>();

                foreach (String HTTPParameter in HTTPRequestSplit) { HTTPParameters.Add(HTTPParameter.Split('=')[0], HTTPParameter.Split('=')[1]); }

                if (Type == "getInfo")
                {
                    String sRealm = HTTPParameters["realm"];
                    String sToken = HTTPParameters["token"];
                    String sSig = HTTPParameters["sig"];

                    Int32 nEMID;
                    Boolean TokenExists = Program.SQL.GetnEMIDFromsToken(sToken, out nEMID);

                    if (!TokenExists) { SendResponse01(); }
                    else
                    {
                        Byte nUses = Program.SQL.GetnUsesFromsToken(sToken);

						if (nUses == 2)
						{
							SendResponse01();

							Program.SQL.DeleteFromtTokensUsingsToken(sToken);
						}
						else
						{
							nUses++;

							String sUsername = Program.SQL.GetsUsernameFromnEMID(nEMID);

							Program.SQL.SetnUsesForsToken(nUses, sToken);

							SendResponse02(nEMID, sUsername);

							if (nUses >= 2) { Program.SQL.DeleteFromtTokensUsingsToken(sToken); }
						}
					}
                }
                else if (Type == "getPurchasedItems") { SendResponse03(""); }
                else if (Type == "setItemUsed") { SendResponse04(false); }

                Disconnect();
            }
            else { Disconnect(); }
        }

        private void SendResponse01() { SendHTTPResponse("TokExp"); }

        private void SendResponse02(Int64 nEMID, String sUsername) { SendHTTPResponse(String.Concat("{\"token_age\":0,\"user_id\":", nEMID, ",\"login\":\"", sUsername, "\",\"user_role\":\"user\",\"blocked\":false}")); }

        private void SendResponse03(String ItemString) { SendHTTPResponse(String.Concat("{\"items\":[", ItemString, "]}")); }

        private void SendResponse04(Boolean Successful) { SendHTTPResponse(String.Concat("{\"result\":", Successful, "}")); }

        private void SendHTTPResponse(String Data)
        {
			String Response;
            Response = String.Format("HTTP/1.1 200 OK{0}", Environment.NewLine);
            Response = String.Format("{0}Server: Rest Server{1}", Response, Environment.NewLine);
            Response = String.Format("{0}Content-Type: application/json{1}", Response, Environment.NewLine);
            Response = String.Format("{0}Expires: Sat, 16 Mar 1991 08:30:00 GMT{1}", Response, Environment.NewLine);
            Response = String.Format("{0}Cache-Control: no-cache, no-store, must-revalidate{1}", Response, Environment.NewLine);
            Response = String.Format("{0}Pragma: no-cache{1}", Response, Environment.NewLine);
            Response = String.Format("{0}Content-Length: {1}{2}", Response, Data.Length, Environment.NewLine);
            Response = String.Format("{0}{1}{2}", Response, Environment.NewLine, Data);

            Byte[] ResponseBuffer = Encoding.ASCII.GetBytes(Response);

            ClientSocket.Send(ResponseBuffer, ResponseBuffer.Length, SocketFlags.None);
            ClientSocket.Send(ResponseBuffer, ResponseBuffer.Length, SocketFlags.None);
        }

        private void Disconnect()
        {
			if (IsConnected == 0 && Interlocked.CompareExchange(ref IsConnected, 1, 0) == 0)
            {
                try { ClientSocket.Dispose(); }
                catch { }

                ClientEndPoint = null;

                ClientBuffer = new Byte[0];
            }
        }

        ~RestClient() { Dispose(); }

        public void Dispose() { Disconnect(); }
    }
}
