/*-
 * Copyright (c) 2021 UPLEX Nils Goroll Systemoptimierung
 * All rights reserved
 *
 * Author: Geoffrey Simmons <geoffrey.simmons@uplex.de>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include "config.h"

#include "cache/cache.h"
#include "vbm.h"
#include "vre.h"
#include "cache/cache_director.h"

#include "vcc_selector_if.h"
#include "qp.h"

#define VFAIL(ctx, fmt, ...) \
	VRT_fail((ctx), "vmod selector failure: " fmt, __VA_ARGS__)

#define VERRNOMEM(ctx, fmt, ...) \
	VFAIL((ctx), "out of space: " fmt,  __VA_ARGS__)

#define VNOTICE(ctx, fmt, ...) \
	VSLb((ctx)->vsl, SLT_Notice, "vmod_selector: " fmt, __VA_ARGS__)

#define VFAIL_OR_NOTICE(ctx, fail, fmt, ...)	do {		\
		if (fail)					\
			VFAIL((ctx), fmt, __VA_ARGS__);		\
		else						\
			VNOTICE((ctx), fmt, __VA_ARGS__);	\
	} while(0)

struct entry {
	unsigned	magic;
#define VMOD_SELECTOR_ENTRY_MAGIC 0x733dbe63
	VCL_BOOL	bool;
	char		*string;
	VCL_BACKEND	backend;
	VCL_SUB		sub;
	VCL_REGEX	re;
	VCL_INT		integer;
};

enum bitmap_e {
	STRING = 0,
	BACKEND,
	REGEX,
	INTEGER,
	BOOLEAN,
	SUB,
	__MAX_BITMAP,
};

struct bitmaps {
	unsigned	magic;
#define VMOD_SELECTOR_BITMAPS_MAGIC 0x5b17093f
	struct vbitmap	*bitmaps[__MAX_BITMAP];
};

struct vmod_selector_set {
	unsigned	magic;
#define VMOD_SELECTOR_SET_MAGIC 0x838979ef
	unsigned	nmembers;
	struct entry	**table;
	char		**members;
	char		**lomembers;
	struct qp_y	*origo;
	struct ph	*hash;
	char		*vcl_name;
	struct bitmaps	*bitmaps;
	unsigned int	case_sensitive:1;
	unsigned int	allow_overlaps:1;
};

static inline int
is_added(const struct vmod_selector_set *set, unsigned idx,
	 enum bitmap_e bitmap)
{
	CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
	CHECK_OBJ_NOTNULL(set->bitmaps, VMOD_SELECTOR_BITMAPS_MAGIC);
	AN(set->bitmaps->bitmaps[bitmap]);

	return (vbit_test(set->bitmaps->bitmaps[bitmap], idx));
}

struct match_data *
get_existing_match_data(const struct vrt_ctx *ctx,
			const struct vmod_selector_set * const restrict set,
			const char * const restrict method, int fail);
