
#include "Webserv.hpp"

void	Webserv::init_virtual_servers(std::vector<ServerConfig>* servers)
{
	int	ret;
	std::vector<int>	_open_ports;

	_servers = *servers;
	_listen_sockets.clear();
	std::vector<ServerConfig>::iterator	it = _servers.begin();

	while (it != _servers.end())
	{
		if ( std::find(_open_ports.begin(), _open_ports.end(), std::atoi(it->port.data()) ) != _open_ports.end() )
		{
			++it;
			continue;
		}

		ret = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); // (SOCK_CLOEXEC) for CGI fork ?
		if (ret == -1)
		{
			std::perror("err socket()");
			throw std::runtime_error("Socket init");
		}
		// HUGO ADD
		//
		// allow socket descriptor to be reuseable
		// I just copied it from https://www.ibm.com/docs/en/i/7.2?topic=designs-example-nonblocking-io-select
		int	on = 1;
		if (setsockopt(ret, SOL_SOCKET,  SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
		{
			::perror("err setsockopt()");
			throw std::runtime_error("Socket init");
		}
		//
		// HUGO ADD END
		_listen_sockets.push_back(ret);

		_bind(_listen_sockets.back(), std::atoi(it->port.data()), it->host);
		_listen(_listen_sockets.back(), 512); // 512 arbitrary

		if (_epoll_update(_listen_sockets.back(), EPOLLIN, EPOLL_CTL_ADD) == -1)
			throw std::runtime_error("Socket init");
		
		_open_ports.push_back(std::atoi(it->port.data()));
		++it;
	}
}

void	Webserv::_bind(int socket_fd, in_port_t port, std::string host)
{
	// cast invalid ? how to ?
	// const struct sockaddr* cast_test = static_cast<const struct sockaddr*>(addr);

	struct sockaddr_in	addr;
	std::memset(&addr, 0, sizeof addr);
	addr.sin_family = AF_INET;
	addr.sin_port = ::htons(port);
	addr.sin_addr.s_addr = ::htonl(::inet_addr(host.c_str()));
	// addr.sin_addr.s_addr = ::htonl(INADDR_ANY);  // htonl useless with 0 value (INADDR_ANY) ?

	if (::bind(socket_fd, (const sockaddr*)&addr, sizeof addr) == -1)
	{
		std::perror("err bind()");
		throw std::runtime_error("Socket bind");		
	}
}

void	Webserv::_listen(int socket_fd, unsigned int max_connections)
{
	if (::listen(socket_fd, max_connections) == -1)
	{
		std::perror("err listen()");
		throw std::runtime_error("Socket listen");
	}
}

void	Webserv::_init_http_status_map()
{
	_http_status[200] = S200;

	_http_status[400] = S400;
	_http_status[404] = S404;
	_http_status[405] = S405;
	_http_status[413] = S413;

	_http_status[500] = S500;
}
