/* Snownews - A lightweight console RSS newsreader
 * $Id: main.c 1159 2005-09-13 19:51:13Z kiza $
 * 
 * Copyright 2003-2004 Oliver Feiler <kiza@kcore.de>
 * http://kiza.kcore.de/software/snownews/
 *
 * main.c
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */
 
#include <ncurses.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <signal.h>
#include <sys/wait.h>

#include "config.h"
#include "interface.h"
#include "ui-support.h"
#include "main.h"
#include "updatecheck.h"
#include "setup.h"
#include "io-internal.h"
#include "getopt.h"

extern struct feed *first_bak;		/* For use with the signal handler. */
static int const pid_file_create = 1;
static int const pid_file_delete = 0;

static int last_signal = 0;

int cursor_always_visible = 0;

void modifyPIDFile (int action) {
	char pid_path[512];
	FILE *file;
	
	snprintf(pid_path, sizeof(pid_path), "%s/.snownews/pid", getenv("HOME"));	
	if (action == pid_file_create) {
		file = fopen(pid_path, "w");
		if (file == NULL) {
			printf("Unable to write PID file %s!", pid_path);
			return;
		}
		fprintf(file, "%d", getpid());
		fclose(file);
	} else {
		unlink(pid_path);
	}
}

/* Deinit ncurses and quit. */
void MainQuit (const char * func, const char * error) {
	if (error == NULL) {
		/* Only save settings if we didn't exit on error. */
		WriteCache();
	}
	clear();
	refresh();
	endwin();		/* Make sure no ncurses function is called after this point! */
	
	modifyPIDFile(pid_file_delete);

	if (last_signal)
		printf ("Exiting via signal %d.\n", last_signal);
	
	if (error == NULL) {		
		printf (_("Bye.\n\n"));
		
		/* Do this after everything else. If it doesn't work or hang
		   user can ctrl-c without interfering with the program operation
		   (like writing caches). */
		AutoVersionCheck();
		
		exit(0);
	} else {
		printf (_("Aborting program execution!\nAn internal error occured. Snownews has quit, no changes has been saved!\n"));
		printf (_("This shouldn't happen, please submit a bugreport to kiza@kcore.de, tell me what you where doing and include the output below in your mail.\n"));
		printf ("----\n");
		/* Please don't localize! I don't want to receive Japanese error messages.
		 * Thanks. :)
		 */
		printf ("While executing: %s\n", func);
		printf ("Error as reported by the system: %s\n\n", error);
		exit(1);
	}
}

/* Signal handler function. */
void MainSignalHandler (int sig) {
	last_signal = sig;
	
	/* If there is a first_bak!=NULL a filter is set. Reset first_ptr
	   so the correct list gets written on the disk when exisiting via SIGINT. */
	if (first_bak != NULL)
		first_ptr = first_bak;
	MainQuit(NULL, NULL);
}

/* Automatic child reaper. */
void sigChildHandler (int sig) {
	int status, child_val;

	/* Wait for any child without blocking */
	if (waitpid(-1, &status, WNOHANG) < 0)
			return;

	if (WIFEXITED(status))
		child_val = WEXITSTATUS(status);
}

void printHelp (void) {
	printf (_("Snownews version %s\n\n"), VERSION);
	printf (_("usage: snownews [-huV] [--help|--update|--version]\n\n"));
	printf (_("\t--cursor-on|-c\tForce cursor always visible.\n"));
	printf (_("\t--help|-h\tPrint this help message.\n"));
	printf (_("\t--update|-u\tAutomatically update every feed.\n"));
	printf (_("\t--version|-V\tPrint version number and exit.\n"));
}
void badOption (const char * arg) {
	printf ("Option %s requires an argument.\n", arg);
}

int main (int argc, char *argv[]) {
#ifdef SIGWINCH
	struct sigaction act;
#endif

	int autoupdate = 0;		/* Automatically update feeds on app start... or not if set to 0. */
	int numfeeds;			/* Number of feeds loaded from Config(). */
	int i = 0;	
	char *arg;
	char *foo;
	
#ifdef LOCALEPATH
	setlocale (LC_ALL, "");
	bindtextdomain ("snownews", LOCALEPATH);
	textdomain ("snownews");
#endif
	
	if (argc > 1) {
//		printf ("=%d\n", argc);	
		i = 1;
		while (i < argc) {
			arg = argv[i];
			if (strcmp(arg, "--version") == 0 || strcmp(arg, "-V") == 0) {
				printf (_("Snownews version %s\n\n"), VERSION);
				return 0;
			} else if (strcmp(arg, "-u") == 0 || strcmp(arg, "--update") == 0) {
				autoupdate = 1;
				i++;
				continue;
			} else if (strcmp(arg, "-c") == 0 || strcmp(arg, "--cursor-on") == 0) {
				cursor_always_visible = 1;
				i++;
				continue;
			} else if (strcmp(arg, "--foo") == 0) {
				i++;
				if (i < argc) {
					foo = strdup(argv[i]);
					i++;
					continue;
				} else {
					badOption(arg);
					exit(1);
				}
			} else if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
				printHelp();
				return 0;
			} else {
				printf ("Unkown option given: \"%s\".\n", arg);
				printHelp();
				return 0;
			}
		}
	}
	
	/* Get fragged gracefully. */
	signal (SIGHUP, MainSignalHandler);
	signal (SIGINT, MainSignalHandler);
	signal (SIGTERM, MainSignalHandler);
	
	/* Un-broken pipify */
	signal (SIGPIPE, SIG_IGN);
	
	/* Call the reaper */
	signal (SIGCHLD, sigChildHandler);
	
#ifdef SIGWINCH
	/* Set up SIGWINCH handler */
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
	act.sa_handler = sig_winch;
	sigaction(SIGWINCH, &act, NULL);
#endif

	InitCurses();
	
	/* Check if configfiles exist and create/read them. */
	numfeeds = Config();
	
	/* Create PID file. */
	modifyPIDFile(pid_file_create);
		
	LoadAllFeeds (numfeeds);

	if (autoupdate)
		UpdateAllFeeds();
	
	/* Init the pRNG. See about.c for usages of rand() ;) */
	srand(time(0));
	
	/* Give control to main program loop. */
	UIMainInterface();

	/* We really shouldn't be here at all... ah well. */
	MainQuit(NULL, NULL);
	return 0;
}
