/* 
** ZABBIX
** Copyright (C) 2000-2005 SIA Zabbix
**
** 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., 675 Mass Ave, Cambridge, MA 02139, USA.
**/

#include "common.h"
#include "log.h"

/******************************************************************************
 *                                                                            *
 * Function: get_programm_name                                                *
 *                                                                            *
 * Purpose: return program name without path                                  *
 *                                                                            *
 * Parameters: path                                                           *
 *                                                                            *
 * Return value: program name without path                                    *
 *                                                                            *
 * Author: Eugene Grigorjev                                                   *
 *                                                                            *
 *  Comments:                                                                 *
 *                                                                            *
 ******************************************************************************/
char* get_programm_name(char *path)
{
	char	*filename = NULL;

	for(filename = path; path && *path; path++)
		if(*path == '\\' || *path == '/')
			filename = path+1;

	return filename;
}

/******************************************************************************
 *                                                                            *
 * Function: get_nodeid_by_id                                                 *
 *                                                                            *
 * Purpose: Get Node ID by resource ID                                        *
 *                                                                            *
 * Parameters:                                                                *
 *                                                                            *
 * Return value: Node ID                                                      *
 *                                                                            *
 * Author: Alexei Vladishev                                                   *
 *                                                                            *
 *  Comments:                                                                 *
 *                                                                            *
 ******************************************************************************/
int get_nodeid_by_id(zbx_uint64_t id)
{
	return (int)(id/__UINT64_C(100000000000000))%1000;

}

/******************************************************************************
 *                                                                            *
 * Function: zbx_time                                                         *
 *                                                                            *
 * Purpose: Gets the current time.                                            *
 *                                                                            *
 * Parameters:                                                                *
 *                                                                            *
 * Return value: Time in seconds                                              *
 *                                                                            *
 * Author: Eugene Grigorjev                                                   *
 *                                                                            *
 *  Comments: Time in seconds since midnight (00:00:00),                      *
 *            January 1, 1970, coordinated universal time (UTC).              *
 *                                                                            *
 ******************************************************************************/
double	zbx_time(void)
{

#if defined(_WINDOWS)

	struct _timeb current;

	_ftime(&current);

	return (((double)current.time) + 1.0e-6 * ((double)current.millitm));

#else /* not _WINDOWS */

	struct timeval current;

	gettimeofday(&current,NULL);

	return (((double)current.tv_sec) + 1.0e-6 * ((double)current.tv_usec));

#endif /* _WINDOWS */

}

/******************************************************************************
 *                                                                            *
 * Function: zbx_current_time                                                 *
 *                                                                            *
 * Purpose: Gets the current time include UTC offset                          *
 *                                                                            *
 * Parameters:                                                                *
 *                                                                            *
 * Return value: Time in seconds                                              *
 *                                                                            *
 * Author: Eugene Grigorjev                                                   *
 *                                                                            *
 ******************************************************************************/

double zbx_current_time (void)
{
	return (zbx_time() + ZBX_JAN_1970_IN_SEC);
}

/******************************************************************************
 *                                                                            *
 * Function: zbx_setproctitle                                                 *
 *                                                                            *
 * Purpose: set process title                                                 *
 *                                                                            *
 * Parameters: title - item's refresh rate in sec                             *
 *                                                                            *
 * Return value:                                                              *
 *                                                                            *
 * Author: Eugene Grigorjev                                                   *
 *                                                                            *
 ******************************************************************************/
void	__zbx_zbx_setproctitle(const char *fmt, ...)
{
#ifdef HAVE_FUNCTION_SETPROCTITLE

	char	title[MAX_STRING_LEN];

	va_list args;

	va_start(args, fmt);
	vsnprintf(title, MAX_STRING_LEN-1, fmt, args);
	va_end(args);

	setproctitle(title);

#endif /* HAVE_FUNCTION_SETPROCTITLE */
}

