#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <assert.h>
#define test
//#undef test

#include "table.h"
#include "parser.h"

typedef struct elem_hitlist* hitlistptr;
typedef struct elem_diz_loc* dizptr;
typedef struct info_link* inflinkptr;
typedef struct info_ipertesto* infiperptr;

//inizializzazioni strutture (costruttori)
//INFO IPERTESTO
infiperptr iniz_info(){
           infiperptr t;
           t=(infiperptr) malloc(sizeof(infiperptr));
           t->diz_loc=NULL;
           t->lista_in=NULL;
           t->lista_out=NULL;
           t->page_rank=0;
           return t;
}
//DIZIONARIO (inserisce in coda le informazioni)
dizptr insert_diz(dizptr diz){
       dizptr t;
       if(diz==NULL){ 
          t=(dizptr) malloc(sizeof(dizptr));
          t->parola=NULL;
          t->next_word=NULL;
          t->hitlist=NULL;
          t->dim=0;
          return t;}
       diz->next_word=(dizptr) malloc(sizeof(dizptr));
       return diz;
}
//HITLIST  (inserisce in testa le informazioni)
hitlistptr insert_hitlist(hitlistptr hit){
           hitlistptr t;
           if(hit==NULL){
              t=(hitlistptr) malloc(sizeof(hitlistptr));
              t->next_elem=NULL;
              t->info_occ_word=NULL;
              return t;}
           t=hit;
           hit=(hitlistptr) malloc(sizeof(hitlistptr));
           hit->next_elem=t;
           return hit;
}
//INFO LINK (inserisce in testa le informazioni)
inflinkptr insert_link(inflinkptr linkptr){
           inflinkptr t;
           if(linkptr==NULL){
              t=(inflinkptr) malloc(sizeof(inflinkptr));
              return t;}
           t=linkptr;
           linkptr=(inflinkptr) malloc(sizeof(inflinkptr));
           linkptr->next=t;
           return linkptr;
}
//******************************************************************************
//******************************************************************************

///////////////////////////////////////////////////////////////////////////////
//ritorna NULL se la ricerca è fallita;
//ritorna il nodo trovato se la ricerca è andata a buon fine

inflinkptr cerca_linklist(inflinkptr linkptr,char*s){
           if(linkptr==NULL) return NULL;
           if(s==(linkptr->ptr_pagina->key))//CONTROLLARE
              return linkptr;
           return cerca_linklist(linkptr->next,s);
}

/*ritorna NULL se la ricerca è fallita;
 *ritorna il nodo della lista con il file cercato
 *se la ricerca è andata a buon fine*/
struct tabelem* cerca_file(struct telist* ls,char* s){
       assert(s!=NULL);
       if(ls==NULL){
          printf("pagina non trovata");
          return NULL;}
       if(((ls->el)->key)==s)
          return ls->el;
       return cerca_file(ls->next,s);
} 
/*Se non ci sono state operazioni ritorna NULL
  altrimenti ritorna il numero delle operazioni fatte*/
int grafin(struct tabelem* tab, struct table* t, inflinkptr out){
    //dichiarazioni
    inflinkptr in;
    infiperptr iper;
    struct tabelem* temp;
    struct tabelem** tab2;
    //PREC
    assert(tab!=NULL);
    assert(t!=NULL);
    //Condizione uscita ricorsione
    if(out==NULL) 
       return 0;
    //operazioni ricorsive
    //temp=cerca_file(t->ls,(out->ptr_pagina)->key);
    //Versione che usa table serch
    //+ veloce ma nn so se funziona...
    temp=table_search(t,(out->ptr_pagina)->key);
    iper=temp->info;
    in=(iper->lista_in);
    in=insert_link(in);
    (in->ptr_pagina)=tab;
    in->molteplicita=out->molteplicita;
    iper->lista_in=in;
    temp->info=iper;
    (*tab2)=temp;
    return (1+ grafin(tab,t,out->next));
}
         
    
    

inflinkptr grafout(infiperptr iper,struct info_word* word,struct table* t){
           //Dichiarazioni
           inflinkptr linkptr=iper->lista_out,linkptr2;
           //Precondizioni
           assert(iper!=NULL);
           assert(word!=NULL);
           assert(t!=NULL);
           //controllo se c'è già l'elemento cercato
           linkptr2=cerca_linklist(linkptr,word->file_link);
           if(linkptr2==NULL){ //ricerca nn riuscita
              if(linkptr==NULL) //controllo se link sia vuoto...se si creo un'elemento
                 linkptr=insert_link(linkptr);
              linkptr->molteplicita=1; //ho creato solo 1 elemento
              //linkptr->ptr_pagina=cerca_file(t->ls,word->file_link);
              //Versione + rapida che cerca nella hashtable
             linkptr->ptr_pagina=table_search(t,word->file_link);
           }//fine creazione nuovo elemento
           else //aggiornamento lista dei link
           linkptr2->molteplicita=(linkptr2->molteplicita)+1;//aggiorno la molteplicità (aggiungo
                                                             //solo un nuovo elemento
           return linkptr;
}

