
#include "Webserv.hpp"

void	Webserv::init_virtual_servers(std::vector<ServerConfig>* servers)
{
	int	ret;
	std::vector<std::string>	open_sockets;
	struct listen_socket		new_socket;
	std::string					host_port;

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

	while (it != _servers.end())
	{
		host_port.clear();
		host_port.append(it->host);
		host_port.append(":");
		host_port.append(it->port);
		if ( std::find(open_sockets.begin(), open_sockets.end(), host_port) != open_sockets.end() )
		{
			++it;
			continue;
		}

		ret = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
		if (ret == -1)
		{
			std::perror("err socket()");
			throw std::runtime_error("Socket init");
		}
		new_socket.fd = ret;
		new_socket.host = it->host;
		new_socket.port = it->port;
		_listen_sockets.push_back(new_socket);

		// 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(new_socket.fd, SOL_SOCKET,  SO_REUSEADDR, &on, sizeof(on)) < 0)
		{
			::perror("err setsockopt()");
			throw std::runtime_error("Socket init");
		}
		//
		// HUGO ADD END

		_bind(new_socket.fd, std::strtoul(it->port.c_str(), NULL, 10), it->host);
		_listen(new_socket.fd, 42); // 42 arbitrary

		if (_epoll_update(new_socket.fd, EPOLLIN, EPOLL_CTL_ADD) == -1)
			throw std::runtime_error("Socket init");
		
		open_sockets.push_back(host_port);
		++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()
{
/*	"map.insert()" more appropriate than "map.operator[]" :
**	http://www.uml.org.cn/c%2B%2B/pdf/EffectiveSTL.pdf#page=93
*/
	typedef std::map<int, std::string>::value_type	status_pair;

	// _http_status.insert(std::make_pair(200, S200)); // equivalent
	_http_status.insert(status_pair(200, S200));
	_http_status.insert(status_pair(201, S201));
	_http_status.insert(status_pair(204, S204));

	_http_status.insert(status_pair(301, S301));
	_http_status.insert(status_pair(302, S302));
	_http_status.insert(status_pair(303, S303));
	_http_status.insert(status_pair(304, S304));
	_http_status.insert(status_pair(307, S307));
	_http_status.insert(status_pair(308, S308));

	_http_status.insert(status_pair(400, S400));
	_http_status.insert(status_pair(403, S403));
	_http_status.insert(status_pair(404, S404));
	_http_status.insert(status_pair(405, S405));
	_http_status.insert(status_pair(408, S408));
	_http_status.insert(status_pair(413, S413));
	_http_status.insert(status_pair(415, S415));

	_http_status.insert(status_pair(500, S500));
	_http_status.insert(status_pair(501, S501));
	_http_status.insert(status_pair(505, S505));
}

void	Webserv::_init_mime_types_map()
{
/*	From :
**	http://nginx.org/en/docs/http/ngx_http_core_module.html#types
*/
	typedef std::map<std::string, std::string>::value_type	mime_pair;

	_mime_types.insert(mime_pair("", MIME_TYPE_DEFAULT));

	_mime_types.insert(mime_pair("html", "text/html"));
	_mime_types.insert(mime_pair("html", "text/html"));
	_mime_types.insert(mime_pair("htm", "text/html"));
	_mime_types.insert(mime_pair("shtml", "text/html"));
	_mime_types.insert(mime_pair("css", "text/css"));
	_mime_types.insert(mime_pair("xml", "text/xml"));
	_mime_types.insert(mime_pair("gif", "image/gif"));
	_mime_types.insert(mime_pair("jpeg", "image/jpeg"));
	_mime_types.insert(mime_pair("jpg", "image/jpeg"));
	_mime_types.insert(mime_pair("js", "application/javascript"));
	_mime_types.insert(mime_pair("atom", "application/atom+xml"));
	_mime_types.insert(mime_pair("rss", "application/rss+xml"));

	_mime_types.insert(mime_pair("mml", "text/mathml"));
	_mime_types.insert(mime_pair("txt", "text/plain"));
	_mime_types.insert(mime_pair("jad", "text/vnd.sun.j2me.app-descriptor"));
	_mime_types.insert(mime_pair("wml", "text/vnd.wap.wml"));
	_mime_types.insert(mime_pair("htc", "text/x-component"));

	_mime_types.insert(mime_pair("png", "image/png"));
	_mime_types.insert(mime_pair("tif", "image/tiff"));
	_mime_types.insert(mime_pair("tiff", "image/tiff"));
	_mime_types.insert(mime_pair("wbmp", "image/vnd.wap.wbmp"));
	_mime_types.insert(mime_pair("ico", "image/x-icon"));
	_mime_types.insert(mime_pair("jng", "image/x-jng"));
	_mime_types.insert(mime_pair("bmp", "image/x-ms-bmp"));
	_mime_types.insert(mime_pair("svg", "image/svg+xml"));
	_mime_types.insert(mime_pair("svgz", "image/svg+xml"));
	_mime_types.insert(mime_pair("webp", "image/webp"));

	_mime_types.insert(mime_pair("woff", "application/font-woff"));
	_mime_types.insert(mime_pair("jar", "application/java-archive"));
	_mime_types.insert(mime_pair("war", "application/java-archive"));
	_mime_types.insert(mime_pair("ear", "application/java-archive"));
	_mime_types.insert(mime_pair("json", "application/json"));
	_mime_types.insert(mime_pair("hqx", "application/mac-binhex40"));
	_mime_types.insert(mime_pair("doc", "application/msword"));
	_mime_types.insert(mime_pair("pdf", "application/pdf"));
	_mime_types.insert(mime_pair("ps", "application/postscript"));
	_mime_types.insert(mime_pair("eps", "application/postscript"));
	_mime_types.insert(mime_pair("ai", "application/postscript"));
	_mime_types.insert(mime_pair("rtf", "application/rtf"));
	_mime_types.insert(mime_pair("m3u8", "application/vnd.apple.mpegurl"));
	_mime_types.insert(mime_pair("xls", "application/vnd.ms-excel"));
	_mime_types.insert(mime_pair("eot", "application/vnd.ms-fontobject"));
	_mime_types.insert(mime_pair("ppt", "application/vnd.ms-powerpoint"));
	_mime_types.insert(mime_pair("wmlc", "application/vnd.wap.wmlc"));
	_mime_types.insert(mime_pair("kml", "application/vnd.google-earth.kml+xml"));
	_mime_types.insert(mime_pair("kmz", "application/vnd.google-earth.kmz"));
	_mime_types.insert(mime_pair("7z", "application/x-7z-compressed"));
	_mime_types.insert(mime_pair("cco", "application/x-cocoa"));
	_mime_types.insert(mime_pair("jardiff", "application/x-java-archive-diff"));
	_mime_types.insert(mime_pair("jnlp", "application/x-java-jnlp-file"));
	_mime_types.insert(mime_pair("run", "application/x-makeself"));
	_mime_types.insert(mime_pair("pl", "application/x-perl"));
	_mime_types.insert(mime_pair("pm", "application/x-perl"));
	_mime_types.insert(mime_pair("prc", "application/x-pilot"));
	_mime_types.insert(mime_pair("pdb", "application/x-pilot"));
	_mime_types.insert(mime_pair("rar", "application/x-rar-compressed"));
	_mime_types.insert(mime_pair("rpm", "application/x-redhat-package-manager"));
	_mime_types.insert(mime_pair("sea", "application/x-sea"));
	_mime_types.insert(mime_pair("swf", "application/x-shockwave-flash"));
	_mime_types.insert(mime_pair("sit", "application/x-stuffit"));
	_mime_types.insert(mime_pair("tcl", "application/x-tcl"));
	_mime_types.insert(mime_pair("tk", "application/x-tcl"));
	_mime_types.insert(mime_pair("der", "application/x-x509-ca-cert"));
	_mime_types.insert(mime_pair("pem", "application/x-x509-ca-cert"));
	_mime_types.insert(mime_pair("crt", "application/x-x509-ca-cert"));
	_mime_types.insert(mime_pair("xpi", "application/x-xpinstall"));
	_mime_types.insert(mime_pair("xhtml", "application/xhtml+xml"));
	_mime_types.insert(mime_pair("xspf", "application/xspf+xml"));
	_mime_types.insert(mime_pair("zip", "application/zip"));

	_mime_types.insert(mime_pair("bin", "application/octet-stream"));
	_mime_types.insert(mime_pair("exe", "application/octet-stream"));
	_mime_types.insert(mime_pair("dll", "application/octet-stream"));
	_mime_types.insert(mime_pair("deb", "application/octet-stream"));
	_mime_types.insert(mime_pair("dmg", "application/octet-stream"));
	_mime_types.insert(mime_pair("iso", "application/octet-stream"));
	_mime_types.insert(mime_pair("img", "application/octet-stream"));
	_mime_types.insert(mime_pair("msi", "application/octet-stream"));
	_mime_types.insert(mime_pair("msp", "application/octet-stream"));
	_mime_types.insert(mime_pair("msm", "application/octet-stream"));

	_mime_types.insert(mime_pair("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"));
	_mime_types.insert(mime_pair("xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"));
	_mime_types.insert(mime_pair("pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"));

	_mime_types.insert(mime_pair("mid", "audio/midi"));
	_mime_types.insert(mime_pair("midi", "audio/midi"));
	_mime_types.insert(mime_pair("kar", "audio/midi"));
	_mime_types.insert(mime_pair("mp3", "audio/mpeg"));
	_mime_types.insert(mime_pair("ogg", "audio/ogg"));
	_mime_types.insert(mime_pair("m4a", "audio/x-m4a"));
	_mime_types.insert(mime_pair("ra", "audio/x-realaudio"));

	_mime_types.insert(mime_pair("3gpp", "video/3gpp"));
	_mime_types.insert(mime_pair("3gp", "video/3gpp"));
	_mime_types.insert(mime_pair("ts", "video/mp2t"));
	_mime_types.insert(mime_pair("mp4", "video/mp4"));
	_mime_types.insert(mime_pair("mpeg", "video/mpeg"));
	_mime_types.insert(mime_pair("mpg", "video/mpeg"));
	_mime_types.insert(mime_pair("mov", "video/quicktime"));
	_mime_types.insert(mime_pair("webm", "video/webm"));
	_mime_types.insert(mime_pair("flv", "video/x-flv"));
	_mime_types.insert(mime_pair("m4v", "video/x-m4v"));
	_mime_types.insert(mime_pair("mng", "video/x-mng"));
	_mime_types.insert(mime_pair("asx", "video/x-ms-asf"));
	_mime_types.insert(mime_pair("asf", "video/x-ms-asf"));
	_mime_types.insert(mime_pair("wmv", "video/x-ms-wmv"));
	_mime_types.insert(mime_pair("avi", "video/x-msvideo"));
}

