#include <stdio.h>
#include <pthread.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include "../htlib.h"

#define FALSE 0
#define TRUE 1

static HTLIB_NEEDS_ENUM
needs(HTLIB_HANDLE o, const char* header_name)
{
	if (strcasecmp(header_name, "Server")==0) {
		return HTLIB_N_NONE;
	}
	if (strcasecmp(header_name, "Date")==0) {
		return HTLIB_N_NONE;
	}
	if (strcasecmp(header_name, "X-Data1")==0) {
		return HTLIB_N_ONLY_VALUE;
	}
	return HTLIB_N_PARSE_PARAM;
}

static const char* prog;
static const char* method = "GET";
static const char* c_body = NULL;

static FILE* output = NULL;

typedef struct {
	int hlen;
	HTLIB_Header headers[];
} ReqHeader;

const ReqHeader header_default = {
	0,
	{
		{ NULL, NULL, 0, NULL },
	}
};
const ReqHeader header_close = {
	1,
	{
		{ "Connection", "close", 0, NULL },
	}
};
const ReqHeader header_post = {
	2,
	{
		{ "Content-Type", "text/plain", 0, NULL },
		{ "Expect", "100-continue", 0, NULL },
	}
};

static int
doHttp(HTLIB_HANDLE h, const char* url, HTLIB_ERROR* err)
{
	const ReqHeader* rh = &header_default;

	if (strcmp(method, "POST")==0 && c_body!=NULL) {
		rh = &header_post;
	}
	if (HTLIB_SendRequest(h, -1, method, url,
						  rh->headers, rh->hlen,
						  NULL, c_body!=NULL? strlen(c_body): 0,
						  err)==FALSE) {
		fprintf(stderr, "HTLIB_SendRequest failed err=%d:%s\n",
				*err, HTLIB_GetErrorMessage(*err));
		return 3;
	}
	
	int status;
	HTLIB_Header headers[30];
	HTLIB_USHORT blen = 30;

	if (rh == &header_post) {
		/* with Expect: 100-continue */
		if ((status=HTLIB_ReceiveResponse(h, 100 /* a little time */,
										  headers, &blen,
										  needs,
										  err))!=100) {
			fprintf(stderr, "expected 100, but %d (err=%d)\n", status, *err);
			return 31;
		}
		if (HTLIB_SendBody(h, -1, c_body, strlen(c_body), err)==FALSE) {
			fprintf(stderr, "HTLIB_SendBody failed err=%d\n", *err);
			return 32;
		}
	}

	blen = 30;
	while ((status=HTLIB_ReceiveResponse(h, 1000,
										 headers, &blen,
										 needs,
										 err))==-1) {
		fprintf(stderr,
				"HTLIB_ReceiveResponse failed status=%d err=%d:%s\n",
				status, *err, HTLIB_GetErrorMessage(*err));
		return 4;
	}

	if (*err != HTLIB_E_NO_ERROR) {
		fprintf(stderr, "warning: ReceiveResponse err=%d:%s\n",
				*err, HTLIB_GetErrorMessage(*err));
	}

	int i;
	for (i=0; i<blen; i++) {
		printf("[%s: %s]\n", headers[i].name, headers[i].value);
		if (headers[i].param != NULL) {
			const HTLIB_Header* param = headers[i].param;
			int j;
			for (j=0; j<headers[i].param_num; j++) {
				if (param[j].value != NULL) {
					printf("  [%s=%s]\n", param[j].name, param[j].value);
				} else {
					printf("  [%s(no value)]\n", param[j].name);
				}
			}
		}
	}

	int len;
	long long total = 0;
	char body[1000];
	while ((len=HTLIB_ReceiveBody(h, 1000, body, sizeof(body), err))>0) {
		if (fwrite(body, len, 1, output)!=1) {
			perror("fwrite");
		}
		total += len;
	}
	fprintf(stderr, "total %lld bytes written\n", total);
	return 0;
}

int
main(int argc, char* argv[])
{
	const char* user_agent = NULL;
	output = stdout;

	prog = argv[0];

	if (argv[1] != NULL && strcmp(argv[1], "--debug")==0) {
		HTLIB_SetLogLevel(HTLIB_LV_DEBUG);
		argv++;
		argc--;
	}
	if (argv[1] != NULL && strncmp(argv[1], "--post-data=", 12)==0) {
		method = "POST";
		c_body = argv[1]+12;
		argv++;
		argc--;
	}
	if (argv[1] != NULL && strcmp(argv[1], "--head")==0) {
		method = "HEAD";
		argv++;
		argc--;
	}
	if (argv[1] != NULL && strncmp(argv[1], "--output=", 9)==0) {
		output = fopen(argv[1]+9, "wb");
		if (output == NULL) {
			perror("fopen");
			return 1;
		}
		argv++;
		argc--;
	}
	if (argv[1] != NULL && strncmp(argv[1], "--user-agent=", 13)==0) {
		user_agent = argv[1]+13;
		argv++;
		argc--;
	}
	if (argc<2) {
		fprintf(stderr,
				"Usage: %s [options] <url to get>\n"
				"  options:\n"
				"    --debug\n"
				"    --post-data='data to post'\n"
				"    --head\n"
				"    --output=<file>\n"
				"    --user-agent=<agent name>\n", prog);
		return 1;
	}
	
	HTLIB ht;
	HTLIB_HANDLE h = &ht;
	HTLIB_ERROR err;

	char send_buffer[1024];
	char rec_buffer[1024];
	
	if (HTLIB_Init(h,
				   send_buffer, sizeof(send_buffer),
				   rec_buffer, sizeof(rec_buffer),
				   &err)==FALSE) {
		fprintf(stderr, "HTLIB_Init failed err=%d:%s\n",
				err, HTLIB_GetErrorMessage(err));
		return 2;
	}

	h->agent_or_server_name = user_agent;
	
	if (doHttp(h, argv[1], &err)!=0) {
		fprintf(stderr, "doHttp failed err=%d:%s\n",
				err, HTLIB_GetErrorMessage(err));
	}
#if 0
	if (doHttp(h, argv[1], &err)!=0) {
		fprintf(stderr, "doHttp failed err=%d:%s\n",
				err, HTLIB_GetErrorMessage(err));
	}
#endif
	
	HTLIB_Uninit(h);
	if (output != stdout) {
		fclose(output);
	}
	return 0;
}
