#include "headers.h"
#include "packman.h"

void count_headers(wdir,hdirs)
char wdir[];
struct hdir_in **hdirs;
{
  DIR *dp;
  struct dirent *ep;
  FILE *fildes;
  int wdirlen;
  struct hdir_in *hd_aux = NULL;
  char path[256];
  char linebuffer[1024];
  char key_name[256];
  u_int16_t fnumber;
  u_int16_t layer;
  
  *hdirs = NULL;
  wdirlen = strlen(wdir);
  dp = opendir(wdir);
  memcpy(path,wdir,wdirlen);
  if (dp != NULL){
    while(ep = readdir(dp)){
      if(ep->d_type == (char)8){
        memset(path+wdirlen,0,256 - wdirlen);
	path[wdirlen] = '/';
        memcpy(path+wdirlen+1,ep->d_name,strlen(ep->d_name)+1);
        fildes = fopen(path,"r");
        if(fscanf(fildes,"#PACKMAN HEADER: %[^ ] LAYER %d\n",key_name,&layer)){
          while(fscanf(fildes,"#%[^\n]\n",linebuffer));
	  fnumber = 0;
          while(fscanf(fildes,"%[^\n]\n",linebuffer)!=EOF) ++fnumber;
	  hd_aux = (struct hdir_in *)malloc(sizeof(struct hdir_in));
          hd_aux->hfpath = (char*)malloc(strlen(path)+1);
          memcpy(hd_aux->hfpath,path,strlen(path)+1);
          hd_aux->hname = (char*)malloc(strlen(key_name)+1);
	  memcpy(hd_aux->hname,key_name,strlen(key_name)+1);
	  hd_aux->layer = layer;
          hd_aux->nof = fnumber;
	  hd_aux->next = *hdirs;
	  *hdirs = hd_aux;
        }
        fclose(fildes);
      }
    }
    closedir(dp);
  }else
    puts ("Couldn't open the directory.");
}

struct header_info **mount_field_table(path,nof)
char *path;
u_int16_t nof; /* Number of fields */
{
  struct header_info **hinf;
  int i,aux;
  u_int16_t max,avail,numkey,place;
  FILE *fildes;
  char fname[256];
  char linebuffer[256];
  u_int32_t off;
  u_int32_t siz;
  u_int32_t swp;
  
  fildes = fopen(path,"r");
  while(fscanf(fildes,"#%[^\n]\n",linebuffer)); 
  /* 3 times the number of fields */
  max = 3*nof;
  hinf = (struct header_info **)malloc(max*sizeof(struct header_info *));
  memset(hinf,0,max*sizeof(struct header_info*));
	      
  for(i=0;i<nof;i++){
    memset(fname,0,256);
    fscanf(fildes,"%s %d %d %d\n",fname,&off,&siz,&swp);
//  printf("\t%s\t (off)%.3d (siz)%.3d (swp)%d",fname,off,siz,swp);
    numkey = string2int(fname);
    place = mid_square(numkey, digits(max))%max;
    avail = 0;
    while(!avail){
      if(hinf[place]==NULL){
        avail = 1;
      }else{
//       place++;
//       place %=max;
	 ++numkey;
	 place = mid_square(numkey, digits(max))%max;
	 avail = 0;
       }
    }
//  printf(" placed @%d\n",place);
    
    hinf[place] = (struct header_info*)malloc(sizeof(struct header_info));
    aux = (strlen(fname)+1)*sizeof(char);
    hinf[place]->fname	= (char*)malloc(aux);
    memcpy(hinf[place]->fname,fname,aux);
    hinf[place]->offset = off;
    hinf[place]->size   = siz;
    hinf[place]->swap 	= swp;
  }
  
  fclose(fildes);
  return hinf;
}

