// file      : web/apache/request -*- C++ -*-
// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd
// license   : MIT; see accompanying LICENSE file

#ifndef WEB_APACHE_REQUEST
#define WEB_APACHE_REQUEST

#include <apr_strings.h>

#include <httpd.h>
#include <http_core.h>
#include <util_script.h>

#include <ios>
#include <chrono>
#include <memory>    // unique_ptr
#include <string>
#include <cassert>
#include <istream>
#include <ostream>
#include <utility>   // move()
#include <streambuf>
#include <stdexcept>
#include <exception>

#include <web/module>
#include <web/apache/stream>

namespace web
{
  namespace apache
  {
    class request: public web::request,
                   public web::response,
                   public write_state
    {
      friend class service;

      request (request_rec* rec) noexcept: rec_ (rec) {rec_->status = HTTP_OK;}

      // Flush of buffered content.
      //
      int
      flush ();

      // Return true if content have been sent to the client, false otherwise.
      //
      bool
      get_write_state () const noexcept {return write_state_;}

      // Get request path.
      //
      virtual const path_type&
      path ();

      // Get request body data stream.
      //
      virtual std::istream&
      content ();

      // Get request parameters.
      //
      virtual const name_values&
      parameters ();

      // Get request cookies.
      //
      virtual const name_values&
      cookies ();

      // Get response status code.
      //
      status_code status () const noexcept {return rec_->status;}

      // Set response status code.
      //
      virtual void
      status (status_code status);

      // Set response status code, content type and get body stream.
      //
      virtual std::ostream&
      content (status_code status,
               const std::string& type,
               bool buffer = true);

      // Add response cookie.
      //
      virtual void
      cookie (const char* name,
              const char* value,
              const std::chrono::seconds* max_age = 0,
              const char* path = 0,
              const char* domain = 0,
              bool secure = false);

    private:
      // Get application/x-www-form-urlencoded form data.
      //
      const std::string&
      form_data ();

      void
      parse_parameters (const char* args);

      virtual void
      set_write_state ()
      {
        if (!write_state_)
        {
          // Preparing to write a response read and discard request
          // body if any.
          //
          int r (ap_discard_request_body (rec_));

          if (r != OK)
          {
            throw invalid_request (r);
          }

          write_state_ = true;
        }
      }

    private:
      request_rec* rec_;
      bool buffer_ {true};
      bool write_state_ {false};
      std::unique_ptr<std::streambuf> out_buf_;
      std::unique_ptr<std::ostream> out_;
      std::unique_ptr<std::streambuf> in_buf_;
      std::unique_ptr<std::istream> in_;
      path_type path_;
      std::unique_ptr<name_values> parameters_;
      std::unique_ptr<name_values> cookies_;
      std::unique_ptr<std::string> form_data_;
    };
  }
}

#include <web/apache/request.ixx>

#endif // WEB_APACHE_REQUEST