/// <summary>Parses incoming data into an HTTP request</summary>
    /// <param name="buffer">Buffer containing the received data</param>
    /// <param name="receivedByteCount">Number of bytes in the receive buffer</param>
    private void parseRequest(byte[] buffer, int receivedByteCount) {

      ArraySegment<byte> data = new ArraySegment<byte>(buffer, 0, receivedByteCount);

      while(data.Count > 0) {

        Response response; // Response that will be delivered to the client
        bool dropConnection = false; // Whether to close the connection

        try {

          // Try to parse a complete request from the bytes the client has sent to us.
          // If there isn't enough data available yet, we exit here and hopefully the
          // next time data arrives it will be enough to complete the request entity.
          Request request = this.parser.ProcessBytes(data.Array, data.Offset, data.Count);
          if(request == null) {
            break;
          }

          // We've got an actual request. Now let's handle it using the implementation
          // provided by the deriving class from the user!
          response = ProcessRequest(request);

        }
        catch(Exceptions.HttpException httpException) {
          response = new Response(httpException.StatusCode, httpException.Message);
          dropConnection = true;
        }
        catch(Exception exception) {
          response = new Response(StatusCode.S500_Internal_Server_Error, exception.Message);
          dropConnection = true;
        }

        // Transform the response entity into a stream of bytes and send it back to
        // the client. If any additional data has to be transmitted, this will be handled
        // by the attachment transmitter.
        byte[] responseBytes = ResponseFormatter.Format(response);
        this.socket.Send(responseBytes); // TODO: Can get an ObjectDisposedException here!

        // TODO: Evil hack!
        if(response.AttachedStream != null) {
          this.socket.Send(((MemoryStream)response.AttachedStream).GetBuffer());
        }

        // TODO: Respect the keep-alive request header here
        //       If keep-alive is not set, we should close the connection here!

        if(dropConnection) {
          Drop();
        } else {
          // Now take the remaining data out of the parser and bring the parser back into
          // its initial state so it can begin parsing the next request
          data = this.parser.GetRemainingData();
          this.parser.Reset();
        }

      }

    }
    /// <summary>Processes the provided request and generates a server response</summary>
    /// <param name="request">Request to be processed by the server</param>
    /// <returns>The response to the server request</returns>
    protected virtual Response ProcessRequest(Request request) {
#if true // GENERATE_DUMMY_RESPONSE

      Console.WriteLine(
        DateTime.Now.ToString() + " Processed request for " + request.Uri
      );

      // Here's the HTML document we want to send to the client
      MemoryStream messageMemory = new MemoryStream();
      StreamWriter writer = new StreamWriter(messageMemory, Encoding.UTF8);
      writer.WriteLine("<html>");
      writer.WriteLine("<head><title>Hello World</title></head>");
      writer.WriteLine("<body><small>Hello World from the Nuclex Web Server</small></body>");
      writer.WriteLine("</html>");
      writer.Flush();

      // Prepare the response message
      Response theResponse = new Response(StatusCode.S200_OK);

      // Add some random headers web server's like to provider
      theResponse.Headers.Add("Cache-Control", "private");
      theResponse.Headers.Add("Content-Type", "text/html; charset=UTF-8");
      theResponse.Headers.Add("Date", "Wed, 30 Jul 2008 14:01:06 GMT");
      theResponse.Headers.Add("Server", "Nuclex");

      // Attach the HTML document to our response
      theResponse.AttachStream(messageMemory);

      // Now comes the important part, specify how many bytes we're going to
      // transmit.
      // TODO: This should be done by parseRequest()
      //       Whether it's needed or not depends on the transport protocol used
      messageMemory.Position = 0;
      theResponse.Headers.Add("Content-Length", messageMemory.Length.ToString());

#endif

      return theResponse;
    }
    /// <summary>
    ///   Convert the provided response into the HTTP response transport format
    /// </summary>
    /// <param name="response">Response that will be converted</param>
    /// <returns>
    ///   An array of bytes containing the response in the HTTP response format
    /// </returns>
    public static byte[] Format(Response response) {

      // Make sure the status code is in a valid numerical range. We will also need
      // this int later to avoid .NETs enum to string conversion helpfulness
      int intStatusCode = (int)response.StatusCode;
      if((intStatusCode < 100) || (intStatusCode > 599)) {
        throw new InvalidOperationException("Invalid status code in response");
      }

      // Build a usable status message string. If the request processor specified
      // null for the status message, we try to replace it with the default message
      // for the given status code. If that also doesn't work, we'll send an empty
      // status message.
      string statusMessage = response.StatusMessage;
      if(statusMessage == null) {
        statusMessage = StatusCodeHelper.GetDefaultDescription(response.StatusCode);
        if(statusMessage == null) {
          statusMessage = string.Empty;
        }
      }

      // Calculate the total size of the return packet
      int combinedLength;
      int versionLength, statusMessageLength;
      int[,] headerLengths;

      // Status line
      {
        // Sum up the length of the constant parts of the reply
        // <Version> SP:1 <StatusCode:3> SP:1 <StatusMessage> CRLF:2 <Headers> CRLF:2
        combinedLength = 1 + 3 + 1 + 2 + 2; // SP + StatusCode + SP + CRLF + CRLF

        // Add the length of the HTTP version and status message
        versionLength = iso88591Encoding.GetByteCount(response.Version);
        combinedLength += versionLength;
        statusMessageLength = iso88591Encoding.GetByteCount(statusMessage);
        combinedLength += statusMessageLength;
      }
      
      // Headers
      {
        // Add the constant per-header overhead of 4 bytes
        // <FieldName> DCOLON:1 SP:1 <FieldValue> CRLF:2
        combinedLength += response.Headers.Count * 4;
        headerLengths = new int[response.Headers.Count, 2];

        // Now sum up the length of the dynamic parts in all header fields
        int headerIndex = 0;
        foreach(KeyValuePair<string, string> header in response.Headers) {
          headerLengths[headerIndex, 0] = iso88591Encoding.GetByteCount(header.Key);
          headerLengths[headerIndex, 1] = iso88591Encoding.GetByteCount(header.Value);

          combinedLength += headerLengths[headerIndex, 0] + headerLengths[headerIndex, 1];
          ++headerIndex;
        }
      }

      // Now that we know the length of the response message, we can set up a buffer and
      // construct the response in it.
      byte[] responseBytes = new byte[combinedLength];
      int responseByteIndex = 0;

      // Write the HTTP protocol version
      iso88591Encoding.GetBytes(
        response.Version, 0, response.Version.Length, responseBytes, 0
      );
      responseByteIndex += versionLength;
      responseBytes[responseByteIndex] = SP;
      ++responseByteIndex;

      //IFormatProvider
      

      // Write the status code
      iso88591Encoding.GetBytes(
        intStatusCode.ToString(), 0, 3, responseBytes, responseByteIndex
      ); // TODO: use explicit locale
      responseByteIndex += 3;
      responseBytes[responseByteIndex] = SP;
      ++responseByteIndex;

      // Write the status message
      iso88591Encoding.GetBytes(
        statusMessage, 0, statusMessage.Length,
        responseBytes, responseByteIndex
      );
      responseByteIndex += statusMessageLength;
      responseBytes[responseByteIndex] = CR;
      ++responseByteIndex;
      responseBytes[responseByteIndex] = LF;
      ++responseByteIndex;

      // Write headers
      {
        int headerIndex = 0;
        foreach(KeyValuePair<string, string> header in response.Headers) {

          // Write header name
          iso88591Encoding.GetBytes(
            header.Key, 0, header.Key.Length, responseBytes, responseByteIndex
          );
          responseByteIndex += headerLengths[headerIndex, 0];
          responseBytes[responseByteIndex] = DC;
          ++responseByteIndex;
          responseBytes[responseByteIndex] = SP; // not in RFC, but common practice
          ++responseByteIndex;

          // Write header value
          iso88591Encoding.GetBytes(
            header.Value, 0, header.Value.Length, responseBytes, responseByteIndex
          );
          responseByteIndex += headerLengths[headerIndex, 1];
          responseBytes[responseByteIndex] = CR;
          ++responseByteIndex;
          responseBytes[responseByteIndex] = LF; // not in RFC, but common practice
          ++responseByteIndex;
          
          ++headerIndex;

        }
      }

      responseBytes[responseByteIndex] = CR;
      ++responseByteIndex;
      responseBytes[responseByteIndex] = LF; // not in RFC, but common practice
      ++responseByteIndex;

      return responseBytes;
    }