commit 6d0d1410be4686b083ae1b9d48b3fbc81308fb58
Author: Eliška Mourycová <eliska.mourycova@seznam.cz>
Date:   Thu May 20 09:33:40 2021 +0200

    Re #8941. Started working on enqueueing requests and processing them in a new thread. + Program.cs cleanup + Fixed Date error.

diff --git a/Server/ServerApp/Connection/ConnectionListener.cs b/Server/ServerApp/Connection/ConnectionListener.cs
deleted file mode 100644
index a0a1b80..0000000
--- a/Server/ServerApp/Connection/ConnectionListener.cs
+++ /dev/null
@@ -1,461 +0,0 @@
-﻿//
-// Author: Eliska Mourycova
-//
-
-using ServerApp.Connection.XMLProtocolHandler;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Net;
-using System.Net.Sockets;
-using System.Text;
-using System.Threading;
-using System.Web;
-
-namespace ServerApp.Connection
-{
-    //  /// <summary>
-    //  /// State object for reading client data asynchronously
-    //  /// </summary>
-    //  public class StateObject
-    //  {
-    //      // Client  socket.
-    //      public Socket WorkSocket = null;
-    //      // Size of receive buffer.
-    //      public const int BUFFER_SIZE = 1024;
-    //      // Receive buffer.
-    //      public byte[] Buffer = new byte[BUFFER_SIZE];
-    //      // Received data string.
-    //      public StringBuilder StrBuilder = new StringBuilder();
-    //  }
-
-    //  /// <summary>
-    //  /// This class takes care of client connection. It serves clients asynchronously.
-    //  /// </summary>
-    //  public class AsynchronousSocketListener
-    //  {
-    //      // port numbers:
-    //      private const int PORT_NO = 11000;
-    //      private const int ADMIN_PORT_NO = 10000;
-
-
-    //      // Thread signal
-    //      private ManualResetEvent allDone = new ManualResetEvent(false);
-
-    //      /// <summary>
-    //      /// Starts listening and accepting connections. It serves requests when they come.
-    //      /// </summary>
-    //      public void StartListening()
-    //      {
-    //          // Data buffer for incoming data.
-    //          byte[] bytes = new Byte[1024];
-
-    //          // Establish the local endpoint for the socket:
-    //          IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
-
-    //          // Get the IP of the machine - UNUSED ATM, USING LOOPBACK ON LOCALHOST
-    //          IPAddress ipAddress = ipHostInfo.AddressList[1];
-    //          Console.WriteLine("machine ip: " + ipAddress.ToString());
-    //          IPEndPoint localEndPoint = new IPEndPoint(/*ipAddress*/IPAddress.Loopback, PORT_NO);
-    //          IPEndPoint localEndPointAdmin = new IPEndPoint(/*ipAddress*/IPAddress.Loopback, ADMIN_PORT_NO);
-
-    //          // Create a TCP/IP socket.
-    //          Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
-    //          Socket listenerAdmin = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
-
-    //          // Bind the socket to the local endpoint and listen for incoming connections.
-    //          try
-    //          {
-    //              listener.Bind(localEndPoint);
-    //              listener.Listen(100);
-
-    //              listenerAdmin.Bind(localEndPointAdmin);
-    //              listenerAdmin.Listen(1);
-
-    //              // keep accepting
-    //              while (true)
-    //              {
-    //                  // Set the event to nonsignaled state.
-    //                  allDone.Reset();
-
-    //                  // Start an asynchronous socket to listen for connections.
-    //                  Console.WriteLine("Waiting for a connection...");
-    //                  listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
-    //                  listenerAdmin.BeginAccept(new AsyncCallback(AcceptCallback), listenerAdmin);
-
-    //                  // Wait until a connection is made before continuing.
-    //                  allDone.WaitOne();
-    //              }
-
-    //          }
-    //          catch (Exception e)
-    //          {
-    //              // bind failed
-    //              Console.WriteLine(e.ToString());
-    //          }
-
-    //          Console.WriteLine("\nPress ENTER to continue...");
-    //          Console.Read();
-
-    //      }
-
-    //      // Routine for when BeginAccept on the given listener ended
-    //      private void AcceptCallback(IAsyncResult ar)
-    //      {
-    //          // Signal the main thread to continue.
-    //          allDone.Set();
-    //          Console.WriteLine("Accepted a connection.");
-
-
-    //          // Get the socket that handles the client request.
-    //          Socket listener = (Socket)ar.AsyncState;
-    //          Socket handler = listener.EndAccept(ar);
-
-    //          // debug
-    //          Console.WriteLine("handler: ");
-    //          Console.WriteLine("I am connected to " + IPAddress.Parse(((IPEndPoint)handler.RemoteEndPoint).Address.ToString()) + " on port number " + ((IPEndPoint)handler.RemoteEndPoint).Port.ToString());
-    //          Console.WriteLine("My local IpAddress is : " + IPAddress.Parse(((IPEndPoint)handler.LocalEndPoint).Address.ToString()) + ". I am connected on port number " + ((IPEndPoint)handler.LocalEndPoint).Port.ToString());
-
-
-
-
-    //          // Create the state object.
-    //          StateObject state = new StateObject();
-    //          state.WorkSocket = handler;
-    //          handler.BeginReceive(state.Buffer, 0, StateObject.BUFFER_SIZE, 0, new AsyncCallback(ReadCallback), state);
-
-    //      }
-
-    //      // Routine for when BeginReceive on the given listener ended
-    //      private void ReadCallback(IAsyncResult ar)
-    //      {
-    //          // string for the received message
-    //          String content = String.Empty;
-
-    //          // Retrieve the state object and the handler socket
-    //          // from the asynchronous state object.
-    //          StateObject state = (StateObject)ar.AsyncState;
-    //          Socket handler = state.WorkSocket;
-
-    //          // check if we're still connected
-    //          if (!SocketConnected(handler))
-    //	{
-    //              // if the client isn't connected anymore, take care of cleanup
-    //              Console.WriteLine("Closing connection - unexpected...");
-    //              CloseConnection(handler);
-
-    //              // return so that we don't attempt to read from a non-existent stream
-    //              return;
-    //          }
-
-    //          // check if it is admin's request we're serving
-    //          bool admin = ((IPEndPoint)handler.LocalEndPoint).Port == ADMIN_PORT_NO;
-
-    //          // Read data from the client socket. 
-    //          int bytesRead = handler.EndReceive(ar);
-
-    //          if (bytesRead > 0)
-    //          {
-    //              // There  might be more data, so store the data received so far.
-    //              state.StrBuilder.Append(Encoding.ASCII.GetString(state.Buffer, 0, bytesRead));
-
-    //              // Check for end-of-file tag. If it is not there, read more data.
-    //              content = state.StrBuilder.ToString();
-    //              if (content.IndexOf("!") > -1)
-    //              {
-    //                  // All the data has been read from the client. Display it on the console.
-    //                  Console.WriteLine("Read {0} bytes from socket. \n Data : {1}", content.Length, content);
-
-    //                  // parse the message and determine the response:
-    //                  content = ParseMessageAndBuildAnswer(content, admin);
-
-    //                  // check if the client wishes to close the connection:
-    //                  if (content.Equals("bye!"))
-    //                  {
-    //                      Console.WriteLine("Closing connection - expected...");
-    //                      //handler.Shutdown(SocketShutdown.Both);
-    //                      //handler.Close();
-    //                      CloseConnection(handler);
-    //                      return;
-    //                  }
-
-    //                  // Send a response to the client
-    //                  Send(handler, content);
-
-    //                  // clear the string
-    //                  state.StrBuilder.Clear();
-
-    //                  // begin receiving another message:
-    //                  handler.BeginReceive(state.Buffer, 0, StateObject.BUFFER_SIZE, 0, new AsyncCallback(ReadCallback), state);
-    //              }
-    //              else
-    //              {
-    //                  // Not all data received. Get more.
-    //                  handler.BeginReceive(state.Buffer, 0, StateObject.BUFFER_SIZE, 0, new AsyncCallback(ReadCallback), state);
-    //              }
-    //          }
-    //      }
-
-    //      // Takes care of sending data to a connected client
-    //      private void Send(Socket handler, String data)
-    //      {
-    //          // Convert the string data to byte data using ASCII encoding.
-    //          byte[] byteData = Encoding.ASCII.GetBytes(data);
-
-    //          // Begin sending the data to the remote device.
-    //          handler.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), handler);
-    //      }
-
-    //      // Routine for when BeginSend on the given listener ended
-    //      private void SendCallback(IAsyncResult ar)
-    //      {
-    //          try
-    //          {
-    //              // Retrieve the socket from the state object.
-    //              Socket handler = (Socket)ar.AsyncState;
-
-    //              // Complete sending the data to the remote device.
-    //              int bytesSent = handler.EndSend(ar);
-    //              Console.WriteLine("Sent {0} bytes to client.", bytesSent);
-
-
-    //              //handler.Shutdown(SocketShutdown.Both);
-    //              //handler.Close();
-
-    //          }
-    //          catch (Exception e)
-    //          {
-    //              // close connection here?
-
-    //              Console.WriteLine(e.ToString());
-    //          }
-    //      }
-
-
-    //      /// <summary>
-    //      /// Parses the incoming request and determines the response.
-    //      /// </summary>
-    //      /// <param name="message">The incoming message from the client</param>
-    //      /// <param name="admin">A flag saying whether it is admin's request</param>
-    //      /// <returns></returns>
-    //      private string ParseMessageAndBuildAnswer(string message, bool admin)
-    //{
-    //          Console.WriteLine("Parsing message from admin: " + admin);
-    //          string ans = "";
-
-    //	if (message.Equals("hello!"))
-    //	{
-    //              ans = "hello to you too.";
-    //	}
-    //          else if (message.Equals("weather!"))
-    //	{
-    //              ans = "weather will be nice";
-    //          }
-    //          else if (message.Equals("bye!"))
-    //	{
-    //              ans = "bye!";
-    //	}
-    //          else
-    //	{
-    //              // here bye too, if we want to disconnect clients who don't follow protocol
-    //              ans = "bye!";//"i didnt understand that";
-
-    //          }
-
-    //          return ans;
-    //}
-
-    //      /// <summary>
-    //      /// Closes the connection on the passed Socket
-    //      /// </summary>
-    //      /// <param name="s">The socket to close the connection for</param>
-    //      private void CloseConnection(Socket s)
-    //{
-    //          s.Shutdown(SocketShutdown.Both);
-    //          s.Close();
-    //      }
-
-    //      /// <summary>
-    //      /// Checks whether the connection on a given socket is active
-    //      /// </summary>
-    //      /// <param name="s">The socket to check for connection activity</param>
-    //      /// <returns>True if the connection is active, false otherwise</returns>
-    //      private bool SocketConnected(Socket s)
-    //      {
-    //          bool part1 = s.Poll(1000, SelectMode.SelectRead);
-    //          bool part2 = (s.Available == 0);
-    //          if (part1 && part2)
-    //              return false;
-    //          else
-    //              return true;
-    //      }
-    //  }
-
-
-    class ClientService
-	{
-        int id;
-        Request request;
-        Response response;
-    }
-
-    public class ConnectionListener
-    {
-        private readonly int PORT;
-        private Dictionary<int, ClientService> allRequests;
-        private Queue<Request> waitingRequests;
-
-
-        public ConnectionListener(int port)
-        {
-            this.PORT = port;
-        }
-
-        public void StartListening()
-        {
-            string ip = GetLocalIPAddress();
-            Console.WriteLine("ip : " + ip);
-            HttpListener server = new HttpListener();
-            //server.Prefixes.Add($"http://*:1234/work/");
-            server.Prefixes.Add($"https://{ip}:{PORT}/");
-            //server.Prefixes.Add($"http://localhost:{PORT}/work/");
-            //server.Prefixes.Add($"http://127.0.0.1:{PORT}/work/");
-            //server.Prefixes.Add($"http://{ip}:{PORT}/work/");
-            //server.Prefixes.Add($"http://+:{PORT}/work/");
-
-            server.Start();
-
-            Console.WriteLine("Listening...");
-
-            while (true)
-            {
-                Console.WriteLine("waiting for request?");
-                //Console.ReadLine();
-
-                HttpListenerContext context = server.GetContext();
-                
-
-
-                if (context.Request.HttpMethod == "GET") // when client says download
-                {
-                    Console.WriteLine("received GET request");
-
-                    HttpListenerResponse response = context.Response;
-                    response.AddHeader("Access-Control-Allow-Credentials", "true");
-                    response.AddHeader("Access-Control-Expose-Headers", "ETag");
-                    response.AddHeader("Access-Control-Allow-Headers", "Accept, X-Access-Token, X-Application-Name, X-Request-Sent-Time");
-                    response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
-                    //response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
-                    //response.AddHeader("Access-Control-Allow-Origin", "https://kacerekz.github.io/KIV-ASWI/");
-                    response.AddHeader("Access-Control-Allow-Origin", "*");
-
-
-
-                    //string page = Directory.GetCurrentDirectory() + context.Request.Url.LocalPath;
-                    // if (page == string.Empty)
-                    //     page = "test.txt";
-                    // 
-                    // TextReader tr = new StreamReader(page);
-                    // string msg = tr.ReadToEnd();
-
-                    int rand = new Random().Next(1, 10);
-                    string msg = "This is a response from the server :) " + rand;
-
-                    Response xmlResp = Response.Randomize();
-                    var xml = XmlCommunication.Serialize(xmlResp);
-                    //Console.WriteLine(xml);
-
-                    msg = xml;
-
-                    byte[] buffer = Encoding.UTF8.GetBytes(msg);
-
-                    response.ContentLength64 = buffer.Length;
-                    Stream st = response.OutputStream;
-                    st.Write(buffer, 0, buffer.Length);
-
-
-                    context.Response.Close();
-                }
-
-                else if (context.Request.HttpMethod == "POST") // when client says upload
-                {
-                    Console.WriteLine("received POST request");
-
-                    string text;
-                    using (var reader = new StreamReader(context.Request.InputStream, context.Request.ContentEncoding))
-                        text = reader.ReadToEnd();
-                    Console.WriteLine("Received request:");
-                    Console.WriteLine(HttpUtility.UrlDecode(text));
-
-
-
-                    HttpListenerResponse response = context.Response;
-                    response.AddHeader("Access-Control-Allow-Credentials", "true");
-                    response.AddHeader("Access-Control-Expose-Headers", "ETag");
-                    response.AddHeader("Access-Control-Allow-Headers", "Accept, X-Access-Token, X-Application-Name, X-Request-Sent-Time");
-                    response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
-                    response.AddHeader("Access-Control-Allow-Origin", "*");
-
-
-
-                    int rand = new Random().Next(1, 10);
-                    string msg = "OK " + rand;
-
-                    byte[] buffer = Encoding.UTF8.GetBytes(msg);
-
-                    response.ContentLength64 = buffer.Length;
-                    Stream st = response.OutputStream;
-                    st.Write(buffer, 0, buffer.Length);
-
-
-                    context.Response.Close(); // ?? Works better with this, if this line is absent, the client gets 'stuck' after approximately 6 messages
-                }
-                else
-                {
-                    Console.WriteLine("received request other than GET or POST");
-                    Console.WriteLine("method: " + context.Request.HttpMethod);
-                    Console.WriteLine("headers: " + context.Request.Headers);
-                    Console.WriteLine("whole request?: " + context.Request);
-                    Console.WriteLine("user: " + context.User);
-
-
-
-                    //HttpListenerResponse response = context.Response;
-                    //response.AddHeader("Access-Control-Allow-Credentials", "true");
-                    //response.AddHeader("Access-Control-Expose-Headers", "ETag");
-                    //response.AddHeader("Access-Control-Allow-Headers", "Accept, X-Access-Token, X-Application-Name, X-Request-Sent-Time, Origin, Content-Type, X-Auth-Token");
-                    //response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
-                    //response.AddHeader("Access-Control-Allow-Origin", "*");
-
-                    //string msg = "Preflight check? ";
-
-                    //byte[] buffer = Encoding.UTF8.GetBytes(msg);
-
-                    //response.ContentLength64 = buffer.Length;
-                    //Stream st = response.OutputStream;
-                    //st.Write(buffer, 0, buffer.Length);
-
-
-                    //context.Response.Close(); // ??
-
-                }
-            }
-        }
-
-
-        private string GetLocalIPAddress()
-        {
-            var host = Dns.GetHostEntry(Dns.GetHostName());
-            foreach (var ip in host.AddressList)
-            {
-                if (ip.AddressFamily == AddressFamily.InterNetwork)
-                {
-                    return ip.ToString();
-                }
-            }
-            throw new Exception("No network adapters with an IPv4 address in the system!");
-        }
-
-    }
-
-}
diff --git a/Server/ServerApp/Connection/ConnectionListenerMulti.cs b/Server/ServerApp/Connection/ConnectionListenerMulti.cs
new file mode 100644
index 0000000..d6795a0
--- /dev/null
+++ b/Server/ServerApp/Connection/ConnectionListenerMulti.cs
@@ -0,0 +1,707 @@
+﻿//
+// Author: Eliska Mourycova
+//
+
+using ServerApp.Connection.XMLProtocolHandler;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading;
+using System.Web;
+
+namespace ServerApp.Connection
+{
+
+	//public class HttpListenerCallbackState
+	//{
+	//    private readonly HttpListener _listener;
+	//    private readonly AutoResetEvent _listenForNextRequest;
+
+	//    public HttpListenerCallbackState(HttpListener listener)
+	//    {
+	//        if (listener == null) throw new ArgumentNullException("listener");
+	//        _listener = listener;
+	//        _listenForNextRequest = new AutoResetEvent(false);
+	//    }
+
+	//    public HttpListener Listener { get { return _listener; } }
+	//    public AutoResetEvent ListenForNextRequest { get { return _listenForNextRequest; } }
+	//}
+
+	//public class HttpRequestHandler
+	//{
+	//    private int requestCounter = 0;
+	//    private ManualResetEvent stopEvent = new ManualResetEvent(false);
+	//    private int PORT;
+
+	//    public HttpRequestHandler(int port)
+	//    {
+	//        this.PORT = port;
+	//    }
+
+	//    public void ListenAsynchronously(/*IEnumerable<string> prefixes*/)
+	//    {
+	//        HttpListener listener = new HttpListener();
+
+	//        //foreach (string s in prefixes)
+	//        //{
+	//        //    listener.Prefixes.Add(s);
+	//        //}
+
+	//        listener.Prefixes.Add($"http://localhost:{PORT}/");
+
+	//        listener.Start();
+	//        Console.WriteLine("Listening...");
+	//        HttpListenerCallbackState state = new HttpListenerCallbackState(listener);
+	//        ThreadPool.QueueUserWorkItem(Listen, state);
+	//    }
+
+	//    public void StopListening()
+	//    {
+	//        stopEvent.Set();
+	//    }
+
+
+	//    private void Listen(object state)
+	//    {
+	//        HttpListenerCallbackState callbackState = (HttpListenerCallbackState)state;
+
+	//        while (callbackState.Listener.IsListening)
+	//        {
+	//            callbackState.Listener.BeginGetContext(new AsyncCallback(ListenerCallback), callbackState);
+	//            int n = WaitHandle.WaitAny(new WaitHandle[] { callbackState.ListenForNextRequest, stopEvent });
+
+	//            if (n == 1)
+	//            {
+	//                // stopEvent was signalled 
+	//                callbackState.Listener.Stop();
+	//                break;
+	//            }
+	//        }
+	//    }
+
+	//    private void ListenerCallback(IAsyncResult ar)
+	//    {
+	//        HttpListenerCallbackState callbackState = (HttpListenerCallbackState)ar.AsyncState;
+	//        HttpListenerContext context = null;
+
+	//        int requestNumber = Interlocked.Increment(ref requestCounter);
+
+	//        try
+	//        {
+	//            context = callbackState.Listener.EndGetContext(ar);
+	//        }
+	//        catch (Exception ex)
+	//        {
+	//            return;
+	//        }
+	//        finally
+	//        {
+	//            callbackState.ListenForNextRequest.Set();
+	//        }
+
+	//        if (context == null) return;
+
+
+	//        HttpListenerRequest request = context.Request;
+
+	//        if (request.HasEntityBody)
+	//        {
+	//            using (System.IO.StreamReader sr = new System.IO.StreamReader(request.InputStream, request.ContentEncoding))
+	//            {
+	//                string requestData = sr.ReadToEnd();
+
+	//                //Stuff I do with the request happens here  
+	//            }
+	//        }
+
+
+	//        try
+	//        {
+	//            using (HttpListenerResponse response = context.Response)
+	//            {
+	//                Console.WriteLine("dealing with response");
+	//                //Thread.Sleep(10000);
+	//                //response stuff happens here  
+	//                string responseString = "Ok";
+
+	//                byte[] buffer = Encoding.UTF8.GetBytes(responseString);
+	//                response.ContentLength64 = buffer.LongLength;
+	//                response.OutputStream.Write(buffer, 0, buffer.Length);
+	//                response.Close();
+	//            }
+	//        }
+	//        catch (Exception e)
+	//        {
+	//        }
+	//    }
+	//}
+
+
+
+
+
+
+
+
+
+
+	public class ConnectionListener
+	{
+		private readonly int PORT;
+
+		public ConnectionListener(int port)
+		{
+			this.PORT = port;
+		}
+
+		public void StartListening()
+		{
+			string ip = GetLocalIPAddress();
+			Console.WriteLine("ip : " + ip);
+			HttpListener server = new HttpListener();
+			//server.Prefixes.Add($"https://{ip}:{PORT}/");
+			server.Prefixes.Add($"http://localhost:{PORT}/");
+
+			server.Start();
+
+			Console.WriteLine("Listening...");
+
+			while (true)
+			{
+				Console.WriteLine("Waiting for a client request...");
+
+				HttpListenerContext context = server.GetContext();
+
+
+
+				if (context.Request.HttpMethod == "GET") // when client says download
+				{
+					Console.WriteLine("received GET request");
+
+					HttpListenerResponse response = context.Response;
+					response.AddHeader("Access-Control-Allow-Credentials", "true");
+					response.AddHeader("Access-Control-Expose-Headers", "ETag");
+					response.AddHeader("Access-Control-Allow-Headers", "Accept, X-Access-Token, X-Application-Name, X-Request-Sent-Time");
+					response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
+					response.AddHeader("Access-Control-Allow-Origin", "*");
+
+
+
+					//string page = Directory.GetCurrentDirectory() + context.Request.Url.LocalPath;
+					// if (page == string.Empty)
+					//     page = "test.txt";
+					// 
+					// TextReader tr = new StreamReader(page);
+					// string msg = tr.ReadToEnd();
+
+					int rand = new Random().Next(1, 10);
+					string msg = "This is a response from the server :) " + rand;
+
+					Response xmlResp = Response.Randomize();
+					var xml = XmlCommunication.Serialize(xmlResp);
+					//Console.WriteLine(xml);
+
+					msg = xml;
+
+					byte[] buffer = Encoding.UTF8.GetBytes(msg);
+
+					response.ContentLength64 = buffer.Length;
+					Stream st = response.OutputStream;
+					st.Write(buffer, 0, buffer.Length);
+
+
+					context.Response.Close();
+				}
+
+				else if (context.Request.HttpMethod == "POST") // when client says upload
+				{
+					Console.WriteLine("received POST request");
+
+					string text;
+					using (var reader = new StreamReader(context.Request.InputStream, context.Request.ContentEncoding))
+						text = reader.ReadToEnd();
+					Console.WriteLine("Received request:");
+					string requestXML = HttpUtility.UrlDecode(text);
+					Console.WriteLine(requestXML);
+
+					Request newRequest = new Request();
+					Request requestDeserialized = XmlCommunication.Deserialize(newRequest, requestXML);
+
+					HttpListenerResponse response = context.Response;
+					response.AddHeader("Access-Control-Allow-Credentials", "true");
+					response.AddHeader("Access-Control-Expose-Headers", "ETag");
+					response.AddHeader("Access-Control-Allow-Headers", "Accept, X-Access-Token, X-Application-Name, X-Request-Sent-Time");
+					response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
+					response.AddHeader("Access-Control-Allow-Origin", "*");
+
+
+
+					int rand = new Random().Next(1, 10);
+					string msg = "OK " + rand;
+
+					byte[] buffer = Encoding.UTF8.GetBytes(msg);
+
+					response.ContentLength64 = buffer.Length;
+					Stream st = response.OutputStream;
+					st.Write(buffer, 0, buffer.Length);
+
+
+					context.Response.Close(); // ?? Works better with this, if this line is absent, the client gets 'stuck' after approximately 6 messages
+				}
+				else
+				{
+					Console.WriteLine("received request other than GET or POST");
+					Console.WriteLine("method: " + context.Request.HttpMethod);
+					Console.WriteLine("headers: " + context.Request.Headers);
+					Console.WriteLine("whole request?: " + context.Request);
+					Console.WriteLine("user: " + context.User);
+
+
+
+					//HttpListenerResponse response = context.Response;
+					//response.AddHeader("Access-Control-Allow-Credentials", "true");
+					//response.AddHeader("Access-Control-Expose-Headers", "ETag");
+					//response.AddHeader("Access-Control-Allow-Headers", "Accept, X-Access-Token, X-Application-Name, X-Request-Sent-Time, Origin, Content-Type, X-Auth-Token");
+					//response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
+					//response.AddHeader("Access-Control-Allow-Origin", "*");
+
+					//string msg = "Preflight check? ";
+
+					//byte[] buffer = Encoding.UTF8.GetBytes(msg);
+
+					//response.ContentLength64 = buffer.Length;
+					//Stream st = response.OutputStream;
+					//st.Write(buffer, 0, buffer.Length);
+
+
+					//context.Response.Close(); // ??
+
+				}
+			}
+		}
+
+		private string GetLocalIPAddress()
+		{
+			var host = Dns.GetHostEntry(Dns.GetHostName());
+			foreach (var ip in host.AddressList)
+			{
+				if (ip.AddressFamily == AddressFamily.InterNetwork)
+				{
+					return ip.ToString();
+				}
+			}
+			throw new Exception("No network adapters with an IPv4 address in the system!");
+		}
+
+	}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+	// ---------------------------------------------------------------------------
+
+
+
+
+
+
+
+
+	class ClientService
+	{
+		public static readonly int MAX_IDS = 1000000; // ??
+		public static int IDs = 0;
+		public int UniqueID;
+		public Request ClientRequest;
+		public Response ClientResponse;
+    }
+
+    public class ConnectionListenerMulti
+    {
+        private readonly int PORT;
+        private ConcurrentDictionary<int, ClientService> readyRequests;
+        private ConcurrentQueue<ClientService> waitingRequests;
+
+
+        public ConnectionListenerMulti(int port)
+        {
+            this.PORT = port;
+        }
+
+
+		private void RequestHandler()
+		{
+			while (true)
+			{
+				if (!waitingRequests.IsEmpty)
+				{
+					Console.WriteLine("handling a request for 10s...");
+					ClientService nextService;
+					bool deqResultOk = waitingRequests.TryDequeue(out nextService);
+					// nextService has ID and request filled out
+					Thread.Sleep(10000);
+
+					Console.WriteLine("finished building response, adding it to the dictionary...");
+					//ClientService service = new ClientService();
+					//service.UniqueID = GetNextID();
+					//service.ClientRequest = Request.Randomize();
+					nextService.ClientResponse = Response.Randomize();
+					bool resultOk = readyRequests.TryAdd(nextService.UniqueID, nextService);
+					if (!resultOk)
+					{
+						Console.WriteLine("ID " + nextService.UniqueID + " is being used!");
+						// do nothing? - keep it in the queue and let the client try later perhaps?
+					}
+					else
+					{
+						// added to dictionary
+						// -> remove it from the queue
+						
+					}
+				}
+				else
+				{
+					Thread.Sleep(100); // ??
+				}
+				
+			}
+			
+
+		}
+
+		private int GetNextID()
+		{
+			int id = (ClientService.IDs++) % ClientService.MAX_IDS; // we presume that after a million requests, the first ids are free again, if not, tough luck
+			return id;
+		}
+
+        public void StartListening()
+        {
+            string ip = GetLocalIPAddress();
+            Console.WriteLine("ip : " + ip);
+            HttpListener server = new HttpListener();
+            //server.Prefixes.Add($"https://{ip}:{PORT}/");
+            server.Prefixes.Add($"http://localhost:{PORT}/");
+
+            server.Start();
+
+            Console.WriteLine("Listening...");
+
+			waitingRequests = new ConcurrentQueue<ClientService>();
+			readyRequests = new ConcurrentDictionary<int, ClientService>();
+
+
+			Thread requestHandlerThread = new Thread(RequestHandler);
+			requestHandlerThread.Start();
+
+			while (true)
+            {
+                Console.WriteLine("Waiting for a client request...");
+				//Console.ReadLine();
+
+				HttpListenerContext context = server.GetContext();
+				//Thread.Sleep(10000);
+
+				//IAsyncResult result = server.BeginGetContext(new AsyncCallback(ListenerCallback), server);
+				//Console.WriteLine("Waiting for request to be processed asyncronously.");
+				//result.AsyncWaitHandle.WaitOne();
+				//Console.WriteLine("Request processed asyncronously.");
+
+
+
+				if (context.Request.HttpMethod == "GET") // when client says download
+				{
+					Console.WriteLine("received GET request");
+
+					HttpListenerResponse response = context.Response;
+					response.AddHeader("Access-Control-Allow-Credentials", "true");
+					response.AddHeader("Access-Control-Expose-Headers", "ETag");
+					response.AddHeader("Access-Control-Allow-Headers", "Accept, X-Access-Token, X-Application-Name, X-Request-Sent-Time");
+					response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
+					response.AddHeader("Access-Control-Allow-Origin", "*");
+
+
+
+					//string page = Directory.GetCurrentDirectory() + context.Request.Url.LocalPath;
+					// if (page == string.Empty)
+					//     page = "test.txt";
+					// 
+					// TextReader tr = new StreamReader(page);
+					// string msg = tr.ReadToEnd();
+
+					int rand = new Random().Next(1, 10);
+					string msg = "This is a response from the server :) " + rand;
+
+					Response xmlResp = Response.Randomize();
+					var xml = XmlCommunication.Serialize(xmlResp);
+					//Console.WriteLine(xml);
+
+					msg = xml;
+
+					byte[] buffer = Encoding.UTF8.GetBytes(msg);
+
+					response.ContentLength64 = buffer.Length;
+					Stream st = response.OutputStream;
+					st.Write(buffer, 0, buffer.Length);
+
+
+					context.Response.Close();
+				}
+
+				else if (context.Request.HttpMethod == "POST") // when client says upload
+				{
+					Console.WriteLine("received POST request");
+
+					string text;
+					using (var reader = new StreamReader(context.Request.InputStream, context.Request.ContentEncoding))
+						text = reader.ReadToEnd();
+					Console.WriteLine("Received request:");
+					string requestXML = HttpUtility.UrlDecode(text);
+					Console.WriteLine(requestXML);
+
+					Request newRequest = new Request();
+					Request requestDeserialized = XmlCommunication.Deserialize(newRequest, requestXML);
+
+					ClientService newService = new ClientService();
+					newService.UniqueID = GetNextID();
+					newService.ClientRequest = requestDeserialized;
+					// save the request to the queue
+					waitingRequests.Enqueue(newService);
+
+
+
+					// SEND THE ID: - TODO xml format also
+					HttpListenerResponse response = context.Response;
+					response.AddHeader("Access-Control-Allow-Credentials", "true");
+					response.AddHeader("Access-Control-Expose-Headers", "ETag");
+					response.AddHeader("Access-Control-Allow-Headers", "Accept, X-Access-Token, X-Application-Name, X-Request-Sent-Time");
+					response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
+					response.AddHeader("Access-Control-Allow-Origin", "*");
+
+
+
+					int rand = new Random().Next(1, 10);
+					string msg = "" + newService.UniqueID;
+
+					byte[] buffer = Encoding.UTF8.GetBytes(msg);
+
+					response.ContentLength64 = buffer.Length;
+					Stream st = response.OutputStream;
+					st.Write(buffer, 0, buffer.Length);
+
+
+					context.Response.Close(); // ?? Works better with this, if this line is absent, the client gets 'stuck' after approximately 6 messages
+				}
+				else
+				{
+					Console.WriteLine("received request other than GET or POST");
+					Console.WriteLine("method: " + context.Request.HttpMethod);
+					Console.WriteLine("headers: " + context.Request.Headers);
+					Console.WriteLine("whole request?: " + context.Request);
+					Console.WriteLine("user: " + context.User);
+
+
+
+					//HttpListenerResponse response = context.Response;
+					//response.AddHeader("Access-Control-Allow-Credentials", "true");
+					//response.AddHeader("Access-Control-Expose-Headers", "ETag");
+					//response.AddHeader("Access-Control-Allow-Headers", "Accept, X-Access-Token, X-Application-Name, X-Request-Sent-Time, Origin, Content-Type, X-Auth-Token");
+					//response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
+					//response.AddHeader("Access-Control-Allow-Origin", "*");
+
+					//string msg = "Preflight check? ";
+
+					//byte[] buffer = Encoding.UTF8.GetBytes(msg);
+
+					//response.ContentLength64 = buffer.Length;
+					//Stream st = response.OutputStream;
+					//st.Write(buffer, 0, buffer.Length);
+
+
+					//context.Response.Close(); // ??
+
+				}
+			}
+        }
+
+
+
+
+
+
+
+
+
+
+
+		private void ListenerCallback(IAsyncResult result)
+		{
+			HttpListener listener = (HttpListener)result.AsyncState;
+			// Call EndGetContext to complete the asynchronous operation.
+			HttpListenerContext context = listener.EndGetContext(result);
+
+			Console.WriteLine("callbacking...");
+
+			Thread.Sleep(10000);
+
+			if (context.Request.HttpMethod == "GET") // when client says download
+			{
+				Console.WriteLine("received GET request");
+
+				HttpListenerResponse response = context.Response;
+				response.AddHeader("Access-Control-Allow-Credentials", "true");
+				response.AddHeader("Access-Control-Expose-Headers", "ETag");
+				response.AddHeader("Access-Control-Allow-Headers", "Accept, X-Access-Token, X-Application-Name, X-Request-Sent-Time");
+				response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
+				response.AddHeader("Access-Control-Allow-Origin", "*");
+
+
+
+				//string page = Directory.GetCurrentDirectory() + context.Request.Url.LocalPath;
+				// if (page == string.Empty)
+				//     page = "test.txt";
+				// 
+				// TextReader tr = new StreamReader(page);
+				// string msg = tr.ReadToEnd();
+
+				int rand = new Random().Next(1, 10);
+				string msg = "This is a response from the server :) " + rand;
+
+				Response xmlResp = Response.Randomize();
+				var xml = XmlCommunication.Serialize(xmlResp);
+				//Console.WriteLine(xml);
+
+				msg = xml;
+
+				byte[] buffer = Encoding.UTF8.GetBytes(msg);
+
+				response.ContentLength64 = buffer.Length;
+				Stream st = response.OutputStream;
+				st.Write(buffer, 0, buffer.Length);
+
+
+				context.Response.Close();
+			}
+
+			else if (context.Request.HttpMethod == "POST") // when client says upload
+			{
+				Console.WriteLine("received POST request");
+
+				string text;
+				using (var reader = new StreamReader(context.Request.InputStream, context.Request.ContentEncoding))
+					text = reader.ReadToEnd();
+				Console.WriteLine("Received request:");
+				Console.WriteLine(HttpUtility.UrlDecode(text));
+
+
+
+				HttpListenerResponse response = context.Response;
+				response.AddHeader("Access-Control-Allow-Credentials", "true");
+				response.AddHeader("Access-Control-Expose-Headers", "ETag");
+				response.AddHeader("Access-Control-Allow-Headers", "Accept, X-Access-Token, X-Application-Name, X-Request-Sent-Time");
+				response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
+				response.AddHeader("Access-Control-Allow-Origin", "*");
+
+
+
+				int rand = new Random().Next(1, 10);
+				string msg = "OK " + rand;
+
+				byte[] buffer = Encoding.UTF8.GetBytes(msg);
+
+				response.ContentLength64 = buffer.Length;
+				Stream st = response.OutputStream;
+				st.Write(buffer, 0, buffer.Length);
+
+
+				context.Response.Close(); // ?? Works better with this, if this line is absent, the client gets 'stuck' after approximately 6 messages
+			}
+			else
+			{
+				Console.WriteLine("received request other than GET or POST");
+				Console.WriteLine("method: " + context.Request.HttpMethod);
+				Console.WriteLine("headers: " + context.Request.Headers);
+				Console.WriteLine("whole request?: " + context.Request);
+				Console.WriteLine("user: " + context.User);
+
+
+
+				//HttpListenerResponse response = context.Response;
+				//response.AddHeader("Access-Control-Allow-Credentials", "true");
+				//response.AddHeader("Access-Control-Expose-Headers", "ETag");
+				//response.AddHeader("Access-Control-Allow-Headers", "Accept, X-Access-Token, X-Application-Name, X-Request-Sent-Time, Origin, Content-Type, X-Auth-Token");
+				//response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
+				//response.AddHeader("Access-Control-Allow-Origin", "*");
+
+				//string msg = "Preflight check? ";
+
+				//byte[] buffer = Encoding.UTF8.GetBytes(msg);
+
+				//response.ContentLength64 = buffer.Length;
+				//Stream st = response.OutputStream;
+				//st.Write(buffer, 0, buffer.Length);
+
+
+				//context.Response.Close(); // ??
+
+			}
+
+
+
+
+
+
+
+
+
+
+			//HttpListenerRequest request = context.Request;
+			//// Obtain a response object.
+			//HttpListenerResponse response = context.Response;
+			//// Construct a response.
+			//string responseString = "<HTML><BODY> Hello world!</BODY></HTML>";
+			//byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
+			//// Get a response stream and write the response to it.
+			//response.ContentLength64 = buffer.Length;
+			//System.IO.Stream output = response.OutputStream;
+			//output.Write(buffer, 0, buffer.Length);
+			//// You must close the output stream.
+			//output.Close();
+		}
+
+
+		private string GetLocalIPAddress()
+        {
+            var host = Dns.GetHostEntry(Dns.GetHostName());
+            foreach (var ip in host.AddressList)
+            {
+                if (ip.AddressFamily == AddressFamily.InterNetwork)
+                {
+                    return ip.ToString();
+                }
+            }
+            throw new Exception("No network adapters with an IPv4 address in the system!");
+        }
+
+    }
+
+}
diff --git a/Server/ServerApp/DataDownload/Date.cs b/Server/ServerApp/DataDownload/Date.cs
index 5c43a99..4fef619 100644
--- a/Server/ServerApp/DataDownload/Date.cs
+++ b/Server/ServerApp/DataDownload/Date.cs
@@ -117,15 +117,15 @@ namespace ServerApp.DataDownload
 			return !(d1 > d2);
 		}
 
