%{
#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>
#include "../proto_util.h"
#include "../kernel.h"
#include "../headers.h"
#include "../arch.h"
#include "packit.h"

extern  int		p_lineno;
extern  char		*yytext;
extern  FILE		*yyin;

char			header_dir[256];        /* Headers definition directory
						*/
struct hdir_in		*hd;                    /* Internal header directory structure
						*/
u_int16_t		noh             = 0;    /* Number of headers loaded (header section)
						*/
u_int16_t		nop		= 0;	/* Number of packets
						*/
struct header_hash_table **head_hash;           /* Header definition hash table
                                                */
struct header_info	*finfo;			/* Information returned by gimme_the_data
						*/
u_int16_t		layer;			/* Header layer
						*/
u_int16_t		aux;
int			len_off;		/* Offset of the length information
						*/
int 			i;

struct pack		*the_pack = NULL, *the_pack_aux = NULL, *the_pack_pivot;

struct pack_vect	*out_packs;

char			*q;

struct fields_list {
  char			field[256];
  u_int32_t		info;
  struct fields_list 	*next;
} *f_list = NULL, *f_list_aux = NULL, *f_list_pivot, *f_back;

struct layers_list {
  char  		hdr[256];
  struct fields_list 	*fields;
  struct layers_list 	*next;
} *l_list = NULL, *l_list_aux = NULL, *l_list_pivot, *l_back;

%}

%type	<yyint> info expression

%union {
  u_int32_t	yyint;
  char		*yystr;
  int		yyaddr[4];
}

%token	NUMBER EXPR STR ADDR BYTES
%token	PACKET OPEN_BRACE CLOSE_BRACE OPEN_BRACK CLOSE_BRACK LAYER HEADER HEADERS
%token	LOAD OUT_PACK_FILE

%type	<yyaddr> ADDR
%type   <yyint> NUMBER
%type	<yystr> STR EXPR

%%

start: statement {
         printf("ok!\n");
       }
     ;

statement: OUT_PACK_FILE ':' EXPR OPEN_BRACE p_expression CLOSE_BRACE {
	     printf("%d packets\n",nop);
	     //put_in_a_file("out_pack",the_pack,nop);
	     //out_packs = load_packs("out_pack");
	     //show_packs(out_packs,nop);
	     exit(0);
	   }
         | load_h {
	   }
         ;

p_expression: expression {
                printf("one more pack...\n");
                ++nop;
	      }
            | expression p_expression {
	        printf("one more pack...\n");
	        ++nop;
	      }
            ;
						      
expression: PACKET '#' NUMBER OPEN_BRACE layers_e CLOSE_BRACE {
              the_pack_aux = (struct pack*)malloc(sizeof(struct pack));
              memset(the_pack_aux,0,sizeof(struct pack));
	      the_pack_aux->id = $3;
	      while(l_list != NULL){
	        printf("%s\n",l_list->hdr);
		f_list = l_list->fields;
		while(f_list != NULL){
  	 	  if(head_hash == NULL){
                    yyerror("C'mon LOAD the headers!!");
		    exit(0);
                  }else{
                     finfo = gimme_the_data(l_list->hdr,f_list->field,head_hash,noh,&layer);
                     if(!strncmp("hlen",finfo->fname,4) && layer < 3)
                       the_pack_aux->layer[layer] = f_list->info << 2+3; // (off<<2)*8bits
                     if(finfo->swap){
                       if(finfo->size <= 16)
                         f_list->info = htons(f_list->info);
                       else{
                         f_list->info = htonl(f_list->info);
		       }
		     }
		     printf("info(%#.8x) offset(%.4d) size(%.3d)\n",\
		            f_list->info,\
/*Debug area!!*/            finfo->offset+the_pack_aux->layer[layer-1],\
			    finfo->size);
		     pack_it(the_pack_aux->data,\
		             f_list->info,\
		             finfo->offset+the_pack_aux->layer[layer-1],\
			     finfo->size);
                     the_pack_aux->psize += finfo->size;
		     f_list_aux = f_list;
		     f_list = f_list->next;
		     free(f_list_aux);
                   }
                }
		l_list_aux = l_list;
		l_list = l_list->next;
		free(l_list_aux);
		l_list_aux = NULL;
	      }
              for(i=0;i<64;i+=2){
/*Debug Area*/      printf("%c%.2x%.2x",(i%16)?(' '):('\n'),the_pack_aux->data[i]\
		                                       ,the_pack_aux->data[i+1]);
	      }
	      f_list_aux = NULL;
	      l_list_aux = NULL;
	      l_list = NULL;
	      f_list = NULL;
  
	      the_pack_pivot = the_pack;
              if(the_pack_pivot != NULL){
	        while(the_pack_pivot->next != NULL)
                  the_pack_pivot = the_pack_pivot->next;
		the_pack_pivot->next = the_pack_aux;
	      }else
	         the_pack = the_pack_aux;
              the_pack_aux->next = NULL;
              the_pack_aux = NULL;
              //printf("\n2send: %d\n",20+((*(the_pack.data+32))>>2)&0x3f);
	      //send_it(the_pack.data,40,the_pack.data+16);
	    }
          ;
	  
load_h:  LOAD HEADERS ':' EXPR {
	   memset(header_dir,0,256);
	   memcpy(header_dir,$4,(strlen($4))%256);
	   count_headers(header_dir,&hd);
	   noh = count_noh(hd);
	   head_hash = mount_header_table(hd,noh);
         }
      ;

layers_e: layers
	| layers_e layers

layers: HEADER ':' STR OPEN_BRACE fields_e CLOSE_BRACE {
	  l_list_aux = (struct layers_list*)malloc(sizeof(struct layers_list));
          memcpy(l_list_aux->hdr,$3,strlen($3)%256+1);
          l_list_aux->fields = f_list;
          l_list_pivot = l_list;
          if(l_list_pivot != NULL){
            while(l_list_pivot->next != NULL)
              l_list_pivot = l_list_pivot->next;
              l_list_pivot->next = l_list_aux;
          }else
             l_list = l_list_aux;
          l_list_aux->next = NULL;
          f_list = NULL;
          f_list_aux = NULL;
        }
      ;

fields_e: fields
	| fields_e fields
	;

fields: STR info {
	  f_list_aux = (struct fields_list*)malloc(sizeof(struct fields_list));
	  memcpy(f_list_aux->field,$1,strlen($1)%256+1);
	  f_list_aux->info = $2;
	  f_list_aux->next = NULL;
	  f_list_pivot = f_list;
	  if(f_list_pivot != NULL){
	    while(f_list_pivot->next != NULL)
	      f_list_pivot = f_list_pivot->next;
	    f_list_pivot->next = f_list_aux;
	  }else
	    f_list = f_list_aux;
	  f_list_aux->next = NULL;
	}
      ;

info: NUMBER {
        $$ = $1;
      }
    | ADDR {
        if($1[0]<256 && $1[1]<256 && $1[2]<256 && $1[3]<256){
	  $$ = 0;
	  $$ |= $1[0];
	  $$ <<=8;
	  $$ |= $1[1];
	  $$ <<=8;
	  $$ |= $1[2];
	  $$ <<=8;
	  $$ |= $1[3];
	}
      }
    ;
%%

int main(int argc, char **argv){
  FILE *file;

  if(argc > 1){
    file = fopen(argv[1],"r");
    yyin = file;
  }else
    yyin = stdin;
 
   while(1) {
     yyparse();
   }
 
  return 0;
}

yyerror(s)
char *s;
{
  fprintf(stderr, "%d: %s at %s\n",p_lineno , s, yytext);
}
