#include <signal.h>
#include <pthread.h>
#include <string.h> /* For memset() */

#include "slices_evt.h"
#include "utils.h"
#include "recover.h"
#include "cursesview.h"

// Global variable shared by all threads to say "finish current operation and go away"
int end=0;

void sigHookAbrt() {
	end=1;
}

// Main thread procedures declaration and a struct for passing arguments in a clean way
void *procWorker(void *a);
void *procViewer(void *a);

struct threadArgs {
	struct progArgs *progArgs;
	slices_evt_t *slices;
};

int main(int argc, char **argv) {
	// System structures
	struct sigaction sa;
	pthread_t tWorker;

	// Main data structure
	slices_evt_t slices;

	// Progam and threads arguments
	struct progArgs args;
	struct threadArgs tArgs;

	// Algorithmic needs
	int res, i;
	
	// Parse command-line arguments	
	res=parseArgs(argc, argv, &args);
	if (res!=0) {
		usage(argv[0]);
		return 1;
	}

	// Set signals behavior
	memset(&sa,0,sizeof(sa));
	sa.sa_handler=sigHookAbrt;
	res=sigaction(SIGABRT, &sa, NULL);
	if (res!=0) {
		return 2;
	}

	//XXX Remove srand : only for simulation
	srand(4);

	// Initialize main data structure
	//XXX provide a method to do that ?
	memset(&slices, 0, sizeof(slices));
	slices.data=slicesNewSingleton(args.beginSector, args.endSector, S_UNKNOWN);
	if ( slices.data == NULL ) {
		return 3;
	}
	slices.data->min=args.beginSector;
	slices.data->max=args.endSector;
	res=pthread_mutex_init(&(slices.eventListenerMutex), NULL);
	if (res!=0) {
		return 4;
	}

	// Threads preparation, creation and start
	memset(&tArgs, 0, sizeof(tArgs));
	tArgs.progArgs=&args;
	tArgs.slices=&slices;


	res=pthread_create(&tWorker, NULL, procWorker, &tArgs);
	if (res!=0) {
		return 5;
	}

	// Ncurses interface run in the main thread
	(void) procViewer((void*)&tArgs);

	// Thread join point (wait worker thread when viewer is done)
	(void) pthread_join(tWorker, NULL);

	//Final dump of datas	
	address_t blockSize=0;
	char *dump;
	dump=slicesDump(slices.data, &blockSize, 10000, args.beginSector, args.endSector);
	if (dump != NULL) {
		puts(dump);
		free(dump);
	}
	printf("blockSize==%lld\n", blockSize);
	printf("slices->count==%d\n", slices.data->count);
	

	//Resources desallocation
	(void) pthread_mutex_destroy(&(slices.eventListenerMutex));

	//XXX Method for that
	slice_t *curr, *toFree;
	i=0; curr=slices.data->first;
	while (curr!=NULL) {
		i++;
		toFree=curr;
		curr=curr->next;
		free(toFree);
	}
	free(slices.data);

	return 0;
}

void *procWorker(void *a) {
	struct threadArgs *tArgs = (struct threadArgs *)a;

	//XXX : We will need something more controlable than just a blocking call to the main algorithm
	recover(
		tArgs->slices,
		tArgs->progArgs->src,
		tArgs->progArgs->dst,
		tArgs->progArgs->ddOpts
	);
	
	return a;
}


void *procViewer(void *a) {
	struct threadArgs *tArgs = (struct threadArgs *)a;
	
	cursesMainLoop(
		tArgs->slices
	);

	return a;
}