// This file is part of the Boost Network library
// Based on the Pion Network Library (r421)
// Copyright Atomic Labs, Inc. 2007-2008
// See http://cpp-netlib.sourceforge.net for library home page.
//
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//          http://www.boost.org/LICENSE_1_0.txt)
//
// Some changes Copyright (c) Dean Michael Berris 2008

#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_HPP
#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_HPP

#include <boost/network/protocol/http/traits.hpp>
#include <boost/network/protocol/http/message/header/name.hpp>
#include <boost/network/protocol/http/message/header/value.hpp>
#include <boost/network/protocol/http/message/header_concept.hpp>
#include <boost/network/message.hpp>
#include <boost/network/tags.hpp>
#include <string>

namespace boost {
namespace network {
namespace http {

/// base class for HTTP messages (requests and responses)
template <typename Tag>
struct message_impl : public basic_message<Tag> {

  typedef typename string<Tag>::type string_type;

  /// escapes URL-encoded strings (a%20value+with%20spaces)
  static string_type const url_decode(string_type const &str);

  /// encodes strings so that they are safe for URLs (with%20spaces)
  static string_type const url_encode(string_type const &str);

  /// builds an HTTP query string from a collection of query parameters
  static string_type const make_query_string(
      typename query_container<Tag>::type const &query_params);

  /**
   * creates a "Set-Cookie" header
   *
   * @param name the name of the cookie
   * @param value the value of the cookie
   * @param path the path of the cookie
   * @param has_max_age true if the max_age value should be set
   * @param max_age the life of the cookie, in seconds (0 = discard)
   *
   * @return the new "Set-Cookie" header
   */
  static string_type const make_set_cookie_header(
      string_type const &name, string_type const &value,
      string_type const &path, bool const has_max_age = false,
      unsigned long const max_age = 0);

  /** decodes base64-encoded strings
   *
   * @param input base64 encoded string
   * @param output decoded string ( may include non-text chars)
   * @return true if successful, false if input string contains non-base64
   *symbols
   */
  static bool base64_decode(string_type const &input, string_type &output);

  /** encodes strings using base64
   *
   * @param input arbitrary string ( may include non-text chars)
   * @param output base64 encoded string
   * @return true if successful
   */
  static bool base64_encode(string_type const &input, string_type &output);

 protected:
  mutable string_type version_;
  mutable boost::uint16_t status_;
  mutable string_type status_message_;

 private:
  typedef basic_message<Tag> base_type;

 public:
  message_impl() : base_type(), version_(), status_(0u), status_message_() {}

  message_impl(message_impl const &other)
      : base_type(other),
        version_(other.version_),
        status_(other.status_),
        status_message_(other.status_message_) {}

  void version(string_type const &version) const { version_ = version; }

  string_type const version() const { return version_; }

  void status(boost::uint16_t status) const { status_ = status; }

  boost::uint16_t status() const { return status_; }

  void status_message(string_type const &status_message) const {
    status_message_ = status_message;
  }

  string_type const status_message() const { return status_message_; }

  message_impl &operator=(message_impl rhs) {
    rhs.swap(*this);
    return *this;
  }

  void swap(message_impl &other) {
    base_type &base_ref(other), &this_ref(*this);
    std::swap(this_ref, base_ref);
    std::swap(status_, other.status_);
    std::swap(status_message_, other.status_message_);
    std::swap(version_, other.version_);
  }
};

template <class Tag>
inline void swap(message_impl<Tag> &lhs, message_impl<Tag> &rhs) {
  lhs.swap(rhs);
}

typedef message_impl<tags::http_default_8bit_tcp_resolve> message;

}  // namespace http

}  // namespace network

}  // namespace boost

// import implementation file
#include <boost/network/protocol/http/impl/message.ipp>

#endif  // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_HPP
