#ifndef CPPCMS_IMPL_CGI_API_H
#define CPPCMS_IMPL_CGI_API_H

#include "noncopyable.h"
#include "refcounted.h"
#include "intrusive_ptr.h"
#include <vector>
#include <map>
#include "config.h"
#ifdef CPPCMS_USE_EXTERNAL_BOOST
#   include <boost/function.hpp>
#   include <boost/system/error_code.hpp>
    namespace boost { namespace asio { class io_service; } }
#else // Internal Boost
#   include <cppcms_boost/function.hpp>
#   include <cppcms_boost/system/error_code.hpp>
    namespace cppcms_boost { namespace asio { class io_service; } }
    namespace boost = cppcms_boost;
#endif



namespace cppcms {
	class service;
	class application;
	namespace http {
		class request;
		class response;
	}


namespace impl {
namespace cgi {

	typedef boost::function<void(boost::system::error_code const &e)> handler;
	typedef boost::function<void(boost::system::error_code const &e,size_t)> io_handler;
	typedef boost::function<void()> callback;
	typedef boost::function<void(bool)> ehandler;

	class acceptor : public util::noncopyable {
	public:
		virtual void async_accept() = 0;
		virtual void stop() = 0;
		virtual ~acceptor(){}
	};

	class connection : public refcounted
	{
	public:
		connection(cppcms::service &srv);
		virtual ~connection();
		cppcms::service &service();
	
		void async_prepare_request(	http::request &request,
						ehandler const &on_post_data_ready);

		void async_write_response(	http::response &response,
						bool complete_response,
						ehandler const &on_response_written);

		void async_complete_response(	ehandler const &on_response_complete);
		
		void aync_wait_for_close_by_peer(callback const &on_eof);

		virtual std::string getenv(std::string const &key) = 0;
		virtual std::map<std::string,std::string> const &getenv() = 0;
		size_t write(void const *data,size_t n);
		bool is_reuseable();
	
		std::string last_error();
	
	protected:

		/****************************************************************************/

		// These are abstract member function that should be implemented by
		// actual protocol like FCGI, SCGI, HTTP or CGI

		virtual void async_read_headers(handler const &h) = 0;
		virtual bool keep_alive() = 0;
		virtual void close() = 0;

		// Concept implementation headers		
		
		virtual void async_read_some(void *,size_t,io_handler const &h) = 0;
		virtual void async_read_eof(callback const &h) = 0;
		virtual void async_write_some(void const *,size_t,io_handler const &h) = 0;
		virtual void async_write_eof(handler const &h) = 0;
		virtual size_t write_some(void const *,size_t) = 0;
		virtual boost::asio::io_service &get_io_service() = 0;

		/****************************************************************************/

	protected:
		intrusive_ptr<connection> self();
		void async_read(void *,size_t,io_handler const &h);
		void async_write(void const *,size_t,io_handler const &h);
	private:

		struct reader;
		struct writer;

		friend struct reader;
		friend struct writer;
		void set_error(ehandler const &h,std::string s);
		void load_content(boost::system::error_code const &e,http::request *request,ehandler const &h);
		void on_post_data_loaded(boost::system::error_code const &e,http::request *r,ehandler const &h);
		void on_async_write_written(boost::system::error_code const &e,bool complete_response,ehandler const &h);
		void on_eof_written(boost::system::error_code const &e,ehandler const &h);
		void handle_eof(callback const &on_eof);

		std::vector<char> content_;
		cppcms::service *service_;
		std::string async_chunk_;
		std::string error_;
		bool request_in_progress_;

	};


} // cgi
} // impl
} // cppcms

#endif
