#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <gtk/gtk.h>
#include "main.h"


/* reads lines from a file and stores them in a GList */
GList * get_items_from_file(char *file) {
	FILE *fp ;
	char *a, *c, bufor[BUFSIZ] ;
	GList *res ;
	int i = 0 ;

	if( !(fp = fopen(file, "r")) ) {
		say(0, "cannot open %s", file) ;
		return NULL ;
	}

	res = NULL ;

	/* reading file line by line */
	while( fgets(bufor, BUFSIZ, fp) ) {
		i++ ;
		/* skipping blanks and comments */
		if(*bufor == '\n' || *bufor == '#') continue ;
		if( (c = strchr(bufor, '\n')) ) *c = '\0' ;
		a = my_strdup(bufor) ;
		res = g_list_append(res, a) ;
	}

	say(0, "%i entries read from file %s", i, file) ;
	fclose(fp) ;
	return res ;
}


/* save a GList to a file */
int put_items_to_file(char *file, GList *list, int items) {
	char *tmp ;
	FILE *fp ;
	int i, j, k, l ;

	/* open the file */
	if( !(fp = fopen(file, "w")) ) {
		say(0, "Could not open file %s for writing", file) ;
		return EXIT_FAILURE ;
	}

	say(0, "....") ;

	/* how many *last* items to write. (items == 0) => all */
	l = g_list_length(list) ;
	if(l > items && items != 0) 
		j = (l - items) ; 
	else 
		j = 0 ;

	for(i = j, k = 0; i < l ; i++, k++) {
		tmp = g_list_nth_data(list, i) ;
		fprintf(fp, "%s\n", tmp) ;
	}

	say(0, "put_items_to_file: wrote %i items", k) ;
	fclose(fp) ;
	return EXIT_SUCCESS ;	
}


/* scans a line for a key, and returns what follows next */
char *find_key(char *line, char *key) {
	char *res, *tmp ;

	res = NULL ;
	while(isspace(*line)) line++ ;
	
	if( (tmp = strchr(line, '\n')) ) *tmp = '\0' ;

	if( (tmp = strstr(line, key)) ) {
		res = my_strdup(tmp + strlen(key)) ;
	} 
	
	return res ;
}


/* read options from a file pointer */
int read_options(char *fname, opt_s *o) {
	char bufor[BUFSIZ], *tmp, *val, *p ;
	FILE *fp ;
	int i ;

	if( !(fp = fopen(fname, "r")) ) {
		say(0, "cannot open file %s", fname) ;
		return EXIT_FAILURE ;
	}
	
	say(0, "reading options from file %s", fname) ;
	while( (tmp = fgets(bufor, BUFSIZ, fp)) ) {

		while(isspace(*tmp)) tmp++ ;
		if(*tmp == '\n' || *tmp == '#') continue ;

		if( (p = strchr(tmp, '\n')) ) *p = '\0' ;

		if( (val = find_key(tmp, "file_history_size=")) ) {
			o->file_history_size = atoi(val) ;
			say(0, "file_history_size = %i", o->file_history_size) ;
			free(val) ;
		}

		if( (val = find_key(tmp, "hide_tooltips=")) ) {
			i = !atoi(val) ;
			if(i != o->show_tooltips) {
				say(0, "show_tooltips status changed") ;
				o->show_tooltips = i ;
			}

			say(0, "show_tooltips = %i", o->show_tooltips) ;
			free(val) ;
		}

		if( (val = find_key(tmp, "command_history_size=")) ) {
			o->command_history_size = atoi(val) ;
			say(0, "command_history_size = %i", o->command_history_size) ;
			free(val) ;
		}

		if( (val = find_key(tmp, "font_name_default=")) ) {
			if(o->font_name_default) free(o->font_name_default) ;
			o->font_name_default = val ;
			say(0, "font_name_default = %s", o->font_name_default) ;
			if(o->font_name) free(o->font_name) ;
			o->font_name = my_strdup(val) ;
			if( !(o->czcionka = gdk_font_load(o->font_name)) )
				say(0, "Cannot load font %s", o->font_name) ;
		}

		if( (val = find_key(tmp, "external_editor=")) ) {
			if(o->external_editor) free(o->external_editor) ;
			o->external_editor = val ;
		}

	}

	return EXIT_SUCCESS ;
}


/* write options to a file pointer */
int write_options(char *file, opt_s *o) {
	FILE *fp ;

	if( !(fp = fopen(file, "w")) ) {
		say(0, "file %s cannot be opened", file) ;
		return EXIT_FAILURE ;
	}

	fprintf(fp, "# configuration file, automagically created by Arka\n"
		"# do not modify -- it gets overwritten anyway each time Arka exits\n\n") ;

	fprintf(fp, "file_history_size=%i\n", o->file_history_size) ;
	fprintf(fp, "command_history_size=%i\n", o->command_history_size) ;
	fprintf(fp, "font_name_default=%s\n", o->font_name_default) ;
	fprintf(fp, "hide_tooltips=%i\n", !(o->show_tooltips)) ;
	fprintf(fp, "external_editor=%s\n", o->external_editor) ;

	fclose(fp) ;
	return EXIT_SUCCESS ;
}


