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

/* Match-type ':count'
 */

#include "lib.h"
#include "str.h"
#include "str-sanitize.h"

#include "sieve-common.h"
#include "sieve-ast.h"
#include "sieve-stringlist.h"
#include "sieve-code.h"
#include "sieve-extensions.h"
#include "sieve-commands.h"
#include "sieve-comparators.h"
#include "sieve-match-types.h"
#include "sieve-validator.h"
#include "sieve-generator.h"
#include "sieve-interpreter.h"
#include "sieve-runtime-trace.h"
#include "sieve-match.h"

#include "ext-relational-common.h"

/*
 * Forward declarations
 */

static int mcht_count_match
	(struct sieve_match_context *mctx, struct sieve_stringlist *value_list,
		struct sieve_stringlist *key_list);

/*
 * Match-type objects
 */

const struct sieve_match_type_def count_match_type = {
	SIEVE_OBJECT("count",
		&rel_match_type_operand, RELATIONAL_COUNT),
	.validate = mcht_relational_validate
};

#define COUNT_MATCH_TYPE(name, rel_match)                      \
const struct sieve_match_type_def rel_match_count_ ## name = { \
	SIEVE_OBJECT("count-" #name,                                 \
    &rel_match_type_operand,                                   \
		REL_MATCH_INDEX(RELATIONAL_COUNT, rel_match)),             \
	.match = mcht_count_match,                                   \
}

COUNT_MATCH_TYPE(gt, REL_MATCH_GREATER);
COUNT_MATCH_TYPE(ge, REL_MATCH_GREATER_EQUAL);
COUNT_MATCH_TYPE(lt, REL_MATCH_LESS);
COUNT_MATCH_TYPE(le, REL_MATCH_LESS_EQUAL);
COUNT_MATCH_TYPE(eq, REL_MATCH_EQUAL);
COUNT_MATCH_TYPE(ne, REL_MATCH_NOT_EQUAL);

/*
 * Match-type implementation
 */

static int mcht_count_match
(struct sieve_match_context *mctx, struct sieve_stringlist *value_list,
	struct sieve_stringlist *key_list)
{
	const struct sieve_runtime_env *renv = mctx->runenv;
	bool trace = sieve_runtime_trace_active(renv, SIEVE_TRLVL_MATCHING);
	int count;
	string_t *key_item;
	int match, ret;

	if ( (count=sieve_stringlist_get_length(value_list)) < 0 ) {
		mctx->exec_status = value_list->exec_status;
		return -1;
	}

	sieve_stringlist_reset(key_list);

	string_t *value = t_str_new(20);
	str_printfa(value, "%d", count);

	if ( trace ) {
		sieve_runtime_trace(renv, 0,
			"matching count value `%s'", str_sanitize(str_c(value), 80));
	}

	sieve_runtime_trace_descend(renv);

  /* Match to all key values */
  key_item = NULL;
	match = 0;
  while ( match == 0 &&
		(ret=sieve_stringlist_next_item(key_list, &key_item)) > 0 )
  {
		match = mcht_value_match_key
			(mctx, str_c(value), str_len(value), str_c(key_item), str_len(key_item));

		if ( trace ) {
			sieve_runtime_trace(renv, 0,
				"with key `%s' => %d", str_sanitize(str_c(key_item), 80), ret);
		}
	}

	sieve_runtime_trace_ascend(renv);

	if ( ret < 0 ) {
		mctx->exec_status = key_list->exec_status;
		match = -1;
	}

	return match;
}





