#ifndef HTTP_SERVER_HPP
#define HTTP_SERVER_HPP

#include <set>
#include <boost/asio.hpp>
#include <boost/asio/ssl/context.hpp>
#include <string>
#include "connection.hpp"
#include "resource.h"


namespace http::server {
    /// Manages open connections so that they may be cleanly stopped when the server
    /// needs to shut down.
    class ConnectionManager {
    public:
        ConnectionManager(const ConnectionManager &) = delete;

        ConnectionManager &operator=(const ConnectionManager &) = delete;

        /// Construct a Connection manager.
        ConnectionManager();

        /// Add the specified Connection to the manager and start it.
        void start(const connection_ptr& c);

        /// Stop the specified Connection.
        void stop(const connection_ptr& c);

        /// Stop all connections.
        void stop_all();

    private:
        /// The managed connections.
        std::set<connection_ptr> connections_;
    };


    /// The top-level class of the HTTP server.
    class Server {
    public:
        Server(const Server &) = delete;

        Server &operator=(const Server &) = delete;

        /// Construct the server to listen on the specified TCP address and port
        explicit Server(const std::string &address, const std::string &port);
        explicit Server(const std::string &address, const std::string &port, std::shared_ptr<boost::asio::ssl::context> ctx);

        std::vector<std::unique_ptr<resource::BasicResource>> resources;

        /// Run the server's io_context loop.
        void run();

    private:
        std::shared_ptr<boost::asio::ssl::context> ssl_ctx;

        /// Perform an asynchronous accept operation.
        void doAccept();

        /// Wait for a request to stop the server.
        void doAwaitStop();

        /// The io_context used to perform asynchronous operations.
        boost::asio::io_context io_context_;

        /// The signal_set is used to register for process termination notifications.
        boost::asio::signal_set signals_;

        /// Acceptor used to listen for incoming connections.
        boost::asio::ip::tcp::acceptor acceptor_;

        /// The Connection manager which owns all live connections.
        ConnectionManager connection_manager_;

        /// Handle a request and produce a reply.
        void requestHandler(const Request &req, reply &rep);
    };
} // namespace http::Server


#endif // HTTP_SERVER_HPP