-		public static bool operator ==(Date d1, Date d2)
-		{
-			return d1.Equals(d2);
-		}
-
-		public static bool operator !=(Date d1, Date d2)
-		{
-			return !d1.Equals(d2);
-		}
+		//public static bool operator ==(Date d1, Date d2)
+		//{
+		//	return d1.Equals(d2);
+		//}
+
+		//public static bool operator !=(Date d1, Date d2)
+		//{
+		//	return !d1.Equals(d2);
+		//}
 
 		#endregion
 	}
diff --git a/Server/ServerApp/Program.cs b/Server/ServerApp/Program.cs
index b935858..5338766 100644
--- a/Server/ServerApp/Program.cs
+++ b/Server/ServerApp/Program.cs
@@ -42,17 +42,52 @@ namespace ServerApp
 				return;
 			}
 
-            
+			// commands accepting test
 			//create a thread for commands accepting:
 			//Thread inputThread = new Thread(CommandsAcceptor.AcceptCommand);
 			//inputThread.Start();
 
 
-
+			// is this obsolete?
 			//DataParser p = new DataParser("data/");
 			//p.Parse();
 
-			#region UNCOMMENT
+
+
+			// data download test
+			//DataDownloader dd = DataDownloadAndRetrievalTest(config);
+
+			// xml building test
+			//XMLTest();
+
+
+
+			// PARSE DATA
+
+
+
+			
+			// json parser test
+			//JSONParserTest();
+
+			// model test
+			//IPredictionController controller = PredictionTest(dd);
+
+
+
+			//parse(new DateTime(2019, 10, 5), , interval = 1, wholeDay = true)
+
+
+			// connection test
+			ConnectionTest(/*controller,*/ config);
+			
+
+			Console.ReadLine();
+        }
+
+
+		private static DataDownloader DataDownloadAndRetrievalTest(Config config)
+		{
 			//test scenario -data download:
 			DataDownloader dd = new DataDownloader(config.DataRootDir, config.DataWebsite, config.DownloadedFilesNaming);
 			dd.OverwriteExisting = false;
@@ -63,78 +98,56 @@ namespace ServerApp
 
 
 
-			//Console.WriteLine("Saved files: ");
-			//foreach (string s in savedFiles)
-			//{
-			//	Console.WriteLine(s);
-			//}
-
-			//Console.WriteLine("subdirectories: ");
-			//foreach (KeyValuePair<DataType, string> kvp in dd.DataSubDirectories)
-			//{
-			//	Console.WriteLine("Key = {0}, Value = {1}", kvp.Key, kvp.Value);
-			//}
-
-			//List<string> retrievedData = dd.GetData(dd.DataSubDirectories[DataType.JIS], new DataDownload.Date(10, 2019), new DataDownload.Date(12, 2020));
-			//Console.WriteLine("Retrieved data: ");
-			//foreach (string s in retrievedData)
-			//{
-			//	Console.WriteLine(s);
-			//}
-			//Console.WriteLine("all from directory:");
-			//retrievedData = dd.GetData(dd.DataSubDirectories[DataType.JIS], null, null);
-			//foreach (string s in retrievedData)
-			//{
-			//	Console.WriteLine(s);
-			//}
-			// test - connection:
-			//ConnectionListener cl = new ConnectionListener(int.Parse(config.Port));
-			//cl.StartListening();
-			#endregion
-
-			#region XML_TEST
-			//Response response = Response.Randomize();
-			//var xml = XmlCommunication.Serialize(response);
-			//Console.WriteLine(xml);
-			//Response responseDeserialized = XmlCommunication.Deserialize(response, xml);
-
-			//Console.WriteLine("------");
-
-
-			//Request request = Request.Randomize();
-			//xml = XmlCommunication.Serialize(request);
-			//Console.WriteLine(xml);
-			//Request requestDeserialized = XmlCommunication.Deserialize(request, xml);
-			#endregion
-
-
-			//Console.WriteLine("Saved files: ");
-			//foreach (string s in savedFiles)
-			//{
-			//	Console.WriteLine(s);
-			//}
-
-			//Console.WriteLine("subdirectories: ");
-			//foreach (KeyValuePair<DataType, string> kvp in dd.DataSubDirectories)
-			//{
-			//	Console.WriteLine("Key = {0}, Value = {1}", kvp.Key, kvp.Value);
-			//}
-
-			/*
-			
-			List<string> retrievedData = dd.GetData(dd.DataSubDirectories[DataType.JIS], new Date(10, 2019), new Date(12, 2020));
+			Console.WriteLine("Saved files: ");
+			foreach (string s in savedFiles)
+			{
+				Console.WriteLine(s);
+			}
+
+			Console.WriteLine("subdirectories: ");
+			foreach (KeyValuePair<DataType, string> kvp in dd.DataSubDirectories)
+			{
+				Console.WriteLine("Key = {0}, Value = {1}", kvp.Key, kvp.Value);
+			}
+
+			List<string> retrievedData = dd.GetData(dd.DataSubDirectories[DataType.JIS], new DataDownload.Date(10, 2019), new DataDownload.Date(12, 2020));
 			Console.WriteLine("Retrieved data: ");
 			foreach (string s in retrievedData)
 			{
 				Console.WriteLine(s);
 			}
-			*/
+			Console.WriteLine("all from directory:");
+			retrievedData = dd.GetData(dd.DataSubDirectories[DataType.JIS], null, null);
+			foreach (string s in retrievedData)
+			{
+				Console.WriteLine(s);
+			}
+
+
+			return dd;
+		}
+
+
+		private static void XMLTest()
+		{
+			Response response = Response.Randomize();
+			var xml = XmlCommunication.Serialize(response);
+			Console.WriteLine(xml);
+			Response responseDeserialized = XmlCommunication.Deserialize(response, xml);
 
-            // PARSE DATA
+			Console.WriteLine("------");
 
 
+			Request request = Request.Randomize();
+			xml = XmlCommunication.Serialize(request);
+			Console.WriteLine(xml);
+			Request requestDeserialized = XmlCommunication.Deserialize(request, xml);
+		}
+
 
