#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "libubox/uhtbl.h"
#include "libubox/hash.h"
#include "zhttpd.h"
#include "env.h"

static void zhttpd_env_gc(uhtbl_bucket_t *bucket) {
	zhttpd_env_bucket_t *env = (zhttpd_env_bucket_t*)bucket;
	free(env->value);
	uhtbl_gc_key(bucket);
}

int zhttpd_env_init(uhtbl_t *tbl, uint32_t sizehint) {
	return uhtbl_init(tbl, sizeof(zhttpd_env_bucket_t), sizehint,
			hash_murmur2_neutral, zhttpd_env_gc);
}

unsigned int zhttpd_env_count(uhtbl_t *tbl) {
	return tbl->used;
}

char* zhttpd_env_next(uhtbl_t *tbl, uint32_t *iter, const char **key) {
	zhttpd_env_bucket_t *bucket = (zhttpd_env_bucket_t*)uhtbl_next(tbl, iter);
	if (bucket) {
		uhtbl_key((uhtbl_bucket_t*)bucket, (void**)key, NULL);
		return bucket->value;
	} else {
		return NULL;
	}
}

char* zhttpd_env_get(uhtbl_t *tbl, const char *key) {
	zhttpd_env_bucket_t *bucket =
			(zhttpd_env_bucket_t*)uhtbl_get(tbl, key, strlen(key));
	return (bucket) ? bucket->value : NULL;
}

int zhttpd_env_set
(uhtbl_t *tbl, const char *key, const char *value, size_t len) {
	void *ekey = NULL;
	char *evalue = NULL;
	zhttpd_env_bucket_t *bucket;

	if (!(ekey = strdup(key)) || !(evalue = malloc(len + 1))
	|| !(bucket = (zhttpd_env_bucket_t*)uhtbl_set(tbl, ekey, strlen(ekey)))) {
		free(ekey);
		free(evalue);
		return ZHTTPD_ENOMEM;
	}
	((char*)memcpy(evalue, value, len))[len] = 0;
	bucket->value = evalue;

	return ZHTTPD_OK;
}

void zhttpd_env_clear_custom(uhtbl_t *tbl) {
	uint32_t iter = 0;
	uhtbl_bucket_t *bucket;
	while ((bucket = uhtbl_next(tbl, &iter))) {
		void *key;
		long len;
		uhtbl_key(bucket, &key, &len);
		if (!strncmp((char*)key, "HTTP_", 5)) {
			uhtbl_unset(tbl, key, len);
		}
	}
}

int zhttpd_env_set_int(uhtbl_t *tbl, const char *key, long long value) {
	char buf[32];
	return zhttpd_env_set(tbl, key, buf, snprintf(buf, 32, "%lli", value));
}

int zhttpd_env_unset(uhtbl_t *tbl, const char *key) {
	return uhtbl_unset(tbl, (const void*)key, strlen(key));
}
