#include <stdio.h>
#include <arpa/inet.h>


/*
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <dirent.h>
#include <time.h>
*/


#define COMMAND_LENGTH	255
#define INFILE		file_to_be_read
#define OUTFILE		file_to_write


struct hop{
	struct in_addr ip;
	int hop_no;
	float_t latency;
	int MPLS;
};

struct trace{
	struct in_addr source;
	struct in_addr dest;
	int num_of_hops;
	struct hop h[30];
};

int num_of_traces=0; // num of traces in a file
int num_of_as=0;



void print_trace(const struct trace *t);
int read_trace(struct trace *t , FILE * inf);
void write_trace(const struct trace *t , FILE * outf);




// ---------------------------------------------
// information about binary files
// (see the print_trace function, and structs)
// e.g. on reading from the text file
// e.g. on writing to a binary file
// e.g. on reading from binary file
// ---------------------------------------------
int main(int argc, char **argv){

 struct trace t;

 inf = fopen(INFILE, "r");
 outf = fopen(OUTFILE, "w");
 if (inf == NULL)
   perror("Error opening IN FILE");
 else {
  while (!feof(inf)) {

    if(read_trace(&t,inf)){
      write_trace(&t,outf);
    }
  }
 }
 printf("[NUM_OF_VALID_TRACES]: %d, [NUM_OF_ASes]: %d\n",num_of_traces,num_of_as);
 rewind(outf);
 fwrite(&num_of_traces,sizeof(int),1,outf);
 fclose(inf);
 fclose(outf);
 return 0;
}




// ---------------------------------------------
// read from binary file and print
// ---------------------------------------------
void print_trace(const struct trace *t){
	int var;
	char ip[INET_ADDRSTRLEN];

	inet_ntop(AF_INET,&(t->source),ip,INET_ADDRSTRLEN);
	printf("source: [%s] ",ip);

	inet_ntop(AF_INET,&(t->dest),ip,INET_ADDRSTRLEN);
	printf("dest: [%s]\n",ip);

	for (var = 0; var < t->num_of_hops; ++var) {
		if(t->h[var].ip.s_addr != 0)
			inet_ntop(AF_INET,&(t->dest),ip,INET_ADDRSTRLEN);
		else
			strcpy(ip,"*");
		printf("[%d] [%s] [%.3f] [%d] \n",t->h[var].hop_no, ip, t->h[var].latency, t->h[var].MPLS);
	}
}




// ---------------------------------------------
// write a trace struct to a text file
// ---------------------------------------------
void write_trace(const struct trace * t, FILE * outfile){

	fwrite(&(t->source),sizeof(struct in_addr),1,outfile);
	fwrite(&(t->dest),sizeof(struct in_addr),1,outfile);
	fwrite(&(t->num_of_hops),sizeof(int),1,outfile);
	fwrite(&(t->h),(t->num_of_hops)*sizeof(struct hop),1,outfile);

}

// ---------------------------------------------
// read a trace from text file to trace struct
// ---------------------------------------------
int read_trace(struct trace *t, FILE * infile){

  int trace_completed=FALSE;
  int i,index;
  char line[COMMAND_LENGTH];
  struct in_addr temp;

  temp.s_addr = 0;
  bzero(t,sizeof(struct trace));

	while(!feof(infile)){

		fgets(line, COMMAND_LENGTH, infile);
		line[strlen(line) - 1] = '\0'; // fgets retains the NEWLINE

		//		if empty line, break the loop, if successfully read a trace return 1, else return 0
		if(strlen(line)<2){
			if(t->num_of_hops > 0 && t->source.s_addr != 0 ){
				num_of_traces++;
				return 1;
			}
			else
				return 0;
		}

		//if regular hops line
		if(line[1]<='9' && line[1]>='0' && t->source.s_addr != 0 ){
			t->h[t->num_of_hops].hop_no=atoi(line);
			if(line[4]=='*'){
				t->h[t->num_of_hops].ip.s_addr =  0;
				t->h[t->num_of_hops].latency = 0;
				t->h[t->num_of_hops].MPLS = 0;
			}else if(line[4]>='0' && line[4]<='9' ){

				for(i=4;line[i]!=' ';i++);
				line[i]='\0';
				inet_pton(AF_INET,&line[4],&(t->h[t->num_of_hops].ip));

				index=i+2;
				for(i=index;line[i]!=' ';i++);
				line[i]='\0';
				t->h[t->num_of_hops].latency = (float) atof(&line[index]);
			}

			(t->num_of_hops)++;
			if(t->num_of_hops > 30){
				return 0;
			}
//			printf("%s\n",line); //////////////////////////////////////////////////////////////////

		}//if MPLS
		else if(line[3]=='M' && t->source.s_addr != 0 ){
			t->h[t->num_of_hops-1].MPLS = atoi(&line[13]);
			if(t->h[(t->num_of_hops)-1].MPLS == 0 ){
				for(i=13;line[i]!='|';i++);
				i++;
				t->h[(t->num_of_hops)-1].MPLS = atoi(&line[i]);
			}

		} //		if new trace start line
		else if(line[0]=='t' && line[1]=='r'){
			if(t->source.s_addr != 0 )
				return 0;
			for(i=13;line[i]!=':';i++);
			line[i]='\0';
			inet_pton(AF_INET,&line[13],&(t->source));

			for(i++;line[i]!='(';i++);
			index=++i;
			for(i++;line[i]!=':';i++);
			line[i]='\0';
			inet_pton(AF_INET,&line[index],&(t->dest));
//			printf("%s\n",&line[index]); /////////////////////////////////////////////////////////////
		}else{
			if(line[0]=='#'){
				num_of_as++;
				//				printf("[NEW AS]: %s\n",line);
			}
			else{
//				printf("[UNDEFINED LINE]: %s\n",line);
				return 0;
			}

		}

	}

	if(t->num_of_hops > 0 && t->source.s_addr != 0 ){
			num_of_traces++;
			return 1;
		}
		else
			return 0;
}

