/***
 * Copyright 2020 HAProxy Technologies
 *
 * This file is part of the HAProxy OpenTracing filter.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
#include "include.h"


/***
 * NAME
 *   flt_ot_conf_hdr_init -
 *
 * ARGUMENTS
 *   size    -
 *   id      -
 *   linenum -
 *   head    -
 *   err     -
 *
 * DESCRIPTION
 *   -
 *
 * RETURN VALUE
 *   -
 */
static void *flt_ot_conf_hdr_init(size_t size, const char *id, int linenum, struct list *head, char **err)
{
	struct flt_ot_conf_hdr *retptr = NULL, *ptr;

	FLT_OT_FUNC("%zu, \"%s\", %d, %p, %p:%p", size, id, linenum, head, FLT_OT_DPTR_ARGS(err));

	if (head != NULL)
		list_for_each_entry(ptr, head, list)
			if (strcmp(ptr->id, id) == 0) {
				FLT_OT_ERR("'%s' : already defined", id);

				FLT_OT_RETURN_PTR(retptr);
			}

	retptr = FLT_OT_CALLOC(1, size);
	if (retptr != NULL) {
		retptr->id_len = strlen(id);
		if (retptr->id_len >= FLT_OT_ID_MAXLEN)
			FLT_OT_ERR("'%s' : name too long", id);
		else
			retptr->id = FLT_OT_STRDUP(id);

		if (retptr->id == NULL)
			FLT_OT_FREE_CLEAR(retptr);
	}

	if (retptr != NULL) {
		retptr->cfg_line = linenum;

		if (head != NULL)
			LIST_APPEND(head, &(retptr->list));
	} else {
		FLT_OT_ERR("out of memory");
	}

	FLT_OT_RETURN_PTR(retptr);
}


/***
 * NAME
 *   flt_ot_conf_ph_init -
 *
 * ARGUMENTS
 *   id      -
 *   linenum -
 *   head    -
 *   err     -
 *
 * DESCRIPTION
 *   -
 *
 * RETURN VALUE
 *   -
 */
struct flt_ot_conf_ph *flt_ot_conf_ph_init(const char *id, int linenum, struct list *head, char **err)
{
	struct flt_ot_conf_ph *retptr;

	FLT_OT_FUNC("\"%s\", %d, %p, %p:%p", id, linenum, head, FLT_OT_DPTR_ARGS(err));

	retptr = flt_ot_conf_hdr_init(sizeof(*retptr), id, linenum, head, err);
	if (retptr != NULL)
		FLT_OT_DBG_CONF_PH("- init ", retptr);

	FLT_OT_RETURN_PTR(retptr);
}


/***
 * NAME
 *   flt_ot_conf_ph_free -
 *
 * ARGUMENTS
 *   ptr -
 *
 * DESCRIPTION
 *   -
 *
 * RETURN VALUE
 *   This function does not return a value.
 */
void flt_ot_conf_ph_free(struct flt_ot_conf_ph **ptr)
{
	FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));

	if ((ptr == NULL) || (*ptr == NULL))
		FLT_OT_RETURN();

	FLT_OT_DBG_CONF_PH("- free ", *ptr);

	FLT_OT_FREE((*ptr)->id);
	FLT_OT_LIST_DEL(&((*ptr)->list));
	FLT_OT_FREE_CLEAR(*ptr);

	FLT_OT_RETURN();
}


/***
 * NAME
 *   flt_ot_conf_sample_expr_init -
 *
 * ARGUMENTS
 *   id      -
 *   linenum -
 *   head    -
 *   err     -
 *
 * DESCRIPTION
 *   -
 *
 * RETURN VALUE
 *   -
 */
struct flt_ot_conf_sample_expr *flt_ot_conf_sample_expr_init(const char *id, int linenum, struct list *head, char **err)
{
	struct flt_ot_conf_sample_expr *retptr;

	FLT_OT_FUNC("\"%s\", %d, %p, %p:%p", id, linenum, head, FLT_OT_DPTR_ARGS(err));

	retptr = flt_ot_conf_hdr_init(sizeof(*retptr), id, linenum, head, err);
	if (retptr != NULL)
		FLT_OT_DBG_CONF_SAMPLE_EXPR("- init ", retptr);

	FLT_OT_RETURN_PTR(retptr);
}