/******************************************************************************
 *                                                                            *
 * Function: calculate_item_nextcheck                                         *
 *                                                                            *
 * Purpose: calculate nextcheck timespamp for item                            *
 *                                                                            *
 * Parameters: delay - item's refresh rate in sec                             *
 *             now - current timestamp                                        *
 *                                                                            *
 * Return value: nextcheck value                                              *
 *                                                                            *
 * Author: Alexei Vladishev                                                   *
 *                                                                            *
 * Comments: Old algorithm: now+delay                                         *
 *           New one: preserve period, if delay==5, nextcheck = 0,5,10,15,... *
 *                                                                            *
 ******************************************************************************/
int	calculate_item_nextcheck(zbx_uint64_t itemid, int item_type, int delay, char *delay_flex, time_t now)
{
	int	i;
	char	*p;
	char	delay_period[30];
	int	delay_val;

	zabbix_log( LOG_LEVEL_DEBUG, "In calculate_item_nextcheck (" ZBX_FS_UI64 ",%d,%s,%d)",
		itemid,delay,delay_flex,now);

/* Special processing of active items to see better view in queue */
	if(item_type == ITEM_TYPE_ZABBIX_ACTIVE)
	{
		zabbix_log( LOG_LEVEL_DEBUG, "End calculate_item_nextcheck (result:%d)",
			(((int)now)+delay));
		return (((int)now)+delay);
	}


	if(delay_flex && *delay_flex)
	{
		do
		{
			p = strchr(delay_flex, ';');
			if(p) *p = '\0';
			
			zabbix_log( LOG_LEVEL_DEBUG, "Delay period [%s]", delay_flex);

			if(sscanf(delay_flex, "%d/%29s",&delay_val,delay_period) == 2)
			{
				zabbix_log( LOG_LEVEL_DEBUG, "%d sec at %s",delay_val,delay_period);
				if(check_time_period(delay_period, now))
				{
					delay = delay_val;
					break;
				}
			}
			else
			{
				zabbix_log( LOG_LEVEL_ERR, "Delay period format is wrong [%s]",delay_flex);
			}
			if(p)
			{
				*p = ';'; /* restore source string */
				delay_flex = p+1;
			}
		}while(p);
		
	}

/*	Old algorithm */
/*	i=delay*(int)(now/delay);*/
	
	i=delay*(int)(now/(time_t)delay)+(int)(itemid % (zbx_uint64_t)delay);

	while(i<=now)	i+=delay;

	zabbix_log( LOG_LEVEL_DEBUG, "End calculate_item_nextcheck (result:%d)", i);
	return i;
}

/******************************************************************************
 *                                                                            *
 * Function: is_ip4                                                           *
 *                                                                            *
 * Purpose: is string IPv4 address                                            *
 *                                                                            *
 * Parameters: ip - string                                                    *
 *                                                                            *
 * Return value: SUCCEED - is IPv4 address                                    * 
 *               FAIL - otherwise                                             *
 *                                                                            *
 * Author: Alexei Vladishev, Aleksander Vladishev                             *
 *                                                                            *
 * Comments:                                                                  *
 *                                                                            *
 ******************************************************************************/
static int	is_ip4(const char *ip)
{
	const char	*p = ip;
	int		nums, dots, res = FAIL;

	zabbix_log(LOG_LEVEL_DEBUG, "In is_ip4() [%s]",
			ip);

	nums = 0;
	dots = 0;
	while ('\0' != *p) {
		if (*p >= '0' && *p <= '9') {
			nums++;
		} else if (*p == '.') {
			if (nums == 0 || nums > 3)
				break;
			nums = 0;
			dots++;
		} else {
			nums = 0;
			break;
		}
		p++;
	}
	if (dots == 3 && nums >= 1 && nums <= 3)
		res = SUCCEED;

	zabbix_log(LOG_LEVEL_DEBUG, "End of is_ip4(result:%d)",
			res);

	return res;
}

#if defined(HAVE_IPV6)
/******************************************************************************
 *                                                                            *
 * Function: is_ip6                                                           *
 *                                                                            *
 * Purpose: is string IPv6 address                                            *
 *                                                                            *
 * Parameters: ip - string                                                    *
 *                                                                            *
 * Return value: SUCCEED - is IPv6 address                                    * 
 *               FAIL - otherwise                                             *
 *                                                                            *
 * Author: Aleksader Vladishev                                                *
 *                                                                            *
 * Comments: could be improved (not supported x:x:x:x:x:x:d.d.d.d addresses)  *
 *                                                                            *
 ******************************************************************************/
