
#ifndef CLIENT_HPP
# define CLIENT_HPP

# include <iostream>
# include <string>
# include <map>
# include <vector>
# include <string.h>		// strdup
# include <netinet/in.h>	// sockaddr_in, struct in_addr
# include <arpa/inet.h>		// htonl, htons, ntohl, ntohs, inet_addr, inet_ntoa
# include "utils.hpp"
# include "ServerConfig.hpp"
# include "parsing_message_http.hpp"

struct Script
{
	std::string							path;
	std::string							info;
};

struct Request
{
	http_method							method;
	std::string							uri;
	std::string							abs_path;
	std::string							query;
	std::string							version;
	std::map<std::string, std::string>	headers;
	std::string							body;
	std::string							port;
	std::string							hostname;
	struct Script						script;
};

class Client
{
	public:
		Client();
		Client(int afd, listen_socket *lsocket, std::string aport, std::string aip);
		~Client();
		// Client(Client const &src);
		// Client &operator=(Client const &rhs);

		std::string				raw_request;
		std::string				response;
		unsigned int			status;
		bool					header_complete;
		size_t					read_body_size;
		ServerConfig			*assigned_server; // cant be const cause of error_pages.operator[]
		const LocationConfig	*assigned_location;

		// getters
		int						get_cl_fd() const;
		const std::string	&	get_cl_port() const;
		const std::string	&	get_cl_ip() const;
		const listen_socket *	get_cl_lsocket() const;

		// requests getters
		http_method		get_rq_method() const;
		std::string		get_rq_method_str() const;
		std::string		get_rq_uri() const;
		std::string		get_rq_abs_path() const;
		std::string		get_rq_query() const;
		std::string		get_rq_version() const;
		std::string		get_rq_body() const;
		std::string		get_rq_port() const;
		std::string		get_rq_hostname() const;
		std::string		get_rq_script_path() const;
		std::string		get_rq_script_info() const;
		std::string		get_rq_headers(const std::string & key) const;

		void	parse_request(std::vector<ServerConfig> &servers);
		void	parse_request_body();
		void	clear();
		void	clear_request();
		void	clear_script();
		bool	fill_script_path(std::string script);

	private:
		int				_fd;
		std::string		_port;
		std::string		_ip;
		listen_socket *	_lsocket;
		struct Request	_request;

		void	_parse_request_line();
		void	_parse_request_headers();
		void	_parse_request_uri( std::string uri );
		void	_parse_port_hostname(std::string host);

		void	_check_request_errors();
};

bool	operator==(const Client& lhs, const Client& rhs);
bool	operator==(const Client& lhs, int fd);
bool	operator==(int fd, const Client& rhs);

// Temporary Global Scope. Probably move to Client in the future.
ServerConfig	*_determine_process_server(Client *client, std::vector<ServerConfig> &servers);
const LocationConfig	*_determine_location(const ServerConfig &server, const std::string &path);

#endif

