
#include "Webserv.hpp"

void	Webserv::_close_client(int fd)
{
	std::vector<Client>::iterator	it = _clients.begin();
	std::vector<Client>::iterator	it_end = _clients.end();
	while (it != it_end)
	{
		if (*it == fd)
		{
			// _epoll_update(fd, 0, EPOLL_CTL_DEL); // normalement superflu, DEBUG
			std::cerr << "close fd " << fd << "\n";
			if (::close(fd) == -1)
				std::perror("err close()");
			_clients.erase(it);
			break;
		}
		++it;
	}
}

void	Webserv::_close_all_clients()
{
	_close_all_clients_fd();
	_clients.clear();
}

void	Webserv::_close_all_clients_fd()
{
	_close_all_clients_cgi_fd();
	std::vector<Client>::iterator	it = _clients.begin();
	std::vector<Client>::iterator	it_end = _clients.end();
	while (it != it_end)
	{
		// _epoll_update(_clients.back().fd, 0, EPOLL_CTL_DEL); // normalement superflu, DEBUG
		std::cerr << "close fd " << it->get_cl_fd() << "\n";
		if (::close(it->get_cl_fd()) == -1)
			std::perror("err close()");
		++it;
	}
}

void	Webserv::_close_all_clients_cgi_fd()
{
	std::vector<Client>::iterator	it = _clients.begin();
	std::vector<Client>::iterator	it_end = _clients.end();
	while (it != it_end)
	{
		// _epoll_update(_clients.back().fd, 0, EPOLL_CTL_DEL); // normalement superflu, DEBUG
		if (it->cgi_pipe_rfd)
		{
			std::cerr << "close cgi-fd " << it->cgi_pipe_rfd << "\n";
			if (::close(it->cgi_pipe_rfd) == -1)
				std::perror("err close()");
		}
		++it;
	}
}


void	Webserv::_close_all_listen_sockets()
{ // TODO : change like clients (clear in place of pop_back)
	while (!_listen_sockets.empty())
	{
		// _epoll_update(_listen_sockets.back().fd, 0, EPOLL_CTL_DEL); // normalement superflu, DEBUG
		std::cerr << "close fd " << _listen_sockets.back().fd << "\n";
		if (::close(_listen_sockets.back().fd) == -1)
			std::perror("err close()");
		_listen_sockets.pop_back();
	}
}

void	Webserv::_reopen_lsocket(std::vector<listen_socket>::iterator it)
{
/*
**	Many common code with init_virtual_servers(). Could refactor it.
*/
	int	ret;

	std::cerr << "close lsocket " << it->fd << "\n";
	if (::close(it->fd) == -1)
		std::perror("err close()");
	std::cerr << "try to reopen lsocket\n";
	ret = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
	if (ret == -1)
	{
		std::perror("err socket()");
		_listen_sockets.erase(it);
		return;
	}
	it->fd = ret;

	// 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(it->fd, SOL_SOCKET,  SO_REUSEADDR, &on, sizeof(on)) < 0)
	{
		::perror("err setsockopt()");
		_listen_sockets.erase(it);
		return;
	}
	// HUGO ADD END

	try {
		_bind(it->fd, std::strtoul(it->port.c_str(), NULL, 10), it->host);
		_listen(it->fd, 42); // 42 arbitrary
	}
	catch (const std::exception& e) {
		std::cerr << e.what() << '\n';
		_listen_sockets.erase(it);
		return;
	}

	if (_epoll_update(it->fd, EPOLLIN, EPOLL_CTL_ADD) == -1)
	{
		_listen_sockets.erase(it);
		return;
	}
	std::cerr << "reopen success\n";
}

void	Webserv::_handle_epoll_error_lsocket(uint32_t events, std::vector<listen_socket>::iterator it)
{
	if (events & EPOLLERR)
		std::cerr << "EPOLLERR on lsocket fd " << it->fd << "\n"; // DEBUG
	if (events & EPOLLHUP)
		std::cerr << "EPOLLHUP on lsocket fd " << it->fd << "\n"; // DEBUG
	_reopen_lsocket(it);
}

void	Webserv::_handle_epoll_error_client(uint32_t events, int fd)
{
	if (events & EPOLLERR)
		std::cerr << "EPOLLERR on client fd " << fd << "\n"; // DEBUG
	if (events & EPOLLHUP)
		std::cerr << "EPOLLHUP on client fd " << fd << "\n"; // DEBUG
	if (std::find(_clients.begin(), _clients.end(), fd) != _clients.end())
		std::cerr << "Found the client in _clients" << "\n"; // DEBUG

	_close_client(fd); // " EPOLLHUP on client fd 8 " en boucle quand on mattraque un peu les CGI, donc il ne le trouve pas dans _clients. Etrange.
}