static int	is_ip6(const char *ip)
{
	const char	*p = ip;
	int		nums, is_nums, colons, dcolons, res = FAIL;

	zabbix_log(LOG_LEVEL_DEBUG, "In is_ip6() [%s]",
			ip);

	nums = 0;
	is_nums = 0;
	colons = 0;
	dcolons = 0;
	while ('\0' != *p) {
		if ((*p >= '0' && *p <= '9') || (*p >= 'A' && *p <= 'F') || (*p >= 'a' && *p <= 'f')) {
			nums++;
			is_nums = 1;
		} else if (*p == ':') {
			if (nums == 0 && colons > 0)
				dcolons++;
			if (nums > 4 || dcolons > 1)
				break;
			nums = 0;
			colons++;
		} else {
			is_nums = 0;
			break;
		}
		p++;
	}
	if (colons >= 2 && colons <= 7 && nums <= 4 && is_nums == 1)
		res = SUCCEED;

	zabbix_log(LOG_LEVEL_DEBUG, "End of is_ip6(result:%d)",
			res);

	return res;
}
#endif /*HAVE_IPV6*/

/******************************************************************************
 *                                                                            *
 * Function: is_ip                                                            *
 *                                                                            *
 * Purpose: is string IP address                                              *
 *                                                                            *
 * Parameters: ip - string                                                    *
 *                                                                            *
 * Return value: SUCCEED - is IP address                                      * 
 *               FAIL - otherwise                                             *
 *                                                                            *
 * Author: Aleksader Vladishev                                                *
 *                                                                            *
 * Comments:                                                                  *
 *                                                                            *
 ******************************************************************************/
int	is_ip(const char *ip)
{
	zabbix_log(LOG_LEVEL_DEBUG, "In is_ip() [%s]",
			ip);

	if (SUCCEED == is_ip4(ip))
		return SUCCEED;
#if defined(HAVE_IPV6)
	if (SUCCEED == is_ip6(ip))
		return SUCCEED;
#endif /*HAVE_IPV6*/
	return FAIL;
}

#if defined(HAVE_IPV6)
/******************************************************************************
 *                                                                            *
 * Function: expand_ipv6                                                      *
 *                                                                            *
 * Purpose: convert short ipv6 addresses to expanded type                     *
 *                                                                            *
 * Parameters: ip - IPv6 IPs [12fc::2]                                        *
 *             buf - result value [12fc:0000:0000:0000:0000:0000:0000:0002]   *
 *                                                                            *
 * Return value: FAIL - invlid IP address, SUCCEED - conversion OK            *
 *                                                                            *
 * Author: Alksander Vladishev                                                *
 *                                                                            *
 * Comments:                                                                  *
 *                                                                            *
 ******************************************************************************/