-            JsonParser jsonP = new JsonParser(null);
+		private static void JSONParserTest()
+		{
+			JsonParser jsonP = new JsonParser(null);
 			jsonP.ParsePrediction();
 
 			var res = jsonP.GetPredictionForTime(jsonP.Predictions[5].startTime, jsonP.Predictions[20].startTime);
@@ -142,27 +155,30 @@ namespace ServerApp
 			Console.WriteLine("end " + jsonP.Predictions[20].startTime);
 			foreach (WeatherInfo w in res)
 				Console.WriteLine(w.ToString());
+		}
 
-
+		private static IPredictionController PredictionTest(DataDownloader dd)
+		{
 			// TODO nastavit čas
 			IDataParser p = new DataParser(dd);
-            IPredictionController predictionController = new PredictionController(p);
-            predictionController.Train();
-            //var results = predictionController.Predict()
-			
-
-			//parse(new DateTime(2019, 10, 5), , interval = 1, wholeDay = true)
+			IPredictionController predictionController = new PredictionController(p);
+			predictionController.Train();
+			//var results = predictionController.Predict()
 
+			return predictionController;
+		}
 
-			// test - connection:
-			//ConnectionListener cl = new ConnectionListener(int.Parse(args[0])/*8000*//*int.Parse(config.Port)*/);
-			//cl.StartListening();
+		private static void ConnectionTest(/*IPredictionController predictionController,*/ Config config)
+		{
+			ConnectionListener cl = new ConnectionListener(int.Parse(config.Port));
+			cl.StartListening();
 
-			Console.ReadLine();
-        }
+			//HttpRequestHandler hrh = new HttpRequestHandler(int.Parse(config.Port));
+			//hrh.ListenAsynchronously();
+		}
 
 
-        private static Config FillConfigInfo(string[] args)
+		private static Config FillConfigInfo(string[] args)
 		{
 
 			Config extractedConfigInfo = new Config();
diff --git a/Server/ServerApp/ServerApp.csproj b/Server/ServerApp/ServerApp.csproj
index 2afd7df..af87444 100644
--- a/Server/ServerApp/ServerApp.csproj
+++ b/Server/ServerApp/ServerApp.csproj
@@ -157,7 +157,7 @@
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
-    <Compile Include="Connection\ConnectionListener.cs" />
+    <Compile Include="Connection\ConnectionListenerMulti.cs" />
     <Compile Include="Connection\XMLProtocolHandler\Buildings.cs" />
     <Compile Include="Connection\XMLProtocolHandler\Date.cs" />
     <Compile Include="Connection\XMLProtocolHandler\Prediction.cs" />
