#include "querydb.h"

static char const rcsid[] = "$Id: asquery.c,v 1.4 2004/03/10 18:04:33 wilhelm Exp $";

int compress_aspath(char *input, char *output) {
	/* 
		compress IP level path of ASes to a path in AS space
		
		- replace sequence of duplicates by one
		- replace a sequence where after a 0 (no info available)
	          previous AS reoccurs by one entry  (no looping in AS space)
		
		return number of AS hops in compressed path 
		
	*/

	char *current;
	char previous[32];
	char lastseen[32];

	int len = 0;
	output[0]   = '\0';   /* start with zero length paths */
	lastseen[0] = '\0';   
	previous[0] = '\0';  

/*	fprintf(stderr, "In: %s ", input);
*/

	if ((current = strtok(input, " ")) == NULL) {
		/* single hop or zero length AS path */
		strcpy(output, input);
		return(1);
	}
   
	/* normal case, start by copying first valid AS to output */

	if (strcmp(current, "0") != 0) {
		len++;
		strcpy(output, current);
		strcat(output, " ");
	}

	strcpy(previous, current);

	while ((current = strtok(NULL, " ")) != NULL) {
		if (strcmp(current, previous) != 0) {
			/* different from previous hop */

			if (strcmp(previous, "0") != 0) {
				if (strcmp(current, "0") != 0) {
					/* valid, add to aspath */
					strcat(output, current);
					strcat(output, " ");
					strcpy(lastseen, current);
					len++;
				}

				/* if current eq 0 we wait with output
				   until we have info from the next hop */

			}
			else {
				/* couldn't find AS for previous IPhop(s)
				   if AS differs from lastseen, ouptut 0
				   for unknown AShop plus current AS.
				   If they are the same, unresolved IP
				   must be in AS, can't have AS loops! */

				if (strcmp(current, lastseen) != 0) {
					/* current differs from last valid
					   unknown hop in between */
					strcat(output, "0 ");
					strcat(output, current);
					strcat(output, " ");
					len += 2; 	 /* 0 + current */
					strcpy(lastseen, current);
				}
			}
			strcpy(previous, current);
		}
	}

	if (strcmp(previous,"0") == 0) {
		/* last AShop unknown. Note that this has to be outside
		   above loop, to capture the case where several hops at
		   the end don't have AS */

		strcat(output, "0 ");
		len++;
	}

/*	fprintf(stderr, "  Out: %s\n ", output);
*/
	return(len);


}