/***
 * NAME
 *   flt_ot_conf_sample_expr_free -
 *
 * ARGUMENTS
 *   ptr -
 *
 * DESCRIPTION
 *   -
 *
 * RETURN VALUE
 *   This function does not return a value.
 */
void flt_ot_conf_sample_expr_free(struct flt_ot_conf_sample_expr **ptr)
{
	FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));

	if ((ptr == NULL) || (*ptr == NULL))
		FLT_OT_RETURN();

	FLT_OT_DBG_CONF_SAMPLE_EXPR("- free ", *ptr);

	FLT_OT_FREE((*ptr)->value);
	release_sample_expr((*ptr)->expr);
	FLT_OT_LIST_DEL(&((*ptr)->list));
	FLT_OT_FREE_CLEAR(*ptr);

	FLT_OT_RETURN();
}


/***
 * NAME
 *   flt_ot_conf_sample_init -
 *
 * ARGUMENTS
 *   args    -
 *   linenum -
 *   head    -
 *   err     -
 *
 * DESCRIPTION
 *   -
 *
 * RETURN VALUE
 *   -
 */
struct flt_ot_conf_sample *flt_ot_conf_sample_init(char **args, int linenum, struct list *head, char **err)
{
	struct flt_ot_conf_sample *retptr;

	FLT_OT_FUNC("%p, %d, %p, %p:%p", args, linenum, head, FLT_OT_DPTR_ARGS(err));

	retptr = flt_ot_conf_hdr_init(sizeof(*retptr), args[1], linenum, head, err);
	if (retptr == NULL)
		FLT_OT_RETURN_PTR(retptr);

	flt_ot_args_to_str(args, 2, &(retptr->value));
	if (retptr->value == NULL) {
		FLT_OT_FREE_CLEAR(retptr);

		FLT_OT_RETURN_PTR(retptr);
	}

	retptr->num_exprs = flt_ot_args_count(args) - 2;
	LIST_INIT(&(retptr->exprs));

	FLT_OT_DBG_CONF_SAMPLE("- init ", retptr);

	FLT_OT_RETURN_PTR(retptr);
}


/***
 * NAME
 *   flt_ot_conf_sample_free -
 *
 * ARGUMENTS
 *   ptr -
 *
 * DESCRIPTION
 *   -
 *
 * RETURN VALUE
 *   This function does not return a value.
 */
void flt_ot_conf_sample_free(struct flt_ot_conf_sample **ptr)
{
	FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));

	if ((ptr == NULL) || (*ptr == NULL))
		FLT_OT_RETURN();

	FLT_OT_DBG_CONF_SAMPLE("- free ", *ptr);

	FLT_OT_FREE((*ptr)->key);
	FLT_OT_FREE((*ptr)->value);
	FLT_OT_LIST_DESTROY(sample_expr, &((*ptr)->exprs));
	FLT_OT_LIST_DEL(&((*ptr)->list));
	FLT_OT_FREE_CLEAR(*ptr);

	FLT_OT_RETURN();
}


/***
 * NAME
 *   flt_ot_conf_str_init -
 *
 * ARGUMENTS
 *   id      -
 *   linenum -
 *   head    -
 *   err     -
 *
 * DESCRIPTION
 *   -
 *
 * RETURN VALUE
 *   -
 */
struct flt_ot_conf_str *flt_ot_conf_str_init(const char *id, int linenum, struct list *head, char **err)
{
	struct flt_ot_conf_str *retptr;

	FLT_OT_FUNC("\"%s\", %d, %p, %p:%p", id, linenum, head, FLT_OT_DPTR_ARGS(err));

	retptr = flt_ot_conf_hdr_init(sizeof(*retptr), id, linenum, head, err);
	if (retptr != NULL)
		FLT_OT_DBG_CONF_STR("- init ", retptr);

	FLT_OT_RETURN_PTR(retptr);
}


/***
 * NAME
 *   flt_ot_conf_str_free -
 *
 * ARGUMENTS
 *   ptr -
 *
 * DESCRIPTION
 *   -
 *
 * RETURN VALUE
 *   This function does not return a value.
 */
void flt_ot_conf_str_free(struct flt_ot_conf_str **ptr)
{
	FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));

	if ((ptr == NULL) || (*ptr == NULL))
		FLT_OT_RETURN();

	FLT_OT_DBG_CONF_STR("- free ", *ptr);

	FLT_OT_FREE((*ptr)->str);
	FLT_OT_LIST_DEL(&((*ptr)->list));
	FLT_OT_FREE_CLEAR(*ptr);

	FLT_OT_RETURN();
}


/***
 * NAME
 *   flt_ot_conf_context_init -
 *
 * ARGUMENTS
 *   id      -
 *   linenum -
 *   head    -
 *   err     -
 *
 * DESCRIPTION
 *   -
 *
 * RETURN VALUE
 *   -
 */
struct flt_ot_conf_context *flt_ot_conf_context_init(const char *id, int linenum, struct list *head, char **err)
{
	struct flt_ot_conf_context *retptr;

	FLT_OT_FUNC("\"%s\", %d, %p, %p:%p", id, linenum, head, FLT_OT_DPTR_ARGS(err));

	retptr = flt_ot_conf_hdr_init(sizeof(*retptr), id, linenum, head, err);
	if (retptr != NULL)
		FLT_OT_DBG_CONF_CONTEXT("- init ", retptr);

	FLT_OT_RETURN_PTR(retptr);
}


/***
 * NAME
 *   flt_ot_conf_context_free -
 *
 * ARGUMENTS
 *   ptr -
 *
 * DESCRIPTION
 *   -
 *
 * RETURN VALUE
 *   This function does not return a value.
 */
void flt_ot_conf_context_free(struct flt_ot_conf_context **ptr)
{
	FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));

	if ((ptr == NULL) || (*ptr == NULL))
		FLT_OT_RETURN();

	FLT_OT_DBG_CONF_CONTEXT("- free ", *ptr);

	FLT_OT_FREE((*ptr)->id);
	FLT_OT_LIST_DEL(&((*ptr)->list));
	FLT_OT_FREE_CLEAR(*ptr);

	FLT_OT_RETURN();
}


/***
 * NAME
 *   flt_ot_conf_span_init -
 *
 * ARGUMENTS
 *   id      -
 *   linenum -
 *   head    -
 *   err     -
 *
 * DESCRIPTION
 *   -
 *
 * RETURN VALUE
 *   -
 */
struct flt_ot_conf_span *flt_ot_conf_span_init(const char *id, int linenum, struct list *head, char **err)
{
	struct flt_ot_conf_span *retptr;

	FLT_OT_FUNC("\"%s\", %d, %p, %p:%p", id, linenum, head, FLT_OT_DPTR_ARGS(err));

	retptr = flt_ot_conf_hdr_init(sizeof(*retptr), id, linenum, head, err);
	if (retptr == NULL)
		FLT_OT_RETURN_PTR(retptr);

	LIST_INIT(&(retptr->tags));
	LIST_INIT(&(retptr->logs));
	LIST_INIT(&(retptr->baggages));

	FLT_OT_DBG_CONF_SPAN("- init ", retptr);

	FLT_OT_RETURN_PTR(retptr);
}


/***
 * NAME
 *   flt_ot_conf_span_free -
 *
 * ARGUMENTS
 *   ptr -
 *
 * DESCRIPTION
 *   -
 *
 * RETURN VALUE
 *   This function does not return a value.
 */
void flt_ot_conf_span_free(struct flt_ot_conf_span **ptr)
{
	FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));

	if ((ptr == NULL) || (*ptr == NULL))
		FLT_OT_RETURN();

	FLT_OT_DBG_CONF_SPAN("- free ", *ptr);

	FLT_OT_FREE((*ptr)->id);
	FLT_OT_FREE((*ptr)->ref_id);
	FLT_OT_FREE((*ptr)->ctx_id);
	FLT_OT_LIST_DESTROY(sample, &((*ptr)->tags));
	FLT_OT_LIST_DESTROY(sample, &((*ptr)->logs));
	FLT_OT_LIST_DESTROY(sample, &((*ptr)->baggages));
	FLT_OT_LIST_DEL(&((*ptr)->list));
	FLT_OT_FREE_CLEAR(*ptr);

	FLT_OT_RETURN();
}


/***
 * NAME
 *   flt_ot_conf_scope_init -
 *
 * ARGUMENTS
 *   id      -
 *   linenum -
 *   head    -
 *   err     -
 *
 * DESCRIPTION
 *   -
 *
 * RETURN VALUE
 *   -
 */
struct flt_ot_conf_scope *flt_ot_conf_scope_init(const char *id, int linenum, struct list *head, char **err)
{
	struct flt_ot_conf_scope *retptr = NULL;

	FLT_OT_FUNC("\"%s\", %d, %p, %p:%p", id, linenum, head, FLT_OT_DPTR_ARGS(err));

	retptr = flt_ot_conf_hdr_init(sizeof(*retptr), id, linenum, head, err);
	if (retptr == NULL)
		FLT_OT_RETURN_PTR(retptr);

	LIST_INIT(&(retptr->acls));
	LIST_INIT(&(retptr->contexts));
	LIST_INIT(&(retptr->spans));
	LIST_INIT(&(retptr->finish));

	FLT_OT_DBG_CONF_SCOPE("- init ", retptr);

	FLT_OT_RETURN_PTR(retptr);
}

/***
 * NAME
 *   flt_ot_conf_scope_free -
 *
 * ARGUMENTS
 *   ptr -
 *
 * DESCRIPTION
 *   -
 *
 * RETURN VALUE
 *   This function does not return a value.
 */
void flt_ot_conf_scope_free(struct flt_ot_conf_scope **ptr)
{
	struct acl *acl, *aclback;

	FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));

	if ((ptr == NULL) || (*ptr == NULL))
		FLT_OT_RETURN();

	FLT_OT_DBG_CONF_SCOPE("- free ", *ptr);

	FLT_OT_FREE((*ptr)->id);
	list_for_each_entry_safe(acl, aclback, &((*ptr)->acls), list) {
		prune_acl(acl);
		FLT_OT_LIST_DEL(&(acl->list));
		FLT_OT_FREE(acl);
	}
	free_acl_cond((*ptr)->cond);
	FLT_OT_LIST_DESTROY(context, &((*ptr)->contexts));
	FLT_OT_LIST_DESTROY(span, &((*ptr)->spans));
	FLT_OT_LIST_DESTROY(str, &((*ptr)->finish));
	FLT_OT_LIST_DEL(&((*ptr)->list));
	FLT_OT_FREE_CLEAR(*ptr);

	FLT_OT_RETURN();
}


/***
 * NAME
 *   flt_ot_conf_group_init -
 *
 * ARGUMENTS
 *   id      -
 *   linenum -
 *   head    -
 *   err     -
 *
 * DESCRIPTION
 *   -
 *
 * RETURN VALUE
 *   -
 */
struct flt_ot_conf_group *flt_ot_conf_group_init(const char *id, int linenum, struct list *head, char **err)
{
	struct flt_ot_conf_group *retptr;

	FLT_OT_FUNC("\"%s\", %d, %p, %p:%p", id, linenum, head, FLT_OT_DPTR_ARGS(err));

	retptr = flt_ot_conf_hdr_init(sizeof(*retptr), id, linenum, head, err);
	if (retptr == NULL)
		FLT_OT_RETURN_PTR(retptr);

	LIST_INIT(&(retptr->ph_scopes));

	FLT_OT_DBG_CONF_GROUP("- init ", retptr);

	FLT_OT_RETURN_PTR(retptr);
}


/***
 * NAME
 *   flt_ot_conf_group_free -
 *
 * ARGUMENTS
 *   ptr -
 *
 * DESCRIPTION
 *   -
 *
 * RETURN VALUE
 *   This function does not return a value.
 */
void flt_ot_conf_group_free(struct flt_ot_conf_group **ptr)
{
	FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));

	if ((ptr == NULL) || (*ptr == NULL))
		FLT_OT_RETURN();

	FLT_OT_DBG_CONF_GROUP("- free ", *ptr);

	FLT_OT_FREE((*ptr)->id);
	FLT_OT_LIST_DESTROY(ph_scope, &((*ptr)->ph_scopes));
	FLT_OT_LIST_DEL(&((*ptr)->list));
	FLT_OT_FREE_CLEAR(*ptr);

	FLT_OT_RETURN();
}


/***
 * NAME
 *   flt_ot_conf_tracer_init -
 *
 * ARGUMENTS
 *   id      -
 *   linenum -
 *   err     -
 *
 * DESCRIPTION
 *   -
 *
 * RETURN VALUE
 *   -
 */
struct flt_ot_conf_tracer *flt_ot_conf_tracer_init(const char *id, int linenum, char **err)
{
	struct flt_ot_conf_tracer *retptr;

	FLT_OT_FUNC("\"%s\", %d, %p:%p", id, linenum, FLT_OT_DPTR_ARGS(err));

	retptr = flt_ot_conf_hdr_init(sizeof(*retptr), id, linenum, NULL, err);
	if (retptr == NULL)
		FLT_OT_RETURN_PTR(retptr);

