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

#include "common.h"


/*///////// GLOBAIS LOCAIS ///////////////////////////////////////////////// */

/* o fd do arquivo */
FILE * from = NULL;

/* o padrão */
unsigned char* pattern = NULL;

/* ptr pra a função de procura */
t_find_func find_func = bmh_find;

/*ptr para a func. de preprocessamento do padrão*/
t_preprocess_pattern_func preprocess_func = bmh_preprocess_pattern;

int conf_line_numbers = 0;

int conf_k = 0;


/* ////// FUNCOES  //////////////////////////////////////////////////////// */
FILE *open_file (char *filename)
{
	FILE *fd;
	
	/*errno = 0;*/
	fd = fopen (filename, "r");
	if (fd == NULL) {
		fprintf (stderr,
			"%s: Não pude abrir o arquivo '%s': %s\n",
			PROG_NAME, filename, strerror (errno));
		exit (1);
	} else {
		return fd;
	}
}

void print_usage()
{
	printf("Uso: %s [opção] padrão arquivo\n",PROG_NAME);
	printf("Procura por PADRÂO em ARQUIVO.\n");
	printf("Exemplo: %s 'hello world' hello.c\n\n",PROG_NAME);
	printf("  -Ai\tEscolhe o algoritmo para busca exata.\n");
	printf("     \tValores para i: B - BMH(padrão); S - Shit-And exato\n");
	printf("  -#\tExecuta busca aproximada com # erros.\n");
	printf("  -n\tImprime o numero da linha onde ocorrer um casamento.\n");
}

void exit_insuficient_args()
{
	fprintf(stderr,
		"%s: Número insuficiente de argumentos.\n\n",
		PROG_NAME);
	print_usage();
	exit(1);
}

void exit_excess_args()
{
	fprintf(stderr,
		"%s: Número excessivo de argumentos.\n\n",
		PROG_NAME);
	print_usage();
	exit(1);
}

void exit_blah_args(unsigned char* blah, unsigned char* bleh)
{
	fprintf(stderr,
		"%s: %s%s\n\n",
		PROG_NAME,blah,bleh);
	print_usage();
	exit(1);
}


void parse_cmd_line(int argc, char * argv[])
{
	int i = 0;

	int exact_or_aprox = 0;
	
	if (argc < 3){
		exit_insuficient_args();
	}	

	i = 1;
	while (i < argc){
		/* Argumentos com '-' no inicio são tratados aqui*/
		if (argv[i][0] == '-'){
			switch (argv[i][1]){
				case '\0':
					exit_blah_args("Nao existe a opção vazia '-'\n","");
					break;
				case 'A':
					if (exact_or_aprox){
						exit_blah_args("Busca exata e aproximada não podem ocorrerm ao mesmo tempo.","");
					} else if (argv[i][2] == 'B'){
						exact_or_aprox=1;
						find_func=bmh_find;
						preprocess_func=bmh_preprocess_pattern;
					} else if (argv[i][2] == 'S'){
						exact_or_aprox=1;
						find_func=shiftand_exato_find;
						preprocess_func=shiftand_exato_preprocess_pattern;
					} else {
						exit_blah_args("A opção -A nao reconhece o comando ", &argv[i][2]);
					}/*case A*/
					break;
				case 'n':
					conf_line_numbers = 1;
					break;
				default:
					if (isdigit(argv[i][1]) && !(exact_or_aprox)){
							conf_k=atoi(&argv[i][1]);
							exact_or_aprox=1;
							find_func=shiftand_aprox_find;
							preprocess_func=shiftand_aprox_preprocess_pattern;
					}else if (isdigit(argv[i][1]) && (exact_or_aprox)){
						exit_blah_args("Busca exata e aproximada não podem ocorrerm ao mesmo tempo.","");
					} else {
							exit_blah_args("Argumento descohecido: ",argv[i]);
					};
					break;
			}/*switch...*/
		} else {
			/* Não é uma opção
			 * Então o proximo é o pattern e o seguinte o filename,
			 * se existirem. Não deve existir mais nada depois.*/
			if (i + 2 < argc ){
				exit_excess_args();
			} else	if (i + 1 < argc){
				pattern = strcpy_alloc(&pattern, argv[i]);
				from = open_file(argv[i+1]);
				i++;	/*Tratamos dois argumentos aqui */	
			} else {
				exit_insuficient_args();
		
			}
		} /* else if ... == '-' */
		i++;
	}/*while...*/
	
}



/* //// MAIN /////////////////////////////////////////////////////////////// */
int main (int argc, char* argv[])
{
	int lineno = 0;			/* # da linha */
	char line[MAX_LINE_SIZE];
	size_t len = 0;

	line[MAX_LINE_SIZE -1]= '\0'; /* Não custa evitar problemas... */
	
	parse_cmd_line(argc, argv);

	preprocess_func(pattern);
		
	while(!feof(from)){
		if ( fgets (line,MAX_LINE_SIZE,from) == NULL ){ 
			/* getline não é ANSI */
			/*EOF ou erro*/
			break;
		}
		
		lineno++;
		if (find_func(line,conf_k) >= 0 ){
			if (conf_line_numbers){
					printf ("%i:%s",lineno,line);
			} else {
					printf ("%s",line);
			}
		};
	}
	fclose(from);
}
