/*
        *FUNCTION		: ListenAndRespond
        *PARAMETERS		: ref TcpListener server: server that listen client
        *RETURNS		: no return
        *DESCRIPTION	: This method accept client and create a stream, through the stream it communicate with client
        *                  It enters infinite loop to get clients message in try block, if the stream has problem with connection
        *                  it throws exception.
        */
        public void ListenAndRespond(ref TcpListener server)
        {
            // Buffer for reading data
            Byte[] bytes = new Byte[10240];
            String request = null;

            try
            {
                // Enter the listening loop.
                while (true)
                {
                    //Console.Write("Waiting for a connection... ");

                    // Perform a blocking call to accept requests.
                    // You could also user server.AcceptSocket() here.
                    TcpClient client = server.AcceptTcpClient();
                    //Console.WriteLine("Connected!");

                    request = null;

                    // Get a stream object for reading and writing
                    NetworkStream stream = client.GetStream();

                    int i;

                    // Loop to receive all the data sent by the client.
                    while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
                    {
                        // Translate data bytes to a ASCII string.
                        request = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
                        //Console.WriteLine("Received: {0}", request);

                        // parse the request and return the full response 
                        byte[] respondMsg = ParseRequest(request);


                        //log request header          
                        Logging.WriteLog(HTTPRequestHeader);

                        // string  respondMsg = request.ToUpper();

                        //serialize the response
                        //byte[] msg = System.Text.Encoding.Default.GetBytes(respondMsg);


                        // Send back a response.
                        stream.Write(respondMsg, 0, respondMsg.Length);
                        //Console.WriteLine("Response Sent...");


                        //log response header 
                        Logging.WriteLog(HTTPResponseHeader);
                        //clear the messages
                        HTTPRequestHeader = "";
                        HTTPResponseBody = "";
                        HTTPResponseHeader = "";

                    }

                    // Shutdown and end connection
                    client.Close();
                }
            }

            catch (SocketException e)
            {
                //Console.WriteLine("SocketException: {0}", e.Message);
                Logging.WriteLog($"SocketException: {e.Message}");
            }
            catch (Exception e)
            {
                Logging.WriteLog($"Exception: {e.Message}");
            }


        }
        /*
        *FUNCTION		: ParseRequest
        *PARAMETERS		: string request : The request string from the client
        *RETURNS		: byte[] : A byte array that contains response
        *DESCRIPTION	: This method first,parse header of the request. second, find the file that client request, 
        *                  third, generate header and body of response, forth, combine header and body in byte array form
        *                  It fill the header with error code and error message if errors accur
        */
        public byte[] ParseRequest(string request)
        {

            try
            {

               string requestFirstLine = request.Substring(0, request.IndexOf('\r'));
               string requestTheRest = request.Substring(request.IndexOf('\n') + 1);

                //In the parsed first line the [0] is method, the [1] is file path, the [2] is HTML Version
                string[] parsedRequestFirstLine = requestFirstLine.Split(' ');
                string method = parsedRequestFirstLine[0];
                string filePath = WebRoot + parsedRequestFirstLine[1];

                string requestSecondLine = requestTheRest.Substring(0, requestTheRest.IndexOf('\r'));

                //creat the request header
                HTTPRequestHeader = requestFirstLine + Environment.NewLine + requestSecondLine;

                //method is not GET
                if (method != "GET")
                {
                    StatusCode = "405 Method Not Allowed";

                }
                //file does not exist
               else if(!File.Exists(filePath))
                {
                    StatusCode = "404 Not Found";
                }
                else
                {

                    //check suffix if not found in dictionary  406
                    FileSuffix = Path.GetExtension(filePath);
                     
                    if(!MIMETypes.ContainsKey(FileSuffix))
                    {
                        StatusCode = "406 Not Acceptable";
                    }
                    else
                    {
                        
                        byte[] content = File.ReadAllBytes(filePath);
                        byteBody = content;

                        ContentLength = content.Length;

                        // all OK 200
                        StatusCode = "200 OK";
                    }

                }
                //after parsing build the response
                BuildResponse();
            }
            catch (Exception e)
            {
                // File I/O exceptions 500
                if( e is ArgumentException ||
                    e is ArgumentNullException ||
                    e is PathTooLongException ||
                    e is IOException ||
                    e is UnauthorizedAccessException)
                {
                    StatusCode = "500 Internal Server Error";
                }
                //parse exception 400
                else
                {
                    StatusCode = "400 Bad Request";
                }

                //Console.WriteLine($"Exception:{e.Message}");
                Logging.WriteLog($"Exception:{e.Message}");

                BuildResponse();

            }

            if(StatusCode!="200 OK")
            {

                byteBody = System.Text.Encoding.UTF8.GetBytes(HTTPResponseBody);
            }
            byte[] byteHeader = System.Text.Encoding.UTF8.GetBytes(HTTPResponseHeader + Environment.NewLine + Environment.NewLine);


            return Combine(byteHeader, byteBody);

        }