dizptr cercadiz(dizptr diz,char*s){
       if(diz==NULL) return NULL; //condizione di uscita
       if(s==diz->parola) //la parola è stata trovata; restituisco il nodo
          return diz;
       return cercadiz(diz->next_word, s);
}

dizptr DizList(dizptr diz, char* key,infiperptr* iper,struct table* t){
       //dichiarazioni
       FILE* f;
       dizptr temp2,temp=diz;
       struct info_word* word;
       hitlistptr hit=NULL;
       //PREC: key=!NULL
       assert(key!=NULL);
       //Se il dizionario punta a NULL (nn esiste)
       if(diz==NULL)
          diz=insert_diz(diz); //Creo il dizionario vuoto
       //apertura file
       f=fopen(key,"r");
       if(f==NULL){
          printf("impossibile aprire il file");
          return NULL;
       }
       //inizio ciclo
       while((word=next_word(f))!=NULL){
             //word=next_word(f);
             if((word->file_link)!=NULL) //se la word letta è un link implementa il grafo dei link out
                 (*iper)->lista_out=grafout((*iper),word,t);
             temp2=cercadiz(diz,word->parola);
             if(temp2==NULL){ //nuova parola (nessuna occorrenza precedente)
                if((temp->next_word==NULL) && (word!=NULL))   // viene creato un nuovo nodo solo se nn 
                    temp->next_word=calloc(1,sizeof(dizptr));//si stà compiendo l'ultimo ciclo
                temp->parola=word->parola; //viene riempito il campo parola
                hit=insert_hitlist(hit);
                temp->hitlist=hit;
                hit->info_occ_word=word;//riempito il campo info occ word di hitlist
                temp->dim=1;           //viene creata una hitlist con un solo elemento!
                temp=temp->next_word; // incremento il puntatore alla coda della lista
                }//fine operazioni x nuova parola
             else{ /*se ci sono + occorrenze di una parola nel file 
                    lavoro con temp2 cercato prima; che indica l'elemento dove è collocata
                    la parola che si ripete*/
                 hit=temp2->hitlist;       //hit corrisponde alla testa della hitlist
                 hit=insert_hitlist(hit);  //inserisco in testa alla hitlist un nuovo elemento
                 hit->info_occ_word=word; //riempio il campo word dell'elemento appena creato
                 temp2->dim=(temp2->dim)+1; //viene incrementata la hitlist solo di un'elemento
             }//fine operazioni x parola già incontrata
       }//chiusura ciclo
       fclose(f); //chiusura file
       return temp;
}
//////////////////////////////////////////////////////////////////////////////////////

void create_diz_ipertesti(struct table *ptb){
     //Dichiarazioni
     struct tabelem* tab;
     struct telist* list;
     infiperptr iper=NULL;
     dizptr diz=NULL;
     list=ptb->ls;
     int i=0;
     //Ciclo creazione info ipertesto x tutti i file
     while(list!=NULL){             
             tab=list->el;
             iper=iniz_info();//inizializzo la struttura info
             //devo fare un cast x trasformare il campo info?!?!?!
             tab->info=iper;
             iper->diz_loc=DizList(diz,tab->key,&iper,ptb);
             if(iper->diz_loc==NULL){//controllo se è stato creato il dizionario locale
                 printf("errore nella creazione del dizionario locale per il file\n\n%s",tab->key);
                 return;}
             list=list->next; //incremento il puntatore che scorre la lista
     }//chiusura while
     list=ptb->ls;
     while(list!=NULL){
           tab=list->el;
           iper=tab->info;
           i=grafin(tab,ptb,iper->lista_out);
           if(i=0 && (iper->lista_out)!=NULL){
              printf("errore nella creazione della lista_in del grafo\
                      del file %s",(list->el)->key);
              break;}
           list=list->next;
     }   
}

main(){
#ifdef test
 char* s;
 struct table* t;
 printf ("Inserire percorso e nome della directory di lavoro :");
  scanf("%s",s);
 t=create_node_table(s);
 create_diz_ipertesti(t);
 getch();
#endif
getch();
 return;    
}

