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


/* returns the actual filename from a filename with path */
char *file_basename(char *filenam) {
	char *res ;

	if( (res = strrchr(filenam, '/')) ) return (res + 1) ; 
	else return filenam ;

}

/* reads the specified file into the specified window */
int read_file(FILE *fp, opt_s *o, okno_s *okno, int color) {
	GdkColor *gdkcol = NULL ;
	char bufor[BUFSIZ] ;
	int chars = 0 ;

	say(0, "read_file: warming up") ;
	if(color >= 0) gdkcol = &o->colors[color] ;

	/* if overwrite mode is set for a given window, delete the existing text */
	if(okno->overwrite) gtk_editable_delete_text(GTK_EDITABLE(okno->tekst), 0, -1) ;


	say(0, "read_file: freezing tekst") ;
	gtk_text_freeze(GTK_TEXT(okno->tekst)) ;

	say(0, "read_file: getting buffer") ;
	while(fgets(bufor,BUFSIZ,fp) != NULL) {
		chars += strlen(bufor) ;

		switch(*bufor){
			case '#':
				gdkcol = &o->colors[2] ;
				break;
			case '>':
				gdkcol = &o->colors[1] ;
				break ;
			default:
				gdkcol = NULL ;
				break ;
		}
		gtk_text_insert(GTK_TEXT(okno->tekst), o->czcionka, 
			gdkcol, NULL, bufor, strlen(bufor)) ;	
	}

	say(0, "read_file: thawing tekst") ;
	gtk_text_thaw(GTK_TEXT(okno->tekst)) ;
	okno->changed = TRUE ;

	say(0, "%i chars read", chars) ;
	if(chars == 0) return EXIT_FAILURE ;

	say(0, "goin' back") ; 
	say(0, "read_file: end") ;
	return EXIT_SUCCESS ; 
}


/* reads the content of a temporary file into the specified window */
int file_to_window(opt_s *o, okno_s *win, int color) {
	FILE *fp ;
	int res = 0 ;

	if( (fp = fopen(win->tmpfil, "r")) == NULL ) {
		say(0, "file_to_window: cannot open %s", win->tmpfil) ;
		return EXIT_FAILURE ; 
	}

	res = read_file(fp, o, win, color) ;
	fclose(fp) ;
	return res ;
}


/* `prints' the content of a text window into a specified file pointer */
int print_file(FILE *fp, opt_s *o, okno_s *okno) {
	char *bufor ;
	int lzn, a ;

	bufor = gtk_editable_get_chars(GTK_EDITABLE(okno->tekst), 0, -1) ;
	lzn = strlen(bufor) ;
	a = fwrite(bufor, 1, lzn, fp) ;
	g_free(bufor) ;

	if(a != lzn) {
		komunikat("Error while writing file\n") ;
		return EXIT_FAILURE ;
	}

	return EXIT_SUCCESS ;

}


/* writes the contents of a window into a temporary file */
int window_tofile(okno_s *okno, opt_s *o) {
	char *bufor ;
	int lzn, a ;
	FILE *fp ;

	if(okno->tekst != NULL) 
		bufor = gtk_editable_get_chars(GTK_EDITABLE(okno->tekst),
			0, -1) ;
	lzn = strlen(bufor) ;

	if( (fp = fopen(okno->tmpfil, "w")) == NULL) {
		komunikat("Cannot open temporary %s file for writing.\n"
		"This probably means serious problems with this program", okno->tmpfil) ;
		return EXIT_FAILURE;
	}

  a = fwrite(bufor, 1, lzn, fp) ;
	fclose(fp) ;

  if(a != lzn) {
		komunikat("Error while writing temporary %s file.\n"
		"This probably means serious problems with this program", okno->tmpfil) ;
		return EXIT_FAILURE;
	}

	g_free(bufor) ;
	return EXIT_SUCCESS ;
}


/* gets the name from the file_selection dialog */
void file_get_name_read(GtkWidget *k, gpointer dane) {
	GtkWidget *okno ;
	data_s *d ;
	char * n ;

	d = (data_s *) dane ;
	okno = d->data ;
	n = gtk_file_selection_get_filename(GTK_FILE_SELECTION(okno)) ;
	d->data1 = strdup(n) ;
	gtk_widget_destroy(okno) ;

}


/* destroys the file dialog */
void file_get_name_destroy(GtkWidget *k, gpointer dane) {
	GtkWidget *okno ;

	okno = (GtkWidget *) dane ;
	gtk_grab_remove(okno) ;
	gtk_main_quit() ;
}


