/* SylFilter - a message filter
 *
 * Copyright (C) 2011 Hiroyuki Yamamoto
 * Copyright (C) 2011 Sylpheed Development Team
 */

#include <depot.h>
#include <stdlib.h>

#include "filter-kvs.h"
#include "filter-kvs-qdbm.h"

static XFilterKVS *qdbm_open(const char *dbfile);
static int qdbm_close(XFilterKVS *kvs);
static int qdbm_insert(XFilterKVS *kvs, const char *key, void *value, int size);
static int qdbm_delete(XFilterKVS *kvs, const char *key);
static int qdbm_update(XFilterKVS *kvs, const char *key, void *value, int size);
static int qdbm_fetch(XFilterKVS *kvs, const char *key, void *vbuf, int vsize);
static int qdbm_size(XFilterKVS *kvs);
static int qdbm_foreach(XFilterKVS *kvs, XFilterKVSForeachFunc func, void *data);


int xfilter_kvs_qdbm_set_engine(void)
{
	XFilterKVSEngine engine = {
		qdbm_open,
		qdbm_close,
		qdbm_insert,
		qdbm_delete,
		qdbm_update,
		qdbm_fetch,
		qdbm_size,
		qdbm_foreach
	};

	return xfilter_kvs_set_engine(&engine);
}

static XFilterKVS *qdbm_open(const char *dbfile)
{
	DEPOT *depot;

	depot = dpopen(dbfile, DP_OREADER|DP_OWRITER|DP_OCREAT, 0);
	if (!depot)
		return NULL;
	return xfilter_kvs_new(dbfile, (void *)depot);
}

static int qdbm_close(XFilterKVS *kvs)
{
	if (!dpclose((DEPOT *)xfilter_kvs_get_handle(kvs)))
		return -1;
	return 0;
}

static int qdbm_insert(XFilterKVS *kvs, const char *key, void *value, int size)
{
	DEPOT *depot;

	depot = (DEPOT *)xfilter_kvs_get_handle(kvs);
	if (!dpput(depot, key, -1, (const char *)value, size, DP_DKEEP))
		return -1;
	return 0;
}

static int qdbm_delete(XFilterKVS *kvs, const char *key)
{
	DEPOT *depot;

	depot = (DEPOT *)xfilter_kvs_get_handle(kvs);
	if (!dpout(depot, key, -1))
		return -1;

	return 0;
}

static int qdbm_update(XFilterKVS *kvs, const char *key, void *value, int size)
{
	DEPOT *depot;

	depot = (DEPOT *)xfilter_kvs_get_handle(kvs);
	if (!dpput(depot, key, -1, (const char *)value, size, DP_DOVER))
		return -1;

	return 0;
}

static int qdbm_fetch(XFilterKVS *kvs, const char *key, void *vbuf, int vsize)
{
	DEPOT *depot;
	int size;

	depot = (DEPOT *)xfilter_kvs_get_handle(kvs);
	size = dpgetwb(depot, key, -1, 0, vsize, (char *)vbuf);
	if (size < 0)
		return -1;

	return size;
}

static int qdbm_size(XFilterKVS *kvs)
{
	DEPOT *depot;

	depot = (DEPOT *)xfilter_kvs_get_handle(kvs);
	return dprnum(depot);
}

static int qdbm_foreach(XFilterKVS *kvs, XFilterKVSForeachFunc func, void *data)
{
	DEPOT *depot;
	char *key;
	int ks;
	int size;
	char vbuf[1024];

	depot = (DEPOT *)xfilter_kvs_get_handle(kvs);
	if (!dpiterinit(depot))
		return -1;
	while ((key = dpiternext(depot, &ks)) != NULL) {
		int r;

		size = dpgetwb(depot, key, ks, 0, sizeof(vbuf), vbuf);
		if (size < 0) {
			free(key);
			break;
		}
		r = func(kvs, key, vbuf, size, data);
		free(key);
		if (r < 0)
			break;
	}

	return 0;
}
