#include "watcomfx.h"

#include "nsres.h"

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

struct RESDATABASE
{
	DB *hdb;
	NSRESTHREADINFO *threadinfo;
	char * pbuf[MAXBUFNUM];
} ;
typedef struct RESDATABASE *  RESHANDLE;

typedef struct STRINGDATA
{
	char *str;
	unsigned int charsetid;
} STRINGDATA;


typedef unsigned int CHARSETTYPE;
#define RES_LOCK	if (hres->threadinfo)   hres->threadinfo->fn_lock(hres->threadinfo->lock);
#define RES_UNLOCK  if (hres->threadinfo)   hres->threadinfo->fn_unlock(hres->threadinfo->lock);

int GenKeyData(const char *library, int32 id, DBT *key);

/* 
  Right now, the page size used for resource is same as for Navigator cache
  database
 */
HASHINFO res_hash_info = {
        32*1024,
        0,
        0,
        0,
        0,   /* 64 * 1024U  */
        0};

int GenKeyData(const char *library, int32 id, DBT *key)
{
	char idstr[10];
	static char * strdata = NULL;
	size_t len;

	if (strdata)
		free (strdata);

	if (id == 0)
		idstr[0] = '\0';
	else
	{
		sprintf(idstr, "%d", id);
		/*	itoa(id, idstr, 10);  */
	}

	if (library == NULL)
		len = strlen(idstr) + 1;
	else
		len = strlen(library) + strlen(idstr) + 1;
	strdata = (char *) malloc (len);
	strcpy(strdata, library);
	strcat(strdata, idstr);

	key->size = len;
	key->data = strdata;

	return 1;
}

NSRESHANDLE NSResCreateTable(const char *filename, NSRESTHREADINFO *threadinfo)
{
	RESHANDLE hres;
	int flag;

	flag = O_RDWR | O_CREAT;

	hres = (RESHANDLE) calloc ( 1, sizeof(struct RESDATABASE) );

	if (threadinfo && threadinfo->lock && threadinfo->fn_lock 
	  && threadinfo->fn_unlock)
	{
		hres->threadinfo = (NSRESTHREADINFO *) malloc( sizeof(NSRESTHREADINFO) );
		hres->threadinfo->lock = threadinfo->lock;
		hres->threadinfo->fn_lock = threadinfo->fn_lock;
		hres->threadinfo->fn_unlock = threadinfo->fn_unlock;
	}


	RES_LOCK

	hres->hdb = dbopen(filename, flag, 0644, DB_HASH, &res_hash_info);

	RES_UNLOCK

	if(!hres->hdb)
		return NULL;

	return (NSRESHANDLE) hres;
}

NSRESHANDLE NSResOpenTable(const char *filename, NSRESTHREADINFO *threadinfo)
{
	RESHANDLE hres;
	int flag;

	flag = O_RDONLY;  /* only open database for reading */

	hres = (RESHANDLE) calloc ( 1, sizeof(struct RESDATABASE) );

	if (threadinfo && threadinfo->lock && threadinfo->fn_lock 
	  && threadinfo->fn_unlock)
	{
		hres->threadinfo = (NSRESTHREADINFO *) malloc( sizeof(NSRESTHREADINFO) );
		hres->threadinfo->lock = threadinfo->lock;
		hres->threadinfo->fn_lock = threadinfo->fn_lock;
		hres->threadinfo->fn_unlock = threadinfo->fn_unlock;
	}


	RES_LOCK

	hres->hdb = dbopen(filename, flag, 0644, DB_HASH, &res_hash_info);

	RES_UNLOCK

	if(!hres->hdb)
		return NULL;

	return (NSRESHANDLE) hres;
}



