/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "array.h"
#include "seq-range-array.h"
#include "mail-search.h"
#include "mailbox-search-result-private.h"
#include "index-search-result.h"
#include "index-sync-private.h"

static bool
search_result_want_flag_updates(const struct mail_search_result *result)
{
	if (!result->args_have_flags && !result->args_have_keywords &&
	    !result->args_have_modseq) {
		/* search result doesn't care about flag changes */
		return FALSE;
	}
	return TRUE;
}

static void index_sync_uidify_array(struct index_mailbox_sync_context *ctx,
				    const ARRAY_TYPE(seq_range) *changes)
{
	const struct seq_range *range;
	uint32_t seq, uid;

	array_foreach(changes, range) {
		for (seq = range->seq1; seq <= range->seq2; seq++) {
			mail_index_lookup_uid(ctx->ctx.box->view, seq, &uid);
			seq_range_array_add(&ctx->all_flag_update_uids, uid);
		}
	}
}

static void index_sync_uidify(struct index_mailbox_sync_context *ctx)
{
	unsigned int count;

	count = array_count(&ctx->flag_updates) +
		array_count(&ctx->hidden_updates);
	i_array_init(&ctx->all_flag_update_uids, count*2);

	index_sync_uidify_array(ctx, &ctx->flag_updates);
	index_sync_uidify_array(ctx, &ctx->hidden_updates);
}

void index_sync_search_results_uidify(struct index_mailbox_sync_context *ctx)
{
	struct mail_search_result *const *results;
	unsigned int i, count;

	i_assert(!array_is_created(&ctx->all_flag_update_uids));

	results = array_get(&ctx->ctx.box->search_results, &count);
	for (i = 0; i < count; i++) {
		if ((results[i]->flags & MAILBOX_SEARCH_RESULT_FLAG_UPDATE) != 0 &&
		    search_result_want_flag_updates(results[i])) {
			index_sync_uidify(ctx);
			break;
		}
	}
}

static void
search_result_update(struct index_mailbox_sync_context *ctx,
		     struct mail_search_result *result)
{
	if ((result->flags & MAILBOX_SEARCH_RESULT_FLAG_UPDATE) == 0) {
		/* not an updateable search result */
		return;
	}

	if (search_result_want_flag_updates(result)) {
		(void)index_search_result_update_flags(result,
						&ctx->all_flag_update_uids);
	}
	(void)index_search_result_update_appends(result, ctx->messages_count);
}

void index_sync_search_results_update(struct index_mailbox_sync_context *ctx)
{
	struct mail_search_result *const *results;
	unsigned int i, count;

	results = array_get(&ctx->ctx.box->search_results, &count);
	for (i = 0; i < count; i++)
		search_result_update(ctx, results[i]);
}

void index_sync_search_results_expunge(struct index_mailbox_sync_context *ctx)
{
	if (ctx->expunges != NULL) {
		index_search_results_update_expunges(ctx->ctx.box,
						     ctx->expunges);
	}
}