/* ------------------- write / parse rcfile and history files ---------- */
/* writes the new configuration file */
int write_rcfile(opt_s *o) {
	char *rcfile, *rcdir ;

	if(! (rcdir = my_strdup(getenv("HOME"))) ) {
		say(0, "$HOME variable absent") ;
		return EXIT_FAILURE ;
	}
	
	rcdir = realloc(rcdir, strlen(rcdir) + strlen(ARKA_DIR) + 1) ;
	strcat(rcdir, ARKA_DIR) ;
	rcfile = malloc(strlen(rcdir) + 50) ;

	/* saves command history */
	strcpy(rcfile, rcdir) ;
	strcat(rcfile, "/command_history") ;

	if(o->command_history) {
		say(0, "saving command history...") ;
		put_items_to_file(rcfile, o->command_history, o->command_history_size) ;
	} else {
		say(0, "no command history recorded") ;
	}

	/* saves file history */
	strcpy(rcfile, rcdir) ;
	strcat(rcfile, "/file_history") ;

	if(o->file_history) {
		say(0, "saving file history...") ;
		put_items_to_file(rcfile, o->file_history, o->file_history_size) ;
	} else {
		say(0, "no file history recorded") ;
	}

	/* saving options */
	strcpy(rcfile, rcdir) ;
	strcat(rcfile, "/configuration") ;

	write_options(rcfile, o) ;

	strcpy(rcfile, rcdir) ;
	strcat(rcfile, "/shortcuts") ;
	gtk_item_factory_dump_rc(rcfile, NULL, TRUE) ;

	free(rcdir) ;
	free(rcfile) ;
	say(0, "configuration saved succesfully") ;
	return EXIT_SUCCESS ;
}


/* reads the configuration file */
int read_rcfile(opt_s *o) {
	char *rcfile, *rcdir ;
	struct stat statbuf ;

	say(0, "reading configuration") ;

	/* getting rc directory */
	if(! (rcdir = my_strdup(getenv("HOME"))) ) {
		say(0, "$HOME not present. No configuration file read") ;
		return EXIT_FAILURE ;
	}

	rcdir = realloc(rcdir, strlen(rcdir) + strlen(ARKA_DIR) + 1) ;
	strcat(rcdir, ARKA_DIR) ;

	/* checking rc directory */
	if( stat(rcdir, &statbuf) < 0) { /* cannot stat rcdir */
	
		if(demand("Arka configuration directory is not present."
			"\nShould I create it for you?")) { /* ask user to confirm creation */

			/* creating directory with umask rwxr-xr-x */
			if(mkdir(rcdir, S_IRWXU | 00050 | 00005) < 0) {	
				/* checking whether mkdir worked */
				komunikat("Creating %s failed", rcdir) ;
				return EXIT_FAILURE ;
			}

		} else { /* user did not agree to create the configuration directory */
			return EXIT_FAILURE ;
		}

		if(demand("I think you use arka for the first time.\n"
			"May I send an empty letter to january@bioinformatics.org?\n"
			"Just to let the author know that there are people interested in arka")) {

			fprintf(stderr, "Executing\n"
				"echo  | mail -s arka_user genpak@localhost\n") ;
			system("echo | mail -s arka_user" AUTHOR_EMAIL) ;
			say(0, "Thank you a lot!") ;
		} else {
			say(0, "You will regret it one day.") ;
		}

	} else {
		if(!S_ISDIR(statbuf.st_mode)) { /* can stat rcdir, but is not a directory */
			komunikat("%s exists, but it is not a directory.\n"
				"Remove it if you plan to use a configuration file", rcdir) ;
			return EXIT_FAILURE ;
		}
	}

	say(0, "configuration directory %s found", rcdir) ;
	rcfile = malloc(strlen(rcdir) + 50) ;

	/* reading command history */
	strcpy(rcfile, rcdir) ;
	strcat(rcfile, "/command_history") ;
	o->command_history = get_items_from_file(rcfile) ;

	/* reading file history */
	strcpy(rcfile, rcdir) ;
	strcat(rcfile, "/file_history") ;
	o->file_history =  get_items_from_file(rcfile) ;

	/* reading configuration */

	/* global configuration file */
	read_options(ARKA_GLOBAL, o) ;

	/* user configuration file */
	strcpy(rcfile, rcdir) ;
	strcat(rcfile, "/configuration") ;

	read_options(rcfile, o) ;

	strcpy(rcfile, rcdir) ;
	strcat(rcfile, "/shortcuts") ;
	gtk_item_factory_parse_rc(rcfile) ;

	free(rcdir) ;
	free(rcfile) ;
	say(0, "configuration read succesfully") ;
	
	return EXIT_SUCCESS ;
}