void NSResCloseTable(NSRESHANDLE handle)
{
	RESHANDLE hres;
	int i;

	if (handle == NULL)
		return;
	hres = (RESHANDLE) handle;

	RES_LOCK

	(*hres->hdb->sync)(hres->hdb, 0);
	(*hres->hdb->close)(hres->hdb);

	RES_UNLOCK

	for (i = 0; i < MAXBUFNUM; i++)
	{
		if (hres->pbuf[i])
			free (hres->pbuf[i]);
	}

	if (hres->threadinfo)
		free (hres->threadinfo);
	free (hres);
}


char *NSResLoadString(NSRESHANDLE handle, const char * library, int32 id, 
	unsigned int charsetid, char *retbuf)
{
	int status;
	RESHANDLE hres;
	DBT key, data;
	if (handle == NULL)
		return NULL;

	hres = (RESHANDLE) handle;
	GenKeyData(library, id, &key);

	RES_LOCK

	status = (*hres->hdb->get)(hres->hdb, &key, &data, 0);

	RES_UNLOCK

	if (retbuf)
	{
		memcpy(retbuf, (char *)data.data + sizeof(CHARSETTYPE), data.size - sizeof(CHARSETTYPE));
		return retbuf;
	}
	else 
	{
		static int WhichString = 0;
		static int bFirstTime = 1;
		char *szLoadedString;
		int i;

		RES_LOCK

		if (bFirstTime) {
			for (i = 0; i < MAXBUFNUM; i++)
				hres->pbuf[i] = (char *) malloc(MAXSTRINGLEN * sizeof(char));
			bFirstTime = 0; 
		} 

		szLoadedString = hres->pbuf[WhichString];
		WhichString++;

		/* reset to 0, if WhichString reaches to the end */
		if (WhichString == MAXBUFNUM)  
			WhichString = 0;

		if (status == 0)
			memcpy(szLoadedString, (char *) data.data + sizeof(CHARSETTYPE), 
			  data.size - sizeof(CHARSETTYPE));
		else
			szLoadedString[0] = 0; 

		RES_UNLOCK

		return szLoadedString;
	}
}

int32 NSResGetSize(NSRESHANDLE handle, const char *library, int32 id)
{
	int status;
	RESHANDLE hres;
	DBT key, data;
	if (handle == NULL)
		return 0;
	hres = (RESHANDLE) handle;
	GenKeyData(library, id, &key);

	RES_LOCK

	status = (*hres->hdb->get)(hres->hdb, &key, &data, 0);

	RES_UNLOCK

	return data.size - sizeof(CHARSETTYPE);
}

int32 NSResLoadResource(NSRESHANDLE handle, const char *library, int32 id, char *retbuf)
{
	int status;
	RESHANDLE hres;
	DBT key, data;
	if (handle == NULL)
		return 0;
	hres = (RESHANDLE) handle;
	GenKeyData(library, id, &key);

	RES_LOCK

	status = (*hres->hdb->get)(hres->hdb, &key, &data, 0);

	RES_UNLOCK

	if (retbuf)
	{
		memcpy(retbuf, (char *)data.data + sizeof(CHARSETTYPE), data.size - sizeof(CHARSETTYPE));
		return data.size;
	}
	else
		return 0;
}

int NSResAddString(NSRESHANDLE handle, const char *library, int32 id, 
  const char *string, unsigned int charset)
{
	int status;
	RESHANDLE hres;
	DBT key, data;
	char * recdata;

	if (handle == NULL)
		return 0;
	hres = (RESHANDLE) handle;

	GenKeyData(library, id, &key);

	data.size = sizeof(CHARSETTYPE) + (strlen(string) + 1) ;

	recdata = (char *) malloc(data.size) ;

	/* set charset to the first field of record data */
	*((CHARSETTYPE *)recdata) = (CHARSETTYPE)charset;

	/* set data field */
	memcpy(recdata+sizeof(CHARSETTYPE), string, strlen(string) + 1);

	data.data = recdata;

	RES_LOCK

	status = (*hres->hdb->put)(hres->hdb, &key, &data, 0);


	if (recdata)
		free(recdata);

	RES_UNLOCK

	return status;
}
