#include "Url.h"
#include "Network.h"
#include <stdio.h>


#ifdef UNIX
#   include <sys/types.h>
#   include <sys/socket.h>
#   include <netinet/in.h>
#   include <netdb.h> 
#else
#   include <winsock2.h>
	struct InitWS {
		InitWS() { WSADATA wsaData; WSAStartup(MAKEWORD(2,2), &wsaData); }
		~InitWS() { WSACleanup(); }
	} g_initWinSock;
#endif


BEGIN_NAMESPACE


static void error(const char *msg)
{
    perror(msg);
    exit(0);
}


static void check(bool cond, const char *msg)
{
	if (!cond)
		error(msg);
}


Socket::Socket()
{
    m_sockfd = (SocketId)socket(AF_INET, SOCK_STREAM, 0);
    check(m_sockfd >= 0, "ERROR opening socket");
}


Socket::~Socket()
{
	closesocket((SOCKET)m_sockfd);
}


bool Socket::connect(const String& a_hostName, int a_port)
{
    struct hostent *server = gethostbyname(a_hostName.data());
	check(server != NULL, "ERROR looking up ip of server");
    if (server == NULL)
		return false;
    struct sockaddr_in serv_addr = {};
    serv_addr.sin_family = AF_INET;
    memcpy((char *)&serv_addr.sin_addr.s_addr, (char *)server->h_addr, server->h_length);
	serv_addr.sin_port = htons(a_port);
	int n = ::connect(m_sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
	check(n >= 0, "ERROR connecting socket to host");
	return (n >= 0);
}


int Socket::send(const String& a_string)
{
    int n = ::send(m_sockfd, a_string.data(), (int)a_string.toUtf8().size(), 0);
	check(n >= 0, "ERROR writing to socket");
	return n;
}


String Socket::receive(int a_length)
{
	int totalRecv = 0, n = 1;
	std::string response;
	while (n > 0)
	{
		char buffer[1025];
		n = ::recv(m_sockfd, buffer, (a_length > totalRecv) ? (a_length - totalRecv) : 1024, 0);
		if (n > 0)
		{
			buffer[n] = 0;
			response += buffer;
			totalRecv += n;
		}
		if (a_length >= 0 && totalRecv >= a_length)
			break;
	}
	check(n >= 0, "ERROR reading from socket");

	return response;
}


String Socket::receiveAll()
{
	return receive(-1);
}


HttpRequest::HttpRequest(const Url& a_url, HttpMethod a_method)
{
	switch (a_method)
	{
		case HM_PUT: m_request = "PUT"; break;
		case HM_POST: m_request = "POST"; break;
		default:
		case HM_GET: m_request = "GET"; break;
	}
	m_request += " " + a_url.path().toUtf8() + " HTTP/1.1\r\n";
	setHeader("Host", a_url.hostName());
	setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.65 Safari/537.36");
}


HttpRequest::~HttpRequest()
{
}


void HttpRequest::setHeader(String a_field, String a_value)
{
	m_headers[a_field] = a_value;
}


String HttpRequest::data()
{
	String request = m_request;
	for (std::map<String, String>::iterator it = m_headers.begin(); it != m_headers.end(); it++)
		request += it->first + ": " + it->second + "\r\n";
	return request + "\r\n";
}


String Network::wget(const String& a_url)
{
	Socket sock;
	Url url(a_url);
	HttpRequest request(url);
	sock.connect(url.hostName(), url.port());
	printf("HTTP request:\n--%s--\n", request.data().data());
	sock.send(request.data());
	return sock.receiveAll();
	//return String(tiny_wget(url.hostName(), url.port(), url.path()));
}


#if 0

/*
	Could this be turned in to a tiny_wget exe to sell with other
	tiny versions of UNIX tools for windows users??????????
*/
static std::string tiny_wget(const char* hostname, int portno, const char* url)
{
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    check(sockfd >= 0, "ERROR opening socket");

    struct hostent *server = gethostbyname(hostname);
    check(server != NULL, "ERROR no such host");

    struct sockaddr_in serv_addr = {};
    serv_addr.sin_family = AF_INET;
    memcpy((char *)&serv_addr.sin_addr.s_addr, (char *)server->h_addr, server->h_length);
	serv_addr.sin_port = htons(portno);
	int connectRet = connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
	check(connectRet >= 0, "ERROR connecting");

	std::string request = "GET " + std::string(url) + " HTTP/1.1\r\n";
	request += "Host: " + std::string(hostname) + "\r\n";
	request += "User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.65 Safari/537.36\r\n";
	//request += "Referer: http://www.investing.com/charts/forex-charts\r\n";
	request += "\r\n";
	
    int n = send(sockfd,request.c_str(),request.size(),0);
	check(n >= 0, "ERROR writing to socket");

	std::string response;
	while (n > 0)
	{
		char buffer[1024];
		n = recv(sockfd, buffer, 1024, 0);
		if (n > 0)
		{
			buffer[n] = 0;
			response += buffer;
		}
	}
	check(n >= 0, "ERROR reading from socket");

    //printf("Got response of:  --%s---\n",response.c_str());
	
    return response;
}


#endif


END_NAMESPACE

