#ifndef BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_ASYNC_MESSAGE_HPP_20100622
#define BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_ASYNC_MESSAGE_HPP_20100622

// Copyright 2010 (c) Dean Michael Berris
// Copyright 2010 (c) Sinefunc, Inc.
// Copyright 2011 Dean Michael Berris (dberris@google.com).
// Copyright 2011 Google, Inc.
// 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)

#include <boost/thread/future.hpp>
#include <boost/cstdint.hpp>
#include <boost/optional.hpp>

// FIXME move this out to a trait
#include <set>
#include <boost/foreach.hpp>
#include <boost/network/detail/wrapper_base.hpp>

namespace boost {
namespace network {
namespace http {

namespace impl {

template <class Tag>
struct ready_wrapper;

} /* impl */

template <class Tag>
struct async_message {

  typedef typename string<Tag>::type string_type;
  typedef typename headers_container<Tag>::type headers_container_type;
  typedef typename headers_container_type::value_type header_type;

  async_message()
      : status_message_(),
        version_(),
        source_(),
        destination_(),
        status_(),
        headers_(),
        body_() {}

  async_message(async_message const& other)
      : status_message_(other.status_message_),
        version_(other.version_),
        source_(other.source_),
        destination_(other.destination_),
        status_(other.status_),
        headers_(other.headers_),
        body_(other.body_) {}

  string_type const status_message() const { return status_message_.get(); }

  void status_message(boost::shared_future<string_type> const& future) const {
    status_message_ = future;
  }

  string_type const version() const { return version_.get(); }

  void version(boost::shared_future<string_type> const& future) const {
    version_ = future;
  }

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

  void status(boost::shared_future<uint16_t> const& future) const {
    status_ = future;
  }

  string_type const source() const { return source_.get(); }

  void source(boost::shared_future<string_type> const& future) const {
    source_ = future;
  }

  string_type const destination() const { return destination_.get(); }

  void destination(boost::shared_future<string_type> const& future) const {
    destination_ = future;
  }

  headers_container_type const& headers() const {
    if (retrieved_headers_) return *retrieved_headers_;
    headers_container_type raw_headers = headers_.get();
    raw_headers.insert(added_headers.begin(), added_headers.end());
    BOOST_FOREACH(string_type const & key, removed_headers) {
      raw_headers.erase(key);
    }
    retrieved_headers_ = raw_headers;
    return *retrieved_headers_;
  }

  void headers(boost::shared_future<headers_container_type> const& future)
      const {
    headers_ = future;
  }

  void add_header(typename headers_container_type::value_type const& pair_)
      const {
    added_headers.insert(added_headers.end(), pair_);
  }

  void remove_header(typename headers_container_type::key_type const& key_)
      const {
    removed_headers.insert(key_);
  }

  string_type const body() const { return body_.get(); }

  void body(boost::shared_future<string_type> const& future) const {
    body_ = future;
  }

  void swap(async_message& other) {
    std::swap(status_message_, other.status_message_);
    std::swap(status_, other.status_);
    std::swap(version_, other.version_);
    std::swap(source_, other.source_);
    std::swap(destination_, other.destination_);
    std::swap(headers_, other.headers_);
    std::swap(body_, other.body_);
  }

  async_message& operator=(async_message other) {
    other.swap(*this);
    return *this;
  }

 private:
  mutable boost::shared_future<string_type> status_message_, version_, source_,
      destination_;
  mutable boost::shared_future<boost::uint16_t> status_;
  mutable boost::shared_future<headers_container_type> headers_;
  mutable headers_container_type added_headers;
  mutable std::set<string_type> removed_headers;
  mutable boost::shared_future<string_type> body_;
  mutable boost::optional<headers_container_type> retrieved_headers_;

  friend struct boost::network::http::impl::ready_wrapper<Tag>;
};

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

}  // namespace http

}  // namespace network

}  // namespace boost

#endif  // BOOST_NETWORK_PROTOCOL_HTTP_MESSAGE_ASYNC_MESSAGE_HPP_20100622
