node* lista_to_array(node *lista, int qtd_nos) {

	node *array = calloc(qtd_nos, sizeof(node));

	node *p = lista;
	node *q = NULL;
	node *r = array;

	while (p != NULL) { // transferindo os elementos
		q = p;
		r->simbolo = p->simbolo;
		r->ocorrencias = p->ocorrencias;
		r->frequencia_relativa = p->frequencia_relativa;
		r++;
		p = p->prox;
		free(q);
	}

	iniciar_lista(lista);
	return array;
}
int main(int argc, char *argv[])
{
	No *ptr_lista;
	int valor_insercao;
	int i;

	imprimir_cabecalho();

	printf("Informe o valor que deseja inserir na cabeca da lista:\n");
	scanf("%d",&valor_insercao);
	putchar('\n');

	ptr_lista = (No*)malloc(sizeof(No));
	iniciar_lista(ptr_lista);

	for(i = 0; i < 5; i ++)
	{
		inserir_cabeca(ptr_lista, i);
	}

	printf("Ate o presente momento, a lista possui os seguintes valores:\n");
	putchar('\n');

	imprimir_lista(ptr_lista);

	printf("Com o valor que voce informou, a lista esta da seguinte maneira:\n");
	putchar('\n');

	inserir_cabeca(ptr_lista,valor_insercao);

	imprimir_lista(ptr_lista);

	printf("Obrigado por utilizar o programa.\n");
	putchar('\n');

	free(ptr_lista);

	return 0;
}
node* array_to_lista(node **array, int qtd_nos) {

	node *lista, *p = *array;
	iniciar_lista(&lista);

	if (array == NULL) {
		return NULL;
	}else {
		int i;
		for (i = 0; i < qtd_nos; i++) {
			node *n = calloc(1, sizeof(node));
			n->simbolo = p[i].simbolo;
			n->ocorrencias = p[i].ocorrencias;
			n->frequencia_relativa = p[i].frequencia_relativa;
			n->prox = NULL;
			inserir_no_final(&lista, n);
		}
	}

	free(*array);
	return lista;
}
int main(int argc, char *argv[]) {

	if(argc != 2) {
		printf("Parametros inválidos.\n");
		exit (EXIT_FAILURE);
	}

	char *inpath = argv[1];

	FILE *infile;
	if ((infile = fopen(argv[1], "rb")) == NULL) {
		printf("O arquivo não pode ser aberto.\n");
		exit(EXIT_FAILURE);
	}

	// encontrando a última "\" ou "/" do path
	char *final_path = NULL;
	final_path = strrchr(inpath, '/');
	if (final_path == NULL) {
		*final_path = strrchr(inpath, '\\');
	}

	// definindo o path do arquivo de saída para o mesmo do arquivo de entrada
	char outpath[TAMANHO_MAX_PATH] = "";
	strncpy(outpath, inpath, (strlen(inpath) - strlen(final_path) + 1));

	// juntando o path ao nome do arquivo .huff para abrí-lo
	char outfile_huff_path[TAMANHO_MAX_PATH + TAMANHO_MAX_NOME_ARQUIVO] = "";
	strcat(outfile_huff_path, outpath);
	strcat(outfile_huff_path, "arquivo_comprimido.huff");
	FILE *outfile_huff;
	if ((outfile_huff = fopen(outfile_huff_path, "wb")) == NULL) {
		printf("O arquivo de saída não pode ser criado.\n");
		exit(EXIT_FAILURE);
	}

	// juntando o path ao nome do arquivo .huftab para abrí-lo
	char outfile_huftab_path[TAMANHO_MAX_PATH + TAMANHO_MAX_NOME_ARQUIVO] = "";
	strcat(outfile_huftab_path, outpath);
	strcat(outfile_huftab_path, "arquivo_comprimido.huftab");
	FILE *outfile_huftab;
	if ((outfile_huftab = fopen(outfile_huftab_path, "wb")) == NULL) {
		printf("O arquivo de saída não pode ser criado.\n");
		exit(EXIT_FAILURE);
	}

	node *lista;
	iniciar_lista(&lista);

	char simbolo;
	int total_simbolos = 0;
	while (!feof(infile)) {
		fread(&simbolo, sizeof(char), 1, infile);
		reportar_ocorrencia(&lista, simbolo);
		total_simbolos++;
	}

	int qtd_simbolos = contar_simbolos(lista);
	lista = ordenar_lista(&lista, qtd_simbolos);

	// resgatando nome do arquivo
	char nome_arquivo[TAMANHO_MAX_NOME_ARQUIVO] = "";
	strcpy(nome_arquivo, ++final_path);

	// persistindo nome do arquivo, total de símbolos e tabela de ocorrências
	int i;
	for (i = 0; i < TAMANHO_MAX_NOME_ARQUIVO; i++) {
		fwrite(&nome_arquivo[i], sizeof(char), 1, outfile_huftab);
	}
	fwrite(&total_simbolos, sizeof(int), 1, outfile_huftab);
	fwrite(&qtd_simbolos, sizeof(int), 1, outfile_huftab);
	node *array = lista_to_array(lista, qtd_simbolos);
	for (i = 0; i < qtd_simbolos; i++) {
		fwrite(&array[i], sizeof(node), 1, outfile_huftab);
	}

	lista = array_to_lista(&array, qtd_simbolos);
	setar_frequencias(&lista, total_simbolos);

	tabela = calloc(qtd_simbolos, sizeof(node_table));
	fim_tabela = tabela;

	node *arvore = gerar_arvore(&lista);

	char vazio[TAMANHO_MAX_CODIGO] = "";
	gerar_codigos(arvore, vazio);

	// resetando o arquivo de entrada
	rewind(infile);

	codificar_arquivo(infile, outfile_huff, outfile_huftab);

	long size_infile = ftell(infile) + 1;
	long size_outfile_huftab = ftell(outfile_huftab) + 1;
	long size_outfile_huff = ftell(outfile_huff) + 1;
	double taxa_compressao = 100 - ((double)size_outfile_huff / size_infile) * 100;

	printf("O arquivo foi compactado com sucesso.\n");
	printf("Tamanho do arquivo de entrada: %d bytes\n", size_infile);
	printf("Tamanho do arquivo comprimido com a tabela: %d bytes\n", size_outfile_huftab);
	printf("Tamanho do arquivo comprimido sem a tabela: %d bytes\n", size_outfile_huff);
	printf("Taxa de compressão: %.2f%\n", taxa_compressao);


	fclose(infile);
	fclose(outfile_huff);
	fclose(outfile_huftab);
	exit(EXIT_SUCCESS);
}