	retptr->rate_limit = FLT_OT_FLOAT_U32(FLT_OT_RATE_LIMIT_MAX, FLT_OT_RATE_LIMIT_MAX);
	init_new_proxy(&(retptr->proxy_log));
	LIST_INIT(&(retptr->acls));
	LIST_INIT(&(retptr->ph_groups));
	LIST_INIT(&(retptr->ph_scopes));

	FLT_OT_DBG_CONF_TRACER("- init ", retptr);

	FLT_OT_RETURN_PTR(retptr);
}


/***
 * NAME
 *   flt_ot_conf_tracer_free -
 *
 * ARGUMENTS
 *   ptr -
 *
 * DESCRIPTION
 *   -
 *
 * RETURN VALUE
 *   This function does not return a value.
 */
void flt_ot_conf_tracer_free(struct flt_ot_conf_tracer **ptr)
{
	struct acl    *acl, *aclback;
	struct logger *logger, *loggerback;

	FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));

	if ((ptr == NULL) || (*ptr == NULL))
		FLT_OT_RETURN();

	FLT_OT_DBG_CONF_TRACER("- free ", *ptr);

	FLT_OT_FREE((*ptr)->id);
	FLT_OT_FREE((*ptr)->config);
	FLT_OT_FREE((*ptr)->cfgbuf);
	FLT_OT_FREE((*ptr)->plugin);
	FLT_OT_DBG(2, "- deleting acls list %s", flt_ot_list_debug(&((*ptr)->acls)));
	list_for_each_entry_safe(acl, aclback, &((*ptr)->acls), list) {
		prune_acl(acl);
		FLT_OT_LIST_DEL(&(acl->list));
		FLT_OT_FREE(acl);
	}
	FLT_OT_DBG(2, "- deleting proxy_log.loggers list %s", flt_ot_list_debug(&((*ptr)->proxy_log.loggers)));
	list_for_each_entry_safe(logger, loggerback, &((*ptr)->proxy_log.loggers), list) {
		LIST_DELETE(&(logger->list));
		FLT_OT_FREE(logger);
	}
	FLT_OT_LIST_DESTROY(ph_group, &((*ptr)->ph_groups));
	FLT_OT_LIST_DESTROY(ph_scope, &((*ptr)->ph_scopes));
	FLT_OT_FREE_CLEAR(*ptr);

	FLT_OT_RETURN();
}


/***
 * NAME
 *   flt_ot_conf_init -
 *
 * ARGUMENTS
 *   px -
 *
 * DESCRIPTION
 *   -
 *
 * RETURN VALUE
 *   -
 */
struct flt_ot_conf *flt_ot_conf_init(struct proxy *px)
{
	struct flt_ot_conf *retptr;

	FLT_OT_FUNC("%p", px);

	retptr = FLT_OT_CALLOC(1, sizeof(*retptr));
	if (retptr == NULL)
		FLT_OT_RETURN_PTR(retptr);

	retptr->proxy = px;
	LIST_INIT(&(retptr->groups));
	LIST_INIT(&(retptr->scopes));

	FLT_OT_DBG_CONF("- init ", retptr);

	FLT_OT_RETURN_PTR(retptr);
}


/***
 * NAME
 *   flt_ot_conf_free -
 *
 * ARGUMENTS
 *   ptr -
 *
 * DESCRIPTION
 *   -
 *
 * RETURN VALUE
 *   This function does not return a value.
 */
void flt_ot_conf_free(struct flt_ot_conf **ptr)
{
	FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));

	if ((ptr == NULL) || (*ptr == NULL))
		FLT_OT_RETURN();

	FLT_OT_DBG_CONF("- free ", *ptr);

	FLT_OT_FREE((*ptr)->id);
	FLT_OT_FREE((*ptr)->cfg_file);
	flt_ot_conf_tracer_free(&((*ptr)->tracer));
	FLT_OT_LIST_DESTROY(group, &((*ptr)->groups));
	FLT_OT_LIST_DESTROY(scope, &((*ptr)->scopes));
	FLT_OT_FREE_CLEAR(*ptr);

	FLT_OT_RETURN();
}

/*
 * Local variables:
 *  c-indent-level: 8
 *  c-basic-offset: 8
 * End:
 *
 * vi: noexpandtab shiftwidth=8 tabstop=8
 */
