
#include "Webserv.hpp"

bool	Webserv::_is_cgi(Client *client)
{
	// TODO see how it works with config
	if (client->fill_script_path("/cgi-bin/php-cgi"))
		return true;
	if (client->fill_script_path("/cgi-bin/cgi_cpp.cgi"))
		return true;
	return false;
}

std::string	Webserv::_exec_cgi(Client *client)
{
	char**			env;
	std::string		script_output;

	env = _set_env(client);
	script_output = _exec_script(client, env);

	for (int i = 0; env[i]; i++)
		delete[] env[i];
	delete[] env;

	return script_output;
}

char*	Webserv::_dup_env(std::string var, std::string val = "")
{
	std::string str;

	str = var + "=" + val;
	return ( strdup(str.c_str()) );
}

char*	Webserv::_dup_env(std::string var, int i)
{
	std::string str;
	std::string val;

	val = ::itos(i);
	str = var + "=" + val;
	// TODO change strdup for something with new
	return ( strdup(str.c_str()) );
}

char**	Webserv::_set_env(Client *client)
{
	char**	env = new char*[19];

	env[0]  = _dup_env("AUTH_TYPE");		// authentification not supported
	env[1]  = _dup_env("CONTENT_LENGTH"		, client->get_rq_body().size());
	env[2]  = _dup_env("CONTENT_TYPE"		, client->get_rq_headers("Content-Type"));
	env[3]  = _dup_env("GATEWAY_INTERFACE"	, "CGI/1.1"); // https://www.rfc-editor.org/rfc/rfc3875
	env[4]  = _dup_env("PATH_INFO"			, client->get_rq_script_info());
	env[5]  = _dup_env("PATH_TRANSLATED");	// not supported
	env[6]  = _dup_env("QUERY_STRING"		, client->get_rq_query());
	env[7]  = _dup_env("REMOTE_ADDR"		, client->get_cl_ip());
	env[8]  = _dup_env("REMOTE_HOST"		, client->get_rq_headers("Host")); // just test
	env[9]  = _dup_env("REMOTE_IDENT");		// authentification not supported
	env[10] = _dup_env("REMOTE_USER");		// authentification not supported
	env[11] = _dup_env("REQUEST_METHOD"		, client->get_rq_method_str());
	env[12] = _dup_env("SCRIPT_NAME"		, client->get_rq_script_path());
	env[13] = _dup_env("SERVER_NAME"		, client->get_rq_hostname());
	env[14] = _dup_env("SERVER_PORT"		, client->get_rq_port());
	env[15] = _dup_env("SERVER_PROTOCOL"	, client->get_rq_version());
	env[16] = _dup_env("SERVER_SOFTWARE"	, "webser/1.0");
	env[17] = _dup_env("REDIRECT_STATUS"	, "200");
	env[18] = NULL;

	return env;
}

std::string	Webserv::_exec_script(Client *client, char **env)
{
	#define RD 0
	#define WR 1
	#define CGI_BUF_SIZE 10
	#define FD_WR_TO_CHLD fd_in[WR]
	#define FD_WR_TO_PRNT fd_out[WR]
	#define FD_RD_FR_CHLD fd_out[RD]
	#define FD_RD_FR_PRNT fd_in[RD]

	pid_t			pid;
	char			buf[CGI_BUF_SIZE]; // WIP define buffer
	char * const *	nll = NULL;
	std::string		script_output;
	std::string		body = client->get_rq_body();
	int				fd_in[2];
	int				fd_out[2];

	pipe(fd_in);
	pipe(fd_out);

	pid = fork();
	if (pid == -1)
		std::cerr << "fork crashed" << std::endl;
	else if (pid == 0)
	{   
		close(FD_WR_TO_CHLD);
		close(FD_RD_FR_CHLD);
		dup2(FD_RD_FR_PRNT, STDIN_FILENO);
		dup2(FD_WR_TO_PRNT, STDOUT_FILENO);
		// DEBUG
		std::cerr << "execve:\n";
		execve(client->get_rq_script_path().c_str(), nll, env);
		// for tests execve crash :
		//execve("wrong", nll, env);
		std::cerr << "execve crashed.\n";
	}
	else
	{
		close(FD_RD_FR_PRNT);
		close(FD_WR_TO_PRNT);
		write(FD_WR_TO_CHLD, body.c_str(), body.size());
		close(FD_WR_TO_CHLD);
		waitpid(-1, NULL, 0);

		memset(buf, '\0', CGI_BUF_SIZE);
		while (read(FD_RD_FR_CHLD, buf, CGI_BUF_SIZE - 1) > 0)
		{
			script_output += buf;
			memset(buf, '\0', CGI_BUF_SIZE);
		}
		close(FD_RD_FR_CHLD);
	}
	if (script_output.empty())
		script_output = "Status: 500\r\n\r\n";
	return script_output;
}

void	Webserv::_check_script_output(Client *client, std::string output)
{
	// TODO: it doesn't work with execve error, i don't know why yet ?
	_check_script_status(client, output);
	_check_script_fields(client, output);
}

void	Webserv::_check_script_status(Client *client, std::string output)
{
	size_t	pos;
	int		status_pos;

	pos = output.find("Status:");
	if (pos != std::string::npos)
	{
		status_pos = pos + std::string("Status:").size();
		client->status = atoi(output.c_str() + status_pos);
		::del_line_in_str(&output, pos, CRLF);
	}
	client->status = 200;
}

void	Webserv::_check_script_fields(Client *client, std::string output)
{
	std::map<std::string, std::string>				srv_fld;	// server_field
	std::map<std::string, std::string>				scr_fld;	// script_field
	std::map<std::string, std::string>::iterator	it_srv;
	std::map<std::string, std::string>::iterator	it_scr;
	size_t											pos;

	srv_fld = parse_http_headers(client->response);
	scr_fld = parse_http_headers(output);
	// wip: compare both map to supress duplicates
	for (it_srv = srv_fld.begin(); it_srv != srv_fld.end(); it_srv++)
	{
		for (it_scr = scr_fld.begin(); it_scr != scr_fld.end(); it_scr++)
		{
			if (it_srv->first == it_scr->first)
			{
				pos = client->response.find(it_srv->first);
				::del_line_in_str(&client->response, pos, CRLF);
			}
		}
	}
}