int	expand_ipv6(const char *ip, char *str, size_t str_len )
{
	unsigned int	i[8]; /* x:x:x:x:x:x:x:x */
	char		buf[5], *ptr;
	int		c, dc, pos = 0, j, len, ip_len, ret = FAIL;

	zabbix_log(LOG_LEVEL_DEBUG, "In expand_ipv6(ip:%s)", ip);

	c = 0; /* colons count */
	for(ptr = strchr(ip, ':'); ptr != NULL; ptr = strchr(ptr + 1, ':'))
	{
		c ++;
	}

	if(c < 2 || c > 7)
	{
		goto out;
	}

	ip_len = strlen(ip);
	if((ip[0] == ':' && ip[1] != ':') || (ip[ip_len - 1] == ':' && ip[ip_len - 2] != ':'))
	{
		goto out;
	}

	memset(i, 0x00, sizeof(i));

	dc  = 0; /* double colon flag */
	len = 0;
	for(j = 0; j<ip_len; j++)
	{
		if((ip[j] >= '0' && ip[j] <= '9') || (ip[j] >= 'A' && ip[j] <= 'F') || (ip[j] >= 'a' && ip[j] <= 'f'))
		{
			if(len > 3)
			{
				goto out;
			}
			buf[len ++] = ip[j];
		}
		else if(ip[j] != ':')
		{
			goto out;
		}

		if(ip[j] == ':' || ip[j + 1] == '\0')
		{
			if(len)
			{
				buf[len] = 0x00;
				sscanf(buf, "%x", &i[pos]);
				pos ++;
				len = 0;
			}

			if(ip[j + 1] == ':')
			{
				if(dc == 0)
				{
					dc = 1;
					pos = ( 8 - c ) + pos + (j == 0 ? 1 : 0);
				}
				else
				{
					goto out;
				}
			}
		}
	}
	zbx_snprintf(str, str_len, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", i[0], i[1], i[2], i[3], i[4], i[5], i[6], i[7]);
	ret = SUCCEED;
out:
	zabbix_log(LOG_LEVEL_DEBUG, "End expand_ipv6(ip:%s):%s", ip, ret == SUCCEED ? "SUCCEED" : "FAIL");

	return ret;
}

/******************************************************************************
 *                                                                            *
 * Function: ip_in_list_ipv6                                                  *
 *                                                                            *
 * Purpose: check if ip matches range of ip addresses                         *
 *                                                                            *
 * Parameters: list -  IPs [12fc::2-55,::45]                                  *
 *                                                                            *
 * Return value: FAIL - out of range, SUCCEED - within the range              *
 *                                                                            *
 * Author: Alexei Vladishev                                                   *
 *                                                                            *
 * Comments:                                                                  *
 *                                                                            *
 ******************************************************************************/
int	ip_in_list_ipv6(char *list, char *ip)
{
	char	*start, *comma = NULL, *dash = NULL, buffer[MAX_STRING_LEN];
	int	i[8], j[9], ret = FAIL;

	zabbix_log(LOG_LEVEL_DEBUG, "In ip_in_list(list:%s,ip:%s)", list, ip);

	if(FAIL == expand_ipv6(ip, buffer, sizeof(buffer)))
	{
		goto out;
	}

	if(sscanf(buffer, "%x:%x:%x:%x:%x:%x:%x:%x", &i[0], &i[1], &i[2], &i[3], &i[4], &i[5], &i[6], &i[7]) != 8)
	{
		goto out;
	}

	for(start = list; start[0] != '\0';)
	{

		if(NULL != (comma = strchr(start, ',')))
		{
			comma[0] = '\0';
		}

		if(NULL != (dash = strchr(start, '-')))
		{
			dash[0] = '\0';
			if(sscanf(dash + 1, "%x", &j[8]) != 1)
			{
				goto next;
			}
		}

		if(FAIL == expand_ipv6(start, buffer, sizeof(buffer)))
		{
			goto next;
		}

		if(sscanf(buffer, "%x:%x:%x:%x:%x:%x:%x:%x", &j[0], &j[1], &j[2], &j[3], &j[4], &j[5], &j[6], &j[7]) != 8)
		{
			goto next;
		}

		if(dash == NULL)
		{
			j[8] = j[7];
		}

		if(i[0] == j[0] && i[1] == j[1] && i[2] == j[2] && i[3] == j[3] && 
		   i[4] == j[4] && i[5] == j[5] && i[6] == j[6] && 
		   i[7] >= j[7] && i[7] <= j[8])
		{
			ret = SUCCEED;
			break;
		}
next:
		if(dash != NULL)
		{
			dash[0] = '-';
			dash = NULL;
		}

		if(comma != NULL)
		{
			comma[0] = ',';
			start = comma + 1;
			comma = NULL;
		}
		else
		{
			break;
		}
	}
out:
	if(dash != NULL)
	{
		dash[0] = '-';
	}

	if(comma != NULL)
	{
		comma[0] = ',';
	}

	zabbix_log(LOG_LEVEL_DEBUG, "End ip_in_list(ret:%s)", ret == SUCCEED ? "SUCCEED" : "FAIL");
	return ret;
}
#endif /*HAVE_IPV6*/
/******************************************************************************
 *                                                                            *
 * Function: ip_in_list                                                       *
 *                                                                            *
 * Purpose: check if ip matches range of ip addresses                         *
 *                                                                            *
 * Parameters: list -  IPs [192.168.1.1-244,192.168.1.250]                    *
 *                                                                            *
 * Return value: FAIL - out of range, SUCCEED - within the range              *
 *                                                                            *
 * Author: Alexei Vladishev                                                   *
 *                                                                            *
 * Comments:                                                                  *
 *                                                                            *
 ******************************************************************************/
int	ip_in_list(char *list, char *ip)
{
	int	i[4], j[5];
	int	ret = FAIL;
	char	*start = NULL, *comma = NULL, *dash = NULL;

	zabbix_log( LOG_LEVEL_DEBUG, "In ip_in_list(list:%s,ip:%s)", list, ip);

	if(sscanf(ip, "%d.%d.%d.%d", &i[0], &i[1], &i[2], &i[3]) != 4)
	{
#if defined(HAVE_IPV6)
		ret = ip_in_list_ipv6(list, ip);
#endif /*HAVE_IPV6*/
		goto out;
	}

	for(start = list; start[0] != '\0';)
	{
		if(NULL != (comma = strchr(start, ',')))
		{
			comma[0] = '\0';
		}

		if(NULL != (dash = strchr(start, '-')))
		{
			dash[0] = '\0';
			if(sscanf(dash + 1, "%d", &j[4]) != 1)
			{
				goto next;
			}
		}

		if(sscanf(start, "%d.%d.%d.%d", &j[0], &j[1], &j[2], &j[3]) != 4)
		{
			goto next;
		}

		if(dash == NULL)
		{
			j[4] = j[3];
		}

		if(i[0] == j[0] && i[1] == j[1] && i[2] == j[2] && i[3] >= j[3] && i[3] <= j[4])
		{
			ret = SUCCEED;
			break;
		}
next:
		if(dash != NULL)
		{
			dash[0] = '-';
			dash = NULL;
		}

		if(comma != NULL)
		{
			comma[0] = ',';
			start = comma + 1;
			comma = NULL;
		}
		else
		{
			break;
		}
	}

out:
	if(dash != NULL)
	{
		dash[0] = '-';
	}

	if(comma != NULL)
	{
		comma[0] = ',';
	}

	zabbix_log( LOG_LEVEL_DEBUG, "End ip_in_list(ret:%s)", ret == SUCCEED ? "SUCCEED" : "FAIL");
	return ret;
}

/******************************************************************************
 *                                                                            *
 * Function: int_in_list                                                      *
 *                                                                            *
 * Purpose: check if integer matches a list of integers                       *
 *                                                                            *
 * Parameters: list -  integers [i1-i2,i3,i4,i5-i6] (10-25,45,67-699          *
 *             value-  value                                                  *
 *                                                                            *
 * Return value: FAIL - out of period, SUCCEED - within the period            *
 *                                                                            *
 * Author: Alexei Vladishev                                                   *
 *                                                                            *
 * Comments:                                                                  *
 *                                                                            *
 ******************************************************************************/
int	int_in_list(char *list, int value)
{
	char	*start = NULL, *end = NULL;
	int	i1,i2;
	int	ret = FAIL;
	char	c = '\0';

	zabbix_log( LOG_LEVEL_DEBUG, "In int_in_list(list:%s,value:%d)", list, value);

	for(start = list; start[0] != '\0';)
	{
		end=strchr(start, ',');

		if(end != NULL)
		{	
			c=end[0];
			end[0]='\0';
		}
		
		if(sscanf(start,"%d-%d",&i1,&i2) == 2)
		{
			if(value>=i1 && value<=i2)
			{
				ret = SUCCEED;
				break;
			}
		}
		else
		{
			if(atoi(start) == value)
			{
				ret = SUCCEED;
				break;
			}
		}

		if(end != NULL)
		{
			end[0]=c;
			start=end+1;
		}
		else
		{
			break;
		}
	}

	if(end != NULL)
	{
		end[0]=c;
	}

	zabbix_log( LOG_LEVEL_DEBUG, "End int_in_list(ret:%s)", ret == SUCCEED?"SUCCEED":"FAIL");

	return ret;
}

/******************************************************************************
 *                                                                            *
 * Function: check_time_period                                                *
 *                                                                            *
 * Purpose: check if current time is within given period                      *
 *                                                                            *
 * Parameters: period - time period in format [d1-d2,hh:mm-hh:mm]*            *
 *             now    - timestamp for comporation                             *
 *                      if NULL - use current timestamp.                      *
 *                                                                            *
 * Return value: 0 - out of period, 1 - within the period                     *
 *                                                                            *
 * Author: Alexei Vladishev                                                   *
 *                                                                            *
 * Comments:                                                                  *
 *                                                                            *
 ******************************************************************************/
int	check_time_period(const char *period, time_t now)
{
	char	tmp[MAX_STRING_LEN];
	char	*s;
	int	d1,d2,h1,h2,m1,m2;
	int	day, hour, min;
	struct  tm      *tm;
	int	ret = 0;


	zabbix_log( LOG_LEVEL_DEBUG, "In check_time_period(%s)",period);

	if(now == (time_t)NULL)	now = time(NULL);
	
	tm = localtime(&now);

	day=tm->tm_wday;
	if(0 == day)	day=7;
	hour = tm->tm_hour;
	min = tm->tm_min;

	strscpy(tmp,period);
       	s=(char *)strtok(tmp,";");
	while(s!=NULL)
	{
		zabbix_log( LOG_LEVEL_DEBUG, "Period [%s]",s);

		if(sscanf(s,"%d-%d,%d:%d-%d:%d",&d1,&d2,&h1,&m1,&h2,&m2) == 6)
		{
			zabbix_log( LOG_LEVEL_DEBUG, "%d-%d,%d:%d-%d:%d",d1,d2,h1,m1,h2,m2);
			if( (day>=d1) && (day<=d2) && (60*hour+min>=60*h1+m1) && (60*hour+min<=60*h2+m2))
			{
				ret = 1;
				break;
			}
		}
		else
		{
			zabbix_log( LOG_LEVEL_ERR, "Time period format is wrong [%s]",period);
		}

       		s=(char *)strtok(NULL,";");
	}
	return ret;
}

/******************************************************************************
 *                                                                            *
 * Function: cmp_double                                                       *
 *                                                                            *
 * Purpose: compares two double values                                        *
 *                                                                            *
 * Parameters: a,b - doubled to compare                                       *
 *                                                                            *
 * Return value:  0 - the values are equal                                    *
 *                1 - otherwise                                               *
 *                                                                            *
 * Author: Alexei Vladishev                                                   *
 *                                                                            *
 * Comments: equal == differs less than 0.000001                              *
 *                                                                            *
 ******************************************************************************/
int	cmp_double(double a,double b)
{
	if(fabs(a-b)<0.000001)
	{
		return	0;
	}
	return	1;
}

/******************************************************************************
 *                                                                            *
 * Function: is_double_prefix                                                 *
 *                                                                            *
 * Purpose: check if the string is double                                     *
 *                                                                            *
 * Parameters: c - string to check                                            *
 *                                                                            *
 * Return value:  SUCCEED - the string is double                              *
 *                FAIL - otherwise                                            *
 *                                                                            *
 * Author: Alexei Vladishev                                                   *
 *                                                                            *
 * Comments: the functions support prefixes K,M,G                             *
 *                                                                            *
 ******************************************************************************/
int	is_double_prefix(char *c)
{
	int i;
	int dot=-1;

	for(i=0;c[i]!=0;i++)
	{
		/* Negative number? */
		if(c[i]=='-' && i==0)
		{
			continue;
		}

		if((c[i]>='0')&&(c[i]<='9'))
		{
			continue;
		}

		if((c[i]=='.')&&(dot==-1))
		{
			dot=i;
			continue;
		}
		/* Last digit is prefix 'K', 'M', 'G' */
		if( ((c[i]=='K')||(c[i]=='M')||(c[i]=='G')) && (i == (int)strlen(c)-1))
		{
			continue;
		}

		return FAIL;
	}
	return SUCCEED;
}

/******************************************************************************
 *                                                                            *
 * Function: is_double                                                        *
 *                                                                            *
 * Purpose: check if the string is double                                     *
 *                                                                            *
 * Parameters: c - string to check                                            *
 *                                                                            *
 * Return value:  SUCCEED - the string is double                              *
 *                FAIL - otherwise                                            *
 *                                                                            *
 * Author: Alexei Vladishev                                                   *
 *                                                                            *
 * Comments:                                                                  *
 *                                                                            *
 ******************************************************************************/
/*int is_double(char *str)
{
	const char *endstr = str + strlen(str);
	char *endptr = NULL;
	double x;
       
	x = strtod(str, &endptr);

	if(endptr == str || errno != 0)
		return FAIL;
	if (endptr == endstr)
		return SUCCEED;
	return FAIL;
}*/

int	is_double(char *c)
{
	int i;
	int dot=-1;
	int len;

	for(i=0; c[i]==' ' && c[i]!=0;i++); /* trim left spaces */

	for(len=0; c[i]!=0; i++, len++)
	{
		/* Negative number? */
		if(c[i]=='-' && i==0)
		{
			continue;
		}

		if((c[i]>='0')&&(c[i]<='9'))
		{
			continue;
		}

		if((c[i]=='.')&&(dot==-1))
		{
			dot=i;
			continue;
		}

		if(c[i]==' ') /* check right spaces */
		{
			for( ; c[i]==' ' && c[i]!=0;i++); /* trim right spaces */
			
			if(c[i]==0) break; /* SUCCEED */
		}

		return FAIL;
	}
	
	if(len <= 0) return FAIL;

	if(len == 1 && dot!=-1) return FAIL;

	return SUCCEED;
}

/******************************************************************************
 *                                                                            *
 * Function: is_uint                                                          *
 *                                                                            *
 * Purpose: check if the string is unsigned integer                           *
 *                                                                            *
 * Parameters: c - string to check                                            *
 *                                                                            *
 * Return value:  SUCCEED - the string is unsigned integer                    *
 *                FAIL - otherwise                                            *
 *                                                                            *
 * Author: Alexei Vladishev                                                   *
 *                                                                            *
 * Comments:                                                                  *
 *                                                                            *
 ******************************************************************************/
int	is_uint(char *c)
{
	int	i;
	int	len;

	for(i=0; c[i]==' ' && c[i]!=0;i++); /* trim left spaces */
	
	for(len=0; c[i]!=0; i++,len++)
	{
		if((c[i]>='0')&&(c[i]<='9'))
		{
			continue;
		}
		
		if(c[i]==' ') /* check right spaces */
		{
			for( ; c[i]==' ' && c[i]!=0;i++); /* trim right spaces */
			
			if(c[i]==0) break; /* SUCCEED */
		}
		return FAIL;
	}

	if(len <= 0) return FAIL;
	
	return SUCCEED;
}

/******************************************************************************
 *                                                                            *
 * Function: uint64_in_list                                                   *
 *                                                                            *
 * Purpose: check if uin64 integer matches a list of integers                 *
 *                                                                            *
 * Parameters: list -  integers [i1-i2,i3,i4,i5-i6] (10-25,45,67-699          *
 *             value-  value                                                  *
 *                                                                            *
 * Return value: FAIL - out of period, SUCCEED - within the list              *
 *                                                                            *
 * Author: Alexei Vladishev                                                   *
 *                                                                            *
 * Comments:                                                                  *
 *                                                                            *
 ******************************************************************************/
int	uint64_in_list(char *list, zbx_uint64_t value)
{
	char		*start = NULL, *end = NULL;
	zbx_uint64_t	i1,i2,tmp_uint64;
	int		ret = FAIL;
	char		c = '\0';

	zabbix_log( LOG_LEVEL_DEBUG, "In int_in_list(list:%s,value:" ZBX_FS_UI64 ")", list, value);

	for(start = list; start[0] != '\0';)
	{
		end=strchr(start, ',');

		if(end != NULL)
		{	
			c=end[0];
			end[0]='\0';
		}
		
		if(sscanf(start,ZBX_FS_UI64 "-" ZBX_FS_UI64,&i1,&i2) == 2)
		{
			if(value>=i1 && value<=i2)
			{
				ret = SUCCEED;
				break;
			}
		}
		else
		{
			ZBX_STR2UINT64(tmp_uint64,start);
			if(tmp_uint64 == value)
			{
				ret = SUCCEED;
				break;
			}
		}

		if(end != NULL)
		{
			end[0]=c;
			start=end+1;
		}
		else
		{
			break;
		}
	}

	if(end != NULL)
	{
		end[0]=c;
	}

	zabbix_log( LOG_LEVEL_DEBUG, "End int_in_list(ret:%s)", ret == SUCCEED?"SUCCEED":"FAIL");

	return ret;
}

/******************************************************************************
 *                                                                            *
 * Function: get_nearestindex                                                 *
 *                                                                            *
 * Purpose:                                                                   *
 *                                                                            *
 * Parameters:                                                                *
 *                                                                            *
 * Return value:                                                              *
 *                                                                            *
 * Author: Alekasander Vladishev                                              *
 *                                                                            *
 * Comments:                                                                  *
 *                                                                            *
 ******************************************************************************/
static int	get_nearestindex(zbx_uint64_t *values, int num, zbx_uint64_t value)
{
	int	first_index, last_index, index;

	if (num == 0)
		return 0;

	first_index = 0;
	last_index = num - 1;
	while (1)
	{
		index = first_index + (last_index - first_index) / 2;

		if (values[index] == value)
			return index;
		else if (last_index == first_index)
		{
			if (values[index] < value)
				index++;
			return index;
		}
		else if (values[index] < value)
			first_index = index + 1;
		else
			last_index = index;
	}
}

/******************************************************************************
 *                                                                            *
 * Function: uint64_array_add                                                 *
 *                                                                            *
 * Purpose: add uint64 value to dynamic array                                 *
 *                                                                            *
 * Parameters:                                                                *
 *                                                                            *
 * Return value:                                                              *
 *                                                                            *
 * Author: Aleksander Vladishev                                               *
 *                                                                            *
 * Comments:                                                                  *
 *                                                                            *
 ******************************************************************************/
int	uint64_array_add(zbx_uint64_t **values, int *alloc, int *num, zbx_uint64_t value)
{
	int	index;

	index = get_nearestindex(*values, *num, value);
	if (index < (*num) && (*values)[index] == value)
		return index;

	if (*alloc == *num)
	{
		*alloc += 100;
		*values = zbx_realloc(*values, *alloc * sizeof(zbx_uint64_t));
	}

	memmove(&(*values)[index + 1], &(*values)[index], sizeof(zbx_uint64_t) * (*num - index));

	(*values)[index] = value;
	(*num)++;

	return index;
}

/******************************************************************************
 *                                                                            *
 * Function: uint64_array_exists                                              *
 *                                                                            *
 * Purpose:                                                                   *
 *                                                                            *
 * Parameters:                                                                *
 *                                                                            *
 * Return value:                                                              *
 *                                                                            *
 * Author: Aleksander Vladishev                                               *
 *                                                                            *
 * Comments:                                                                  *
 *                                                                            *
 ******************************************************************************/
int	uint64_array_exists(zbx_uint64_t *values, int num, zbx_uint64_t value)
{
	int	index;

	index = get_nearestindex(values, num, value);
	if (index < num && values[index] == value)
		return SUCCEED;

	return FAIL;
}

/******************************************************************************
 *                                                                            *
 * Function: uint64_array_remove                                              *
 *                                                                            *
 * Purpose: add uint64 value to dynamic array                                 *
 *                                                                            *
 * Parameters:                                                                *
 *                                                                            *
 * Return value:                                                              *
 *                                                                            *
 * Author: Aleksander Vladishev                                               *
 *                                                                            *
 * Comments:                                                                  *
 *                                                                            *
 ******************************************************************************/
void	uint64_array_rm(zbx_uint64_t *values, int *num, zbx_uint64_t *rm_values, int rm_num)
{
	int	rindex, index;

	for (rindex = 0; rindex < rm_num; rindex++)
	{
		index = get_nearestindex(values, *num, rm_values[rindex]);
		if (index == *num || values[index] != rm_values[rindex])
			continue;

		memmove(&values[index], &values[index + 1], sizeof(zbx_uint64_t) * ((*num) - index - 1));
		(*num)--;
	}
}
