
#ifndef WEBSERV_HPP
# define WEBSERV_HPP

# include <map>
# include <vector>
# include <exception>		// exception, what
# include <stdexcept>		// runtime_error, invalid_argument
# include <sys/epoll.h>		// epoll
# include <fcntl.h>			// fcntl
# include <sys/wait.h>		// waitpid
# include <csignal>			// signal
# include <fstream>			// ifstream
# include <sstream>			// stringstream
# include <cerrno>			// errno
# include <unistd.h>		// close, access
# include <iostream>		// cout, cin
# include <cstring>			// memset
# include <sys/socket.h>	// socket, accept, listen, send, recv, bind, connect, setsockopt, getsockname
# include <arpa/inet.h>		// htonl, htons, ntohl, ntohs, inet_addr, inet_ntoa
# include <netinet/in.h>	// sockaddr_in, struct in_addr
// # include <netinet/ip.h> // usefull for what ? -> 'man (7) ip' says it's a superset of 'netinet/in.h'
# include <algorithm>		// find
# include <string>			// string
# include <cstdio>			// perror, remove
# include <cstdlib>			// atoi (athough it's already cover by <string>)

# include "Client.hpp"
# include "ServerConfig.hpp"
# include "utils.hpp"
# include "http_status.hpp"

extern bool	g_run;
extern int	g_last_signal;
void	signal_handler(int signum);

// these might only be TMP
# define FAILURE -1
# define SUCCESS 1

class Webserv
{
	public:
	// base.cpp
		Webserv();
		// Webserv(Webserv const &src);

	// what should it take as arg, *, &, ?
//		Webserv(std::vector<ServerConfig>& servers);

		~Webserv();
		// Webserv &operator=(Webserv const &rhs);

	// init.cpp
		void	init_virtual_servers(std::vector<ServerConfig>* servers);
	// run_loop.cpp
		void	run();

	private:
		int	_epfd;
		std::vector<listen_socket>	_listen_sockets;
		std::vector<ServerConfig>	_servers;
		std::vector<Client>			_clients;
		std::map<int, std::string>	_http_status;
		std::map<std::string, std::string>	_mime_types;

	// accept.cpp
		void	_accept_connection(listen_socket &lsocket);
		std::map<std::string, std::string>
				_extract_infos(struct sockaddr_in addr);
	// request.cpp
		void	_request(Client *client);
		void	_read_request(Client *client);
	// response.cpp
		void	_response(Client *client);
		void	_send_response(Client *client, ServerConfig &server);

		void	_append_base_headers(Client *client);
		void	_construct_response(Client *client, ServerConfig &server);
		void	_process_method(Client *client, ServerConfig &server, LocationConfig &location);
		void	_insert_status_line(Client *client);
		void	_error_html_response(Client *client, ServerConfig &server);
		void	_append_body(Client *client, const char *body, size_t body_size, const std::string &file_extension = "");
	
		void	_get(Client *client, ServerConfig &server, LocationConfig &location);
		void	_get_file(Client *client, const std::string &path);

		void	_post(Client *client, ServerConfig &server, LocationConfig &location);
		void	_post_file(Client *client, const std::string &path);

		void	_delete(Client *client, ServerConfig &server, LocationConfig &location);
		void	_delete_file(Client *client, const std::string &path);

		ServerConfig	&_determine_process_server(Client *client);
		LocationConfig	&_determine_location(ServerConfig &server, std::string const &path);
		void	_response_correction(Client *client);
	// cgi_script.cpp
		bool	_is_cgi(Client *client);
		void	_exec_cgi(Client *client);
		char**	_set_env(Client *client);
		char*	_dup_env(std::string var, std::string val);
		char*	_dup_env(std::string var, int i);
		void	_exec_script(Client *client, char **env);
	// epoll_update.cpp
		int		_epoll_update(int fd, uint32_t events, int op);
		int		_epoll_update(int fd, uint32_t events, int op, void *ptr);
	// signal.cpp
		void	_handle_last_signal();
	// close.cpp
		void	_close_client(int fd);
		void	_close_all_clients();
		void	_close_all_listen_sockets();
	// init.cpp
		void	_bind(int socket_fd, in_port_t port, std::string host);
		void	_listen(int socket_fd, unsigned int max_connections);
		void	_init_http_status_map();
		void	_init_mime_types_map();
};

#endif
