/*
** Copyright (C) 2001-2025 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/>.
**/

/* debug logging, remove for release */

#include "pp_cache.h"
#include "zbxjson.h"
#include "zbxprometheus.h"
#include "preproc_snmp.h"

/******************************************************************************
 *                                                                            *
 * Purpose: create preprocessing cache                                        *
 *                                                                            *
 * Parameters: preproc  - [IN] preprocessing data                             *
 *             value    - [IN/OUT] input value - it will copied to cache      *
 *                                 and cleared                                *
 *                                                                            *
 * Return value: The created preprocessing cache                              *
 *                                                                            *
 ******************************************************************************/
zbx_pp_cache_t	*pp_cache_create(const zbx_pp_item_preproc_t *preproc, const zbx_variant_t *value)
{
	zbx_pp_cache_t	*cache = (zbx_pp_cache_t *)zbx_malloc(NULL, sizeof(zbx_pp_cache_t));

	if (0 != preproc->steps_num)
	{
		switch (preproc->steps[0].type)
		{
			/* 'prometheus pattern' cache is reused for 'prometheus to json' */
			case ZBX_PREPROC_PROMETHEUS_TO_JSON:
				cache->type = ZBX_PREPROC_PROMETHEUS_PATTERN;
				break;
			default:
				cache->type = preproc->steps[0].type;
		}
	}
	else
		cache->type = ZBX_PREPROC_NONE;

	zbx_variant_copy(&cache->value, value);
	cache->data = NULL;
	cache->refcount = 1;
	cache->error = NULL;

	return cache;
}

/******************************************************************************
 *                                                                            *
 * Purpose: free preprocessing cache                                          *
 *                                                                            *
 ******************************************************************************/
static void	pp_cache_free(zbx_pp_cache_t *cache)
{
	zbx_variant_clear(&cache->value);

	if (NULL != cache->data)
	{
		switch (cache->type)
		{
			case ZBX_PREPROC_JSONPATH:
				zbx_jsonobj_clear(&((zbx_pp_cache_jsonpath_t *)cache->data)->obj);
				zbx_jsonpath_index_free(((zbx_pp_cache_jsonpath_t *)cache->data)->index);
				break;
			case ZBX_PREPROC_PROMETHEUS_PATTERN:
				zbx_prometheus_clear((zbx_prometheus_t *)cache->data);
				break;
			case ZBX_PREPROC_SNMP_WALK_VALUE:
				zbx_snmp_value_cache_clear((zbx_snmp_value_cache_t *)cache->data);
				break;
		}

		zbx_free(cache->data);
	}

	zbx_free(cache->error);
	zbx_free(cache);
}

/******************************************************************************
 *                                                                            *
 * Purpose: release preprocessing cache                                       *
 *                                                                            *
 ******************************************************************************/
void	pp_cache_release(zbx_pp_cache_t *cache)
{
	if (NULL == cache || 0 != --cache->refcount)
		return;

	pp_cache_free(cache);
}

/******************************************************************************
 *                                                                            *
 * Purpose: copy preprocessing cache                                          *
 *                                                                            *
 * Return value: The copied preprocessing cache.                              *
 *                                                                            *
 ******************************************************************************/
zbx_pp_cache_t	*pp_cache_copy(zbx_pp_cache_t *cache)
{
	if (NULL == cache)
		return NULL;

	cache->refcount++;

	return cache;
}

/******************************************************************************
 *                                                                            *
 * Purpose: copy original value from cache if needed                          *
 *                                                                            *
 * Parameters: cache     - [IN] preprocessing cache                           *
 *             step_type - [IN] preprocessing step type                       *
 *             value     - [OUT] output value                                 *
 *                                                                            *
 * Comments: The value is copied from preprocessing cache if cache exists and *
 *           cache is not initialized or wrong preprocessing step type is     *
 *           cached. Otherwise the cache will be used to execute the step.    *
 *                                                                            *
 ******************************************************************************/
void	pp_cache_prepare_output_value(zbx_pp_cache_t *cache, int step_type, zbx_variant_t *value)
{
	if (NULL == cache->data || step_type != cache->type)
		zbx_variant_copy(value, &cache->value);
}

/******************************************************************************
 *                                                                            *
 * Purpose: check if caching can be done for the specified preprocessing      *
 *          data                                                              *
 *                                                                            *
 * Parameters: preproc  - [IN] preprocessing data                             *
 *                                                                            *
 * Return value: SUCCEED - the preprocessing caching is possible              *
 *               FAIL    - otherwise                                          *
 *                                                                            *
 ******************************************************************************/
int	pp_cache_is_supported(zbx_pp_item_preproc_t *preproc)
{
	if (0 < preproc->steps_num)
	{
		switch (preproc->steps[0].type)
		{
			case ZBX_PREPROC_JSONPATH:
			case ZBX_PREPROC_PROMETHEUS_PATTERN:
			case ZBX_PREPROC_PROMETHEUS_TO_JSON:
			case ZBX_PREPROC_SNMP_WALK_VALUE:
				return SUCCEED;
		}
	}

	return FAIL;
}