
/*  CPS372 - Link State Routing Simulation
 *  Programming Assignment #2 
 *
 *  Helper code to parse event files.
 *
 */
#include <stdio.h>
#include <stdlib.h>

/*  Maximum expected input/output line length.  */
#define MAXLINE 10000


/* There are 3 distinct events in our simulation */
typedef enum {
    EVENT_INIT,
    EVENT_LSP,
    EVENT_UFWD,
} e_type;

/* An LSP pair consists of a host and a distance */
typedef struct {
    int host;
    int distance;
} lsp_pair;


/* An event consists of many fields (not all used by all events) 
 *    - an integer timestamp
 *    - a  type
 *    - a  host ID
 *    - a  sequence number 
 *    - an array of lsp_pairs 
 */
typedef struct {
    int        timestamp;
    e_type     type;
    int        unihost;
    int        seqno;
    lsp_pair  *pairs;
    int        num_pairs;
} EVENT;


/* Parse the next event from the input file and return it.                  */ 
/* Return zero on success and -1 on failure or when end-of-file is reached. */ 
/* Note:  There may be garbage in unused fields of a particular event       */

int parse_event (FILE *infp, EVENT *the_main_event) {

    char  line[MAXLINE]; 
    char  first_char = '\0';

    int   offset, i;   /* helpers for parsing */
    int   more_offset;
    int   left_brace_count;
    
    while (fgets (line, MAXLINE, infp) != NULL) {

	/* Skip blank lines and comments */
        if ((sscanf (line, " %c", &first_char) == 0) || 
	       (first_char == '#') ||
	       (first_char == '\0')) {
	    continue;
	}

	/* Parse a real input line */
	else if (sscanf (line, " %d F %d ", &the_main_event->timestamp,
		&the_main_event->unihost) == 2) {

            /* Unicast forwarding event */
	    the_main_event->type = EVENT_UFWD;
	    return 0;
	}
	else {

	    /* Initialization, link-state packet, or garbage */

	    if (sscanf (line, "%d I %d%n", &the_main_event->timestamp,
		    &the_main_event->unihost, &offset) == 2) {

		/* Initialization*/
		the_main_event->type = EVENT_INIT;
	    }
	    else if (sscanf (line, "%d L %d %d%n", &the_main_event->timestamp,
		    &the_main_event->unihost,
		    &the_main_event->seqno, &offset) == 3) {

		/* Initialization*/
		the_main_event->type = EVENT_LSP;
	    }
	    else 
		return -1;

	    /* Now, munge through the lsp-pairs        */
	    /* This is somewhat painful, so don't look */

	    /* Count the left braces, so we know how much space to allocate */
	    the_main_event->num_pairs = 0;
	    for (i = offset; line[i] != '\0'; i++) {
		if (line[i] == '<') {
		    the_main_event->num_pairs++;
		}
	    }
	    the_main_event->pairs =  (lsp_pair *)
		    calloc (sizeof(lsp_pair), the_main_event->num_pairs);

	    i = 0;
	    while (sscanf (&line[offset], " <%d, %d >%n",
		    &(the_main_event->pairs[i].host), 
		    &(the_main_event->pairs[i].distance),
		    &more_offset) == 2) {

		i++;
		offset += more_offset; 
	    }
	    return 0; 
	}
    }
    return -1;
}


/*  This is just to test the parsing of events.  Once you are
 *  convinced that the parser works correctly, this can be
 *  ignored.
 */
void dump_event(EVENT evt) 
{
    int i;

    switch (evt.type) {
       case EVENT_UFWD:  
	    printf ("UFWD, host = %d\n", evt.unihost);
	    break;
       case EVENT_INIT:  
       case EVENT_LSP:  
	    if (evt.type == EVENT_INIT) {
	        printf ("INIT, id = %d, ", evt.unihost);
	    }
	    else {
		printf ("LSP, source = %d, seqno = %d, ", evt.unihost, evt.seqno);
	    }
	    printf ("PAIRS = "); 
	    for (i = 0; i < evt.num_pairs; i ++) {
		printf ("<%d, %d> ", evt.pairs[i].host, evt.pairs[i].distance);
	    }
	    printf ("\n");
	    break;

	default:
	    printf ("ERROR: Invalid event parsed. \n");
    }
}


/*  Parse events and dump them to stdout */ 
int main (void) 
{
    EVENT evt;
    
    while (parse_event (stdin, &evt) != -1) {
	dump_event(evt);
    }
    return 0;
}
