#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define TAM_MAX_PALAVRA 256
#define TAM_MAX_INDICE 256
#define MAX_PALAVRAS 256
#define TAM_MAX_LINHA 256

struct palavra_indice{char palavra[TAM_MAX_PALAVRA];
                      int lin;
                      int col;};

struct indice{int num_elem;
              struct palavra_indice entrada[TAM_MAX_INDICE];
             };

struct lista_palavras{
                      int num_elem;
                      char palavras[MAX_PALAVRAS][TAM_MAX_PALAVRA];
                     };

int le_linha(FILE *f, char *linha, int n){
    char c;
    int i;

    for (i=0; (i<n) && ((c=fgetc(f))!=EOF) && (c!='\n');i++){
        linha[i] = c;
    }

    if (c=='\n'){
        linha[i] = '\n';
        i++;
    }

    linha[i] = '\0';

    return i;

}


void ler_arq_palavras(char *nome_arq, struct lista_palavras *lst){
    FILE *f = fopen(nome_arq,"r");

    if (!f){return;}

    lst->num_elem = 0;

    while (le_linha(f,lst->palavras[lst->num_elem],TAM_MAX_PALAVRA))
    {
        int tam = strlen(lst->palavras[lst->num_elem]);

        // remove os \n
        if (lst->palavras[lst->num_elem][tam-1]=='\n'){
            lst->palavras[lst->num_elem][tam-1]='\0';
        }

        lst->num_elem++;


    }
    fclose(f);
}

int busca_palavra(const char *palavra, struct lista_palavras lst){
    int pos = -1;

    for (int i=0;i<lst.num_elem;i++){
        if (strcmp(palavra,lst.palavras[i])==0){
            return i;
        }
    }
    return pos;
}

void insere_indice_palavras(struct indice *indice, char *palavra, int lin, int col){

    int i = 0;

    for (i=0; i<indice->num_elem && strcmp(indice->entrada[i].palavra,palavra)<0;i++);

    // Se for igual a alguma palavra já existente no indice retorne
    if (strcmp(indice->entrada[i].palavra,palavra)==0){return;}

    // Mover de trás para frente os elementos nas posicoes após o elemento maior que o desejado
    for (int j = indice->num_elem;j>i;j--){
            indice->entrada[j] = indice->entrada[j-1];
    }

    // Efetuar as atribuições para a entrada
    strcpy(indice->entrada[i].palavra,palavra);
    indice->entrada[i].lin = lin+1;
    indice->entrada[i].col = col+1;

    indice->num_elem++;

}


int eh_caracter_valido(char c){
    return c!=' ' && c!='.' && c!=',' && c!=';' && c!=':' && c!='?' && c!='!' && c!='-'  && c!='\n';
}

int get_palavra(char *linha, char *palavra, int *col, int *pos){
    int i = 0;

    //pula espaços e pontuação
    while (linha[*pos]!='\0' && !eh_caracter_valido(linha[*pos])){
        (*pos)++;
    }
    *col = *pos;

    // copia os caracteres validos para uma palavra
    while (linha[*pos]!='\0'){
        if (eh_caracter_valido(linha[*pos])){
            palavra[i] = linha[*pos];
            (*pos)++;
            i++;
        }
        else{
            break;
        }
    }
    //Insere o terminador de string
    if(i>0){
        palavra[i] = '\0';
    }

    return i;
}

void criar_indice(char *nome_arq, struct indice *indice_palavras, struct lista_palavras palavras){
    FILE *f;
    char linha[TAM_MAX_LINHA];
    char palavra[TAM_MAX_PALAVRA];

    f = fopen(nome_arq,"r");

    if (!f){return;}

    int lin = 0;

    while(le_linha(f,linha,TAM_MAX_LINHA)>0){
        printf("    0000000000111111111222222222233333333334444444445555555555566666666667\n");
        printf("    1234567890123456789012345678901234567890123456789012345678901234567890\n");
        printf("--------------------------------------------------------------------------\n");
        printf("%3d %s",lin+1,linha);
        printf("--------------------------------------------------------------------------\n");

        int pos=0;
        int col=0;

        // Enquanto houver uma nova palavra começando na posição col a partir de posição atual pos
        while(get_palavra(linha,palavra,&col,&pos)){
            printf("    %s lin:%d col:%d\n",palavra,lin+1,col+1);
            // Insira a palavra no indice se ela for uma importante
            if (busca_palavra(palavra,palavras)!=-1){
                insere_indice_palavras(indice_palavras,palavra,lin,col);
            }
        }
        lin++;
        printf("--------------------------------------------------------------------------\n");
    }

    fclose(f);
}

int buscar_pos_indice(struct indice indice, char *palavra){
    int pos = -1;

    for (int i=0;i<indice.num_elem;i++){
        if (strcmp(palavra,indice.entrada[i].palavra)==0){
            return i;
        }
    }
    return pos;
}

void imprimir_indice(struct indice indice_palavras){
    printf("--------------------------------------------------------------------------\n");
    printf("Indice da primeira ocorrencia das palavras importantes:\n");
    printf("--------------------------------------------------------------------------\n");
    for (int i=0;i<indice_palavras.num_elem;i++){
        printf("%s lin:%d col:%d\n",indice_palavras.entrada[i].palavra,indice_palavras.entrada[i].lin,indice_palavras.entrada[i].col);
    }
    printf("--------------------------------------------------------------------------\n");
}

void codificar(struct indice indice, char * frase, char * frase_cod){
    char palavra[TAM_MAX_PALAVRA];
    char str_lin[TAM_MAX_PALAVRA];
    char str_col[TAM_MAX_PALAVRA];

    int pos=0;
    int col=0;
    int pos_indice;


    // Enaquanto houver uma palavra a ser codificada
    while(get_palavra(frase,palavra,&col,&pos)){
        // Encontra a posicao no indice
        pos_indice = buscar_pos_indice(indice,palavra);
        // Monte uma string com o código dado por linha e coluna se a palavra existir no indice
        if (pos_indice!=-1){
            sprintf(str_lin,"%d",indice.entrada[pos_indice].lin);
            sprintf(str_col,"%d",indice.entrada[pos_indice].col);
            strcat(frase_cod,str_lin);
            strcat(frase_cod," ");

            strcat(frase_cod,str_col);
            strcat(frase_cod," ");
        }
        else{
            strcat(frase_cod,"0");
            strcat(frase_cod," ");
            strcat(frase_cod,"0");
            strcat(frase_cod," ");
        }
    }

}

int main()
{

    struct lista_palavras palavras;
    struct indice indice_palavras;

    indice_palavras.num_elem = 0;
    palavras.num_elem = 0;
    char frase_cod[TAM_MAX_LINHA];

    ler_arq_palavras("palavras.txt",&palavras);
    criar_indice("texto.txt",&indice_palavras,palavras);
    imprimir_indice(indice_palavras);

    codificar(indice_palavras,"I am a child of the universe",frase_cod);
    printf("frase codificada: %s\n",frase_cod);

    //Limpar o array de caracteres já usado
    strcpy(frase_cod,"");
    codificar(indice_palavras,"you are a profound triumph",frase_cod);
    printf("frase codificada: %s\n",frase_cod);

    return 0;
}
