
#include "Webserv.hpp"

Webserv::Webserv()
{
	std::cout << "Server init\n";
	_socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
	if (_socket_fd == -1)
	{
		::perror("err socket(): ");
		throw std::runtime_error("Socket init");
	}
}

Webserv::~Webserv()
{
	std::cout << "Server destroyed\n";
}


  ///////////////
 // Functions //

void	Webserv::bind(in_port_t port)
{
	// cast invalid ? how to ?
	// const struct sockaddr* cast_test = static_cast<const struct sockaddr*>(addr);

	struct sockaddr_in	addr;
	addr.sin_family = AF_INET;
	addr.sin_port = ::htons(port);
	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)
	{
		::perror("err bind(): ");
		throw std::runtime_error("Socket bind");		
//		std::cerr << "error bind\n";
	}
}

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

#define BUFSIZE 8192
#define MSG_TEST "Le Webserv / 20 =D\n"
#define MSG_BOUNCE "bounced properly ;)\n" // placeholder

void	Webserv::start()
{
	struct sockaddr_in	addr;
	socklen_t 			addr_len;
	int					accepted_fd;

	// poll (or equivalent)
	struct pollfd	poll_s;
	poll_s.fd = _socket_fd;
	poll_s.events = POLLIN;

	char	buf[BUFSIZE]; // WIP buffer. need to try with std::vector or std::string.
	int		ret;

	std::cout << "Server started\n";
	while (1)
	{
		std::cout << "----------\n";
		std::cout << "poll()\n"; // poll (or equivalent)
		::poll(&poll_s, 1, -1);

		addr_len = sizeof addr;
		accepted_fd = ::accept(_socket_fd, (sockaddr*)&addr, &addr_len);
		if (accepted_fd == -1)
		{
			::perror("err accept(): ");
			//throw WebservError();
			continue;		
		}
		std::cout << "accept()\n";

		// "Your server must never block and the client can be bounced properly if necessary".
		// NO-Block OK, but how to handle it ? Miss the bouncing part.
		::fcntl(accepted_fd, F_SETFL, O_NONBLOCK);

		std::cout << "recv()\n";
		ret = ::recv(accepted_fd, buf, BUFSIZE, 0);
		if (ret == -1)
		{
			::perror("err recv(): ");
			if (::send(accepted_fd, MSG_BOUNCE, sizeof MSG_BOUNCE - 1, 0) == -1)
				::perror("err send(): ");
			::close(accepted_fd);
			continue;
		}
		/*
		if (ret == BUFSIZE)
			// send error like "request too long" to client
		*/
		buf[ret] = '\0';
		
		std::cout << "send()\n";
		if (::send(accepted_fd, buf, ret, 0) == -1) // echo the read
			::perror("err send(): ");
		if (::send(accepted_fd, MSG_TEST, sizeof MSG_TEST - 1, 0) == -1)
			::perror("err send(): ");

		::close(accepted_fd);
	}
}