int match_aspath_by_time(MYSQL *mysql, char *srcbox, char *dstbox, time_t t_start, time_t t_end, struct querystruct *data)
{
	char query [1024];
	MYSQL_RES *result;
	MYSQL_ROW row;
	
	struct querystruct *current;
	struct querystruct *index, *next;
	struct querystruct *limit_record;
	
	unsigned int src;
	unsigned int dst;
	unsigned int counter;
	
	GHashTable *ranges;
	unsigned int *pz;
	
	unsigned int flag;
	
	data = NULL;
	counter = 0;
	flag = 0;
	
	limit_record = malloc(sizeof(struct querystruct));
	limit_record->tend = 0;
	
	ranges  = g_hash_table_new (g_str_hash,g_str_equal);
	
	get_ranges_by_boxname (ranges, PATHBOXES);

	pz = g_hash_table_lookup (ranges,srcbox);
	
	if (pz == NULL)
	{
		fprintf (stderr,"Box %s does not exist.\n",srcbox);
		return (0);
	};
	
	src = *(int *)pz;
	
	pz = g_hash_table_lookup (ranges,dstbox);
		
	if (pz == NULL)
	{
		fprintf (stderr,"Box %s does not exist.\n",dstbox);
		return (0);
	};	
	
	dst = *(int *)pz;
	
	/*Query the DB*/
	sprintf (query,"SELECT Records.aspathid, Records.tstart, Records.tend, Records.numrec, ASpaths.len, ASpaths.path FROM Records, ASpaths WHERE Records.src=%u AND Records.dst=%u AND  Records.aspathid=ASpaths.id AND ((Records.tstart BETWEEN %u AND %u) OR (%u BETWEEN Records.tstart AND Records.tend+%u)) ORDER BY Records.tstart",
	src,dst,(unsigned int)(t_start),(unsigned int)(t_end),(unsigned int)(t_start),TIME_LIMIT);
	
	// printf ("%s\n",query);
	// tt01.ripe.net tt47.ripe.net 960900000 961000000

	if (mysql_query(mysql,query))
	{
		fprintf(stderr, "MySQL query error: %s\n", mysql_error(mysql));
		return (0);
	};   

	if (!(result = mysql_use_result(mysql)))
	{
		fprintf(stderr, "MySQL Result error: %s\n", mysql_error(mysql));
		mysql_free_result(result);	
		return (0);
	};

	/* Set return params - add new element to Buffers */
	while ((row = mysql_fetch_row(result)))
	{
		if ((atoi(row[1]) < (unsigned int)(t_start)) &&
		((atoi(row[2]) + TIME_LIMIT) > (unsigned int)(t_start)) &&
		(atoi(row[2]) > (unsigned int)(limit_record->tend)))
		{			
			limit_record->aspathid = atoi(row[0]);
			limit_record->tstart  = atoi(row[1]);
			limit_record->tend    = atoi(row[2]);
			limit_record->numrec  = atoi(row[3]);
			limit_record->next    = NULL;
			
			limit_record->ashops = compress_aspath(row[5],
							limit_record->aspath);
			
			continue;
		};
		
		if ((atoi(row[1]) < (unsigned int)(t_start)) ||
		(atoi(row[1]) > (unsigned int)(t_end))) { continue; };
		
		current = malloc(sizeof(struct querystruct));
		current->aspathid = atoi(row[0]);
		current->tstart  = atoi(row[1]);
		current->tend    = atoi(row[2]);
		current->numrec  = atoi(row[3]);
		current->next    = NULL;
				
		current->ashops = compress_aspath(row[5], current->aspath);
		
		if (data == NULL)
		{
			data = current;
		}
		else
		{
			index = data;
			
			while (index->next != NULL)
			{
				index = index->next;
			};
			
			index->next = current;
		};
		
		if (++counter > 10 * MAX_QUERY_LINES)
		/* we compress to ASpaths, be generous on query lines */
		{
			flag = 1;
			break;
		};
	};
	
	/* limit_record was not used ? */
	if (limit_record->tend == 0)
	{
		free(limit_record);
	}
	else
	{
		/* Append limit_record at the beginning of data */
		limit_record->next = data;
		data = limit_record;
	};
	
	index = data;
	if (index != NULL) {

		/* merge records with identical compressed ASpath */

		while ((next = index->next) != NULL)
		{
			if ( (strcmp(index->aspath, next->aspath) == 0) &&
				(next->tstart < index->tend + TIME_LIMIT) )
			{

				/* combine the two records */
				index->numrec += next->numrec;
				index->tend = next->tend;
				index->next = next->next;
				free(next);
			}
			else
			{
				index = index->next;
			}
		}		
	}

	index = data;
	while (index != NULL)
	{
		printf ("%s %s %d %d %d %d %d %s\n",srcbox,dstbox,index->tstart,index->tend,index->aspathid,index->ashops,index->numrec,index->aspath);	
		index = index->next;
	};		
	
	
	if (flag)
	{
		printf (".%u\n",MAX_QUERY_LINES);
	}
	else
	{
		printf (".\n");
	};
	
	mysql_free_result(result);

	return (1);

};

int main (int argc, char *argv[])
{
	MYSQL mysql;
	struct querystruct *data;
	char *src, *dst, *host;
	unsigned int tstart, tend;
	int ip6flag = 0;

	data = NULL;

	/* Parse arguments */

        if ((argc < 5) || (argc > 7)) 
        { 
                fprintf (stderr,"Usage: %s [-6] <source> <destination> <starttime> <endtime> [MySQL host]\n",argv[0]); 
                exit (1); 
        };

	if (strcmp(argv[1], "-6") == 0) {
		ip6flag = 1;
		argv++;
		argc--;
	}

	src = argv[1];
	dst = argv[2];
	tstart = atoi(argv[3]);
	tend = atoi(argv[4]);

	if (argc == 6) {
		/* we should check if the argument makes sense as a hostname */
		/* future version ...  */
		host = argv[5];
	}
	else {
		host = MYSQL_HOST;
	}

	/* process request */

	if (!ip6flag) {
		open_user_connection (&mysql, host);
	}
	else {
		open_user_connection_ip6 (&mysql, host);
	}
	
	if (!match_aspath_by_time(&mysql,src,dst,tstart,tend,data))
	{
		fprintf (stderr,"match_aspath_by_time: Cannot send query.\n");
		exit (1);
	};

	mysql_close(&mysql);

	return (0);
};
