/*
** Copyright (C) 2001-2024 Zabbix SIA
**
** This program is free software: you can redistribute it and/or modify it under the terms of
** the GNU Affero General Public License as published by the Free Software Foundation, version 3.
**
** 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 Affero General Public License for more details.
**
** You should have received a copy of the GNU Affero General Public License along with this program.
** If not, see <https://www.gnu.org/licenses/>.
**/

#include "checks_calculated.h"

#include "zbxexpression.h"
#include "zbxeval.h"
#include "zbxtime.h"
#include "zbxvariant.h"

int	get_value_calculated(zbx_dc_item_t *dc_item, AGENT_RESULT *result)
{
	int			ret = NOTSUPPORTED;
	char			*error = NULL;
	zbx_eval_context_t	ctx;
	zbx_variant_t		value;
	zbx_timespec_t		ts;
	zbx_expression_eval_t	eval;
	zbx_dc_um_handle_t	*um_handle;

	zabbix_log(LOG_LEVEL_DEBUG, "In %s() key:'%s' expression:'%s'", __func__, dc_item->key_orig, dc_item->params);

	um_handle = zbx_dc_open_user_macros();

	if (NULL == dc_item->formula_bin)
	{
		zabbix_log(LOG_LEVEL_DEBUG, "%s() serialized formula is not set", __func__);
		SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot evaluate calculated item:"
				" serialized formula is not set"));
		goto out;
	}

	zbx_eval_deserialize(&ctx, dc_item->params, ZBX_EVAL_PARSE_CALC_EXPRESSION, dc_item->formula_bin);

	if (SUCCEED != zbx_eval_expand_user_macros(&ctx, &dc_item->host.hostid, 1,
			(zbx_macro_expand_func_t)zbx_dc_expand_user_and_func_macros, um_handle, &error))
	{
		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot evaluate calculated item: %s", error));
		zbx_free(error);
		zbx_eval_clear(&ctx);
		goto out;
	}

	zbx_timespec(&ts);

	zbx_expression_eval_init(&eval, ZBX_EXPRESSION_AGGREGATE, &ctx);
	zbx_expression_eval_resolve_item_hosts(&eval, dc_item);
	zbx_expression_eval_resolve_filter_macros(&eval, dc_item);

	if (SUCCEED != zbx_expression_eval_execute(&eval, &ts, &value, &error))
	{
		zabbix_log(LOG_LEVEL_DEBUG, "%s() error:%s", __func__, error);
		SET_MSG_RESULT(result, error);
		error = NULL;
	}
	else
	{
		zabbix_log(LOG_LEVEL_DEBUG, "%s() value:%s", __func__, zbx_variant_value_desc(&value));

		switch (value.type)
		{
			case ZBX_VARIANT_DBL:
				SET_DBL_RESULT(result, value.data.dbl);
				break;
			case ZBX_VARIANT_UI64:
				SET_UI64_RESULT(result, value.data.ui64);
				break;
			case ZBX_VARIANT_STR:
				SET_TEXT_RESULT(result, value.data.str);
				break;
			default:
				SET_MSG_RESULT(result, zbx_dsprintf(NULL, "unsupported calculated value result \"%s\""
						" of type \"%s\"", zbx_variant_value_desc(&value),
						zbx_variant_type_desc(&value)));
				zbx_variant_clear(&value);
				break;
		}

		if (ZBX_VARIANT_NONE != value.type)
		{
			zbx_variant_set_none(&value);
			ret = SUCCEED;
		}
	}

	zbx_expression_eval_clear(&eval);
	zbx_eval_clear(&ctx);
	zbx_variant_clear(&value);
out:
	zbx_dc_close_user_macros(um_handle);

	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));

	return ret;
}