/* select file dialog */
char *file_get_name(opt_s *o, char *default_name) {

	GtkWidget *okno ;
	data_s d ;
	char *res, *dir, *tmp ;

	say(0, "file_get_name start") ;
	okno = gtk_file_selection_new("Select file") ; 

	if(default_name)
		gtk_file_selection_set_filename(GTK_FILE_SELECTION(okno), default_name) ;
	else if(o->wdir)
		gtk_file_selection_set_filename(GTK_FILE_SELECTION(okno), o->wdir) ;

	d.data = okno ;
	d.data1 = NULL ;

	gtk_signal_connect(GTK_OBJECT(okno), 
		"destroy", GTK_SIGNAL_FUNC(file_get_name_destroy), okno) ;
	gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(okno)->cancel_button),
		"clicked", (GtkSignalFunc) close_dialog, okno) ;
	gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(okno)->ok_button),
		"clicked", (GtkSignalFunc) file_get_name_read, &d) ;

	gtk_widget_show(okno) ;
	gtk_grab_add(okno) ;
	gtk_main() ;

	res = (char *) d.data1 ;

	if(res) {
		tmp = strdup(res) ;

		if(tmp && (dir = strrchr(tmp, '/')) ) {
			if(o->wdir) free(o->wdir) ;
			*(dir + 1) = '\0' ;
			o->wdir = strdup(tmp) ;
			free(tmp) ;
		}

	}

	say(0, "file_get_name: got %s", res) ;

	return res ;
}


/* reads a filename into the input window. Called from anywhere */
int file_open_from_name(opt_s *o, int signal, char *filenam){
	FILE *fp ;
	char tmp[FILENAME_MAX] ;
	okno_s *okno = &o->panels[signal] ;

	say(0, "file_open_from_name: warming up.") ;
	say(0, "opening %s", filenam) ;

	if(! (fp = fopen(filenam, "r")) ) {
		komunikat("Cannot open file %s for reading", filenam) ;
		return EXIT_FAILURE ;
	}

	okno->filenam = filenam ;
	read_file(fp, o, okno, -1) ;
	fclose(fp) ;

	/* updating frame title */
	sprintf(tmp, "%s: %s", okno->title, file_basename(filenam)) ;
	gtk_frame_set_label(GTK_FRAME(okno->ramka), tmp) ;

	return EXIT_SUCCESS ;

}


/* opens a file from the file history list. Called from the menu */
void file_open_from_list(gpointer dane, guint signal, GtkWidget *kontrolka) {
	okno_s *okno ;
	opt_s * o ;
	char *filenam, tmp[FILENAME_MAX] ;
	int i ;
	FILE *fp ;

	o = (opt_s *) dane ;
	okno = &o->panels[0] ; /* stdin window */

	if(! (filenam = g_list_nth_data(o->file_history, signal)) ) {
		say(0, "file no. %i not found", signal) ;
		return ;
	}

	/* updating statusbar */
	i = gtk_statusbar_get_context_id(GTK_STATUSBAR(o->status), "open file") ;
	gtk_statusbar_pop(GTK_STATUSBAR(o->status), i) ;


	if(! (fp = fopen(filenam, "r")) ) {
		komunikat("Cannot open file %s for reading", filenam) ;
		return ;
	}

	okno->filenam = filenam ;
	read_file(fp, o, okno, -1) ;
	fclose(fp) ;

	/* updating frame title */
	sprintf(tmp, "%s: %s", okno->title, file_basename(filenam)) ;
	gtk_frame_set_label(GTK_FRAME(okno->ramka), tmp) ;

	/* updating statusbar */
	sprintf(tmp, "File %s loaded in \"%s\"", file_basename(filenam), okno->title ) ;
	gtk_statusbar_push(GTK_STATUSBAR(o->status), i, tmp) ;

	if(!o->file_history || strcmp( (g_list_last(o->file_history))->data, filenam)) {
		o->file_history = g_list_append(o->file_history, filenam) ;
		append_single_entry(o, filenam, -1) ;
	} else {
		okno->filenam = (char *) (g_list_last(o->file_history))->data ;
	}

}


