#include "htlib2.h"
#include "HtLib_.h"
#include "Header.h"
#include "Sender.h"
#include "Receiver.h"
#include "Date.h"

HTLIB_BOOL
HTLIB_Init(HTLIB* o,
		   char* send_buffer, HTLIB_USHORT send_len,
		   char* rec_buffer, HTLIB_USHORT rec_len,
		   HTLIB_ERROR* err)
{
	return M(HTLIB,Init)(o,
						 send_buffer, send_len,
						 rec_buffer, rec_len,
						 err);
}

void
HTLIB_Uninit(HTLIB* o)
{
	M(HTLIB,Uninit)(o);
}

HTLIB_BOOL
HTLIB_Open(HTLIB_HANDLE o,
		   const struct sockaddr* addr,
		   socklen_t addr_len,
		   HTLIB_ERROR* err)
{
	return M(HTLIB,Open)(o, addr, addr_len, err);
}

void
HTLIB_Attach(HTLIB_HANDLE o, int socket)
{
	M(HTLIB,Attach)(o, socket);
}

void
HTLIB_Close(HTLIB_HANDLE o)
{
	M(HTLIB,Close)(o);
}


HTLIB_BOOL
HTLIB_SendRequest(HTLIB* o,
				  int timeout_millis,
				  const char* method,
				  const char* url,
				  const HTLIB_Header* headers,
				  HTLIB_USHORT header_len,
				  const char* body,
				  HTLIB_ULONGLONG body_len,
				  HTLIB_ERROR* err)
{
	LOGINFO("SendRequest(%d, %s, %s)\n", timeout_millis, method, url);
	LOGDBG("SendRequest:body=\n%.*s\n", body_len, body);

	if (M(Sender,SendRequest)(o,
							  timeout_millis,
							  method, url,
							  headers, header_len,
							  body, body_len,
							  err)==FALSE) {
		if (*err != HTLIB_E_SYSTEM) {
			return FALSE;
		}
		if ((strcmp(method, "GET")!=0 &&
			 strcmp(method, "HEAD")!=0 &&
			 strcmp(method, "PUT")!=0 &&
			 strcmp(method, "DELETE")!=0)) {
			return FALSE;
		}
		if (errno!=EPIPE && errno!=ENOTCONN) {
			return FALSE;
		}

		/* retry */
		LOGINFO("re-trying because of disconnection by server\n");
		M(Sender,Close)(o);
		if (M(Sender,SendRequest)(o,
								  timeout_millis,
								  method, url,
								  headers, header_len,
								  body, body_len,
								  err)==FALSE) {
			LOGERR("re-tried, but failed again err=%d\n", *err);
			return FALSE;
		}
	}
	return TRUE;
}
HTLIB_BOOL
HTLIB_SendResponse(HTLIB_HANDLE o,
				   int timeout_millis,
				   int status, const char* msg,
				  const HTLIB_Header* headers,
				  HTLIB_USHORT header_len,
				  const char* body,
				  HTLIB_ULONGLONG body_len,
				  HTLIB_ERROR* err)
{
	LOGINFO("SendResponse(%d, %d, %s)\n", timeout_millis, status, msg);
	LOGDBG("SendResponse:body=\n%.*s\n", body_len, body);

	if (M(Sender,SendResponse)(o,
							   timeout_millis,
							   status, msg,
							   headers, header_len,
							   body, body_len,
							   err)==FALSE) {
		return FALSE;
	}
	return TRUE;
}

HTLIB_BOOL
HTLIB_SendBody(HTLIB_HANDLE o,
			   int timeout_millis,
			   const char* body,
			   HTLIB_USHORT body_len,
			   HTLIB_ERROR* err)
{
	LOGDBG("SendBody(%d, %d)\n", timeout_millis, body_len);
	return M(Sender,SendBody)(o, timeout_millis, body, body_len, err);
}

const char*
HTLIB_ReceiveRequest(HTLIB_HANDLE o,
					 int timeout_millis,
					 const char** method,
					 HTLIB_Header* header_buffer, HTLIB_USHORT* blen,
					 HTLIB_NEEDS_FUNC needs,
					 HTLIB_ERROR* err)
{
	LOGINFO("ReceiveRequest(%d,%d)\n", timeout_millis, *blen);
	const char* url = NULL;
	url = M(Receiver,ReceiveRequest)(o, timeout_millis,
									 method,
									 header_buffer, blen,
									 needs,
									 err);
	LOGINFO("ReceiveRequest returns %s, %s\n", *method, url);
	return url;
}

int
HTLIB_ReceiveResponse(HTLIB* o,
					  int timeout_millis,
					  HTLIB_Header* header_buffer, HTLIB_USHORT* blen,
					  HTLIB_NEEDS_FUNC needs,
					  HTLIB_ERROR* err)
{
	int ret;
	
	LOGINFO("ReceiveResponse(%d, %d)\n",
			timeout_millis, *blen);
	
	ret = M(Receiver,ReceiveResponse)(o, timeout_millis,
									 header_buffer, blen,
									 needs,
									 err);
	LOGINFO("ReceiveResponse returns status:%d blen=%d err=%d\n",
			ret, *blen, *err);

	return ret;
}

int
HTLIB_Find(const HTLIB_Header* header_or_param, USHORT len, const char* name)
{
	return M(Header,Find)(header_or_param, len, name);
}


int
HTLIB_ReceiveBody(HTLIB* o,
				  int timeout_millis,
				  char* buffer,
				  USHORT buffer_len,
				  HTLIB_ERROR* err)
{
	int ret;
	
	LOGDBG("ReceiveBody(%d, %d)\n", timeout_millis, buffer_len);
	ret = M(Receiver,ReceiveBody)(o, timeout_millis,
								  buffer, buffer_len, err);
	LOGDBG("ReceiveBody returns %d bytes (%.10s...) err=%d\n",
		   ret, buffer, *err);
	
	return ret;
}

void
HTLIB_Cancel(HTLIB* o, HTLIB_BOOL trueIfCancel)
{
	M(HTLIB, Cancel)(o, trueIfCancel);
}
void
HTLIB_CancelAll(HTLIB_BOOL cancel_or_not)
{
	M(HTLIB, CancelAll)(cancel_or_not);
}

void
HTLIB_SetLogHandler(HTLIB_LOG_HANDLER handler)
{
	G(SetLogHandler)(handler);
}
void
HTLIB_SetLogLevel(HTLIB_LOGLEVEL levelAndHigher)
{
	G(SetLogLevel)(levelAndHigher);
}

const char*
HTLIB_GetErrorMessage(HTLIB_ERROR err)
{
	return G(GetErrorMessage)(err);
}

void
HTLIB_SetDate(char* buf30, const time_t* tm)
{
	M(Date,Set)(buf30, tm);
}