struct header_hash_table **mount_header_table(hd,noh)
struct hdir_in *hd;
u_int16_t noh;		/* Number of headers */
{
  FILE *fides;
  int i,avail,aux;
  u_int16_t numkey,place,max;
  struct hdir_in *hdaux = hd;
  struct header_hash_table **head_hash;
  
  /* 3 times the number of headers  */
  max = 3*noh;
  aux = max*sizeof(struct header_hash_table *);
  head_hash = (struct header_hash_table **)malloc(aux);
  memset(head_hash,0,aux);
  for(i=0;i<noh;i++){
    avail = 0;
    numkey = string2int(hdaux->hname);
    place = mid_square(numkey, digits(max))%max;
    while(!avail){
      if(head_hash[place] == NULL){
        avail = 1;
      }else{
        avail = 0;
//      place++;
//      place %= max;
        ++numkey;
        place = mid_square(numkey, digits(max))%max;
       }
    }  
    head_hash[place] = (struct header_hash_table *)malloc(sizeof(struct header_hash_table));
    aux = (strlen(hdaux->hname)+1)*sizeof(char);
    head_hash[place]->hname = (char**)malloc(aux);
    memcpy(head_hash[place]->hname,hdaux->hname,aux);
    head_hash[place]->layer = hdaux->layer;
    head_hash[place]->nof  = hdaux->nof;
    head_hash[place]->hinf = mount_field_table(hdaux->hfpath,hdaux->nof);
//  printf("%s header placed @%d\n\n",hdaux->hname,place);
  
    hdaux = hdaux->next;
  }
  return head_hash;
}
  
struct header_info *gimme_the_data(hname,fname,hdrtable,noh,layer)
char				*hname;		/* in  */
char				*fname;		/* in  */
struct header_hash_table 	**hdrtable;	/* in  */
u_int16_t			noh;		/* in  */
u_int16_t			*layer;		/* out */
{
  u_int16_t numkey,hplace,fplace,max;
  int cntrl,match;
  
  max = 3*noh;
  numkey = string2int(hname);
  hplace = mid_square(numkey, digits(max))%max;
  cntrl = 0;
 
  if(hdrtable[hplace])
    match = !strcmp(hname,(char*)(hdrtable[hplace]->hname));
  else
    return NULL;
  while(!match){
//    ++hplace;
//    hplace %= max;
      ++numkey;
      hplace = mid_square(numkey, digits(max))%max;		      
    ++cntrl;
    if(cntrl==max) return NULL;
    if(hdrtable[hplace])
       match = !strcmp(hname,(char*)(hdrtable[hplace]->hname));
     else
       return NULL;      
  }
//printf("HEADER: match!\n");
  max = 3*hdrtable[hplace]->nof;
  numkey = string2int(fname);
  fplace = mid_square(numkey, digits(max))%max;
  cntrl = 0;

  if(hdrtable[hplace]->hinf[fplace])
    match = !strcmp(fname,hdrtable[hplace]->hinf[fplace]->fname);
  else
    return NULL;

  while(!match){
//  ++fplace;
//  fplace %= max;
    ++numkey;
    fplace = mid_square(numkey, digits(max))%max;
    ++cntrl;
    if(cntrl==max) return NULL;
    if(hdrtable[hplace]->hinf[fplace]){
      match = !strcmp(fname,hdrtable[hplace]->hinf[fplace]->fname);
    }else
      return NULL;      
  }
//printf("FIELD: match!\n");
  *layer = hdrtable[hplace]->layer;
  return hdrtable[hplace]->hinf[fplace];
}

u_int16_t count_noh(struct hdir_in *hd){
  u_int16_t cnt=0;
  struct hdir_in *aux = hd;
  while(aux != NULL){
    ++cnt;
    aux = aux->next;
  }
  return cnt;
}

void show_hash_table(struct header_hash_table **hdrtable, u_int16_t noh){
  int i,j;
  for(i=0;i<3*noh;i++){
    if(hdrtable[i] !=  NULL){
      printf("[%d]->(%s)(layer %d)(nof %d){\n",i,hdrtable[i]->hname,\
		                                 hdrtable[i]->layer,\
						 hdrtable[i]->nof);
      for(j=0;j<3*hdrtable[i]->nof;j++){
        if(hdrtable[i]->hinf[j] != NULL){
          printf("\t\t[%d]->(%s)(offset %d)(size %d)(%s)\n",j,\
		                            hdrtable[i]->hinf[j]->fname,\
					    hdrtable[i]->hinf[j]->offset,\
					    hdrtable[i]->hinf[j]->size,\
					    hdrtable[i]->hinf[j]->swap?"swap":"don't swap");
	}else
          printf("\t\t[%d]-> NULL\n",j);
      }
      printf("}\n");
    }else
      printf("[%d]->NULL\n",i);
  }
}
