#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <stdint.h>
#include <string.h>
#include <pthread.h>
 
#include "slices_evt.h"
#include "recover.h"
#include "utils.h"


int end=0;
//FIXME remove me, only for tests
unsigned long c=0;

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


void sigHookAbrt() {
	end=1;
}

//TODO : remove that when procViewer is done
void dumper(slices_evt_t *slicesEvt, slice_t *modifiedSlice) {
	address_t blockSize=0;
	char *dump;
	dump=slicesDump(slicesEvt->data, &blockSize, 1000, 0, 21474836480ULL);
	puts(dump);
	free(dump);

}

void *procWorker(void *a);
void *procViewer(void *a);

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

	// Main data structures
	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);

	// Data structure initialization
	memset(&slices, 0, sizeof(slices));
	slices.data=slicesNewSingleton(args.beginSector, args.endSector, S_UNKNOWN);
	slices.eventListener=dumper;
	res=pthread_mutex_init(&(slices.mutex), NULL);
	if (res!=0) {
		return 3;
	}

	// 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 4;
	}

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

	// Thread join point
	(void) pthread_join(tWorker, NULL);
	(void) pthread_join(tViewer, NULL);

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

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

	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;

	recover(
		tArgs->slices,
		tArgs->progArgs->src,
		tArgs->progArgs->dst,
		tArgs->progArgs->ddOpts
	);
	
	return a;
}

void *procViewer(void *a) {

	return a;
}