/*
	Copyright (c) 2010 by Dennis Schridde

	This file is part of dovecot-metadata.

	dovecot-metadata is free software: you can redistribute it and/or modify
	it under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	dovecot-metadata is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with dovecot-metadata.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "dict-ext.h"

#include "str.h"
#include "dict.h"

enum dict_scope
dict_get_scope(const char *path) {
	if (strncasecmp(DICT_PATH_SHARED, path, sizeof(DICT_PATH_SHARED)) == 0)
		return DICT_SCOPE_SHARED;
	else if (strncasecmp(DICT_PATH_PRIVATE, path, sizeof(DICT_PATH_PRIVATE)) == 0)
		return DICT_SCOPE_PRIVATE;

	return DICT_SCOPE_INVALID;
}

const char *
dict_path_from_scope(enum dict_scope scope) {
	switch (scope) {
		case DICT_SCOPE_SHARED:
			return DICT_PATH_SHARED;
		case DICT_SCOPE_PRIVATE:
			return DICT_PATH_PRIVATE;
		case DICT_SCOPE_INVALID:
			return "";
	}

	return "";
}

struct dict_iterate_multiscope_context {
	struct dict_iterate_context *dict_ctx;
	struct dict *dict;
	enum dict_iterate_flags flags;
	string_t *path;
	bool do_shared;
	bool failed;
};

struct dict_iterate_multiscope_context *
dict_iterate_multiscope_init(struct dict *dict, const char *path, enum dict_iterate_multiscope_flags flags) {
	struct dict_iterate_multiscope_context *ctx = i_new(struct dict_iterate_multiscope_context, 1);
	memset(ctx, 0, sizeof(*ctx));

	ctx->dict = dict;
	ctx->flags = flags & ~DICT_ITERATE_MULTISCOPE_FLAG_MULTISCOPE;

	ctx->path = str_new(default_pool, 128);
	if (flags & DICT_ITERATE_MULTISCOPE_FLAG_MULTISCOPE)
		str_append(ctx->path, DICT_PATH_PRIVATE);
	str_append(ctx->path, path);

	ctx->do_shared = (flags & DICT_ITERATE_MULTISCOPE_FLAG_MULTISCOPE);
	ctx->failed = false;

	ctx->dict_ctx = dict_iterate_init(ctx->dict, str_c(ctx->path), ctx->flags);

	return ctx;
}

bool
dict_iterate_multiscope(struct dict_iterate_multiscope_context *ctx, const char **name, const char **value) {
	i_assert(ctx != NULL);
	if (ctx == NULL)
		return false;

	if (ctx->failed)
		return false;

	*name = NULL;
	while (*name == NULL) {
		bool ret = dict_iterate(ctx->dict_ctx, name, value);

		/* we have no more shared/ keys and priv/ was also already iterated over */
		if (!ret && !ctx->do_shared) {
			return false;
		}
		/* no more priv/ keys, continue with shared/ */
		else if (!ret && ctx->do_shared) {
			if (dict_iterate_deinit(&ctx->dict_ctx) < 0) {
				ctx->failed = true;
				return false;
			}

			/* replace priv/ with shared/ */
			str_delete(ctx->path, 0, sizeof(DICT_PATH_SHARED));
			str_insert(ctx->path, 0, DICT_PATH_PRIVATE);

			ctx->do_shared = false;

			ctx->dict_ctx = dict_iterate_init(ctx->dict, str_c(ctx->path), ctx->flags);
			if (ctx->dict_ctx == NULL) {
				ctx->failed = true;
			}

			continue;
		}
	}

	return true;
}

int
dict_iterate_multiscope_deinit(struct dict_iterate_multiscope_context **ctx) {
	i_assert(ctx != NULL);
	if (ctx == NULL)
		return -1;

	i_assert(*ctx != NULL);
	if (*ctx == NULL)
		return -1;

	int ret = (*ctx)->failed ? -1 : 0;

	if (dict_iterate_deinit(&(*ctx)->dict_ctx) < 0)
		ret = -1;

	str_free(&(*ctx)->path);
	i_free(*ctx);

	return ret;
}