/* opens the "open file" dialog */
void file_open(gpointer dane, guint signal, GtkWidget *kontrolka) {
	okno_s *okno ;
	opt_s * o ;
	char *filenam, tmp[FILENAME_MAX] ;
	int i, exit = FALSE ;
	FILE *fp ;

	say(0, "file_open: signal %i", signal) ;
	o = (opt_s *) dane ;

	/* updating statusbar */
	i = gtk_statusbar_get_context_id(GTK_STATUSBAR(o->status), "open file") ;
	gtk_statusbar_pop(GTK_STATUSBAR(o->status), i) ;

	/* which text window are we talking about? */
	okno = &o->panels[signal] ;

	/* repeatedly querying the user */
	while(!exit) {
		filenam = file_get_name(o, okno->filenam) ;

		if(!filenam) {
			printf("Exiting without opening\n") ;
			return ;
		}
			
		exit = TRUE ;

		if(! (fp = fopen(filenam, "r")) ) {
			komunikat("Cannot open file %s for reading", filenam) ;
			exit = FALSE ;
		} else say(0, "file_open: reading %s", filenam) ;
	}

	okno->filenam = filenam ;
	read_file(fp, o, okno, -1) ;
	fclose(fp) ;

	/* updating frame title */
	sprintf(tmp, "%s: %s", okno->title, file_basename(filenam)) ;
	gtk_frame_set_label(GTK_FRAME(okno->ramka), tmp) ;

	/* updating statusbar */
	sprintf(tmp, "File %s loaded in \"%s\"", file_basename(filenam), okno->title ) ;
	gtk_statusbar_push(GTK_STATUSBAR(o->status), i, tmp) ;
	
	if(!o->file_history) say(0, "File history empty") ;

	/* update file history */
	if(!o->file_history || strcmp((g_list_last(o->file_history))->data, filenam) ) {
		o->file_history = g_list_append(o->file_history, filenam) ;
		append_single_entry(o, filenam, -1) ;
	} else {
		okno->filenam = (char *) (g_list_last(o->file_history))->data ;
		g_free(filenam) ;
	}

}


/* called in emergencies */
char* file_save_lowlevel(opt_s *o, int signal, char *filenam) {
	okno_s *okno ;
	FILE *fp ;
	int exit = FALSE ;
	struct stat fs ;

	okno = &o->panels[signal] ;

	/* if no filename is given, ask the user for one */
	if(filenam == NULL) {
		while(!exit){

			filenam = file_get_name(o, okno->filenam) ;

			if(!filenam) {
				say(0, "Exiting without saving\n") ;
				return NULL ;
			}
			
			exit = TRUE ;
	
			if(!stat(filenam, &fs) &&
				!demand("File %s exists. \nReally overwrite?", filenam) ) exit = FALSE ;
		}
	}

	printf("saving to %s\n", filenam) ;

	/* trying to open a file */
	if(!(fp = fopen(filenam, "w")) ) {
		komunikat("I cannot open file %s for writing.", filenam) ;
		return NULL ;
	}

	print_file(fp, o, okno) ;
	fclose(fp) ;

	return filenam ;
}


/* opens the "save as" dialog. Signal shows which window is to be saved */
void file_save_as(gpointer dane, guint signal, GtkWidget *kontrolka) {
	okno_s *okno ;
	opt_s * o = (opt_s *) dane ;
	char *filenam, tmp[FILENAME_MAX] ;
	int i ;

	/* updating statusbar */
	i = gtk_statusbar_get_context_id(GTK_STATUSBAR(o->status), "open file") ;
	gtk_statusbar_pop(GTK_STATUSBAR(o->status), i) ;

	/* which panel to use */
	okno = &o->panels[signal] ;
	
	filenam = file_save_lowlevel(o, signal, NULL) ;

	/* updating frame title */
	if(filenam) {
		sprintf(tmp, "%s: %s", okno->title, file_basename(filenam)) ;
		gtk_frame_set_label(GTK_FRAME(okno->ramka), tmp) ;
		sprintf(tmp, "Saved \"%s\" to file %s", okno->title, file_basename(filenam) ) ;
		gtk_statusbar_push(GTK_STATUSBAR(o->status), i, tmp) ;
	}

	/* updating statusbar */
}


/* save the contents of a window into the current file */
void file_save(gpointer dane, guint signal, GtkWidget *kontrolka) {
	okno_s *okno ;
	opt_s * o = (opt_s *) dane ;
	int i ;

	okno = &o->panels[signal] ;

	/* if we haven't saved output yet, call save_as */
	if(!okno->filenam) {
		file_save_as(dane, signal, kontrolka) ;
		return ;
	}

	file_save_lowlevel(o, signal, okno->filenam) ;

	/* updating statusbar */
	i = gtk_statusbar_get_context_id(GTK_STATUSBAR(o->status), "open file") ;
	gtk_statusbar_pop(GTK_STATUSBAR(o->status), i) ;
	gtk_statusbar_push(GTK_STATUSBAR(o->status), i, "Saved") ;
}


