#include <errno.h>
#include <stdio.h>
#include "recover.h"

extern unsigned long c;

slices_t *recover(char *src, char *dst, char *ddOpts, address_t beginSector, address_t endSector/*, int depth*/) {
	slices_t *slices;
	slice_t *sliceToRead;
	address_t firstError=0, median, foundMax=0;
	int res;

	// Initialization : we want to try to recover the beginning of the whole zone
	slices=slicesNew();
	sliceToRead=sliceNew(beginSector, endSector, S_UNKNOWN, NULL);
	if (sliceToRead==NULL) {
		exit(1);//TODO
	}
	slicesAppend(slices, sliceToRead);
	
	// Main loop 
	while (!end) { // && slices->count < (endSector-beginSector)/depth) {
		// try to recover sliceToRead and split it if read error
		switch ( tryRecoverUntilError(sliceToRead, &firstError, src, dst, ddOpts) ) {
			case 0:
				// slice recovery has been executed without read error
				sliceToRead->status=S_RECOVERED;
				break;
			case EIO:
				// slice recovery has encountered a readerror
				res=sliceSplit(slices, sliceToRead, firstError, S_RECOVERED, S_UNREADABLE, S_UNKNOWN);
				if (res<1) {
					//TODO
					printf("sliceSplit return %d\n", res);
					exit(5);
				}
				break;
			default:
				exit(2); //TODO
		}

		/* Now, search the largest S_UNKNOWN zone
		 split it in two parts */
		//sliceToRead=slicesFindLargest(slices, S_UNKNOWN);
		sliceToRead=slicesFindLargestFast(slices, &foundMax, S_UNKNOWN, foundMax, sliceToRead->next);
		if ( sliceToRead == NULL ) {
			// There is nothing more to recover, bailout
			end=1;
			continue;
		}
			

 		median=(sliceToRead->begin+sliceToRead->end)/2;
		res=sliceSplit(slices, sliceToRead, median, S_UNKNOWN, S_UNKNOWN, S_UNKNOWN);
		switch (res) {
			case 1:
				// No split, try analyse this zone
				// Should be a slice of length 1
				break;
			case 2:
				/* After splitting an S_UNKNOWN zone in two parts
				   take the second for further analysis.
				   We already now that this first one is just preceded by
				   a read error, and errors are frequently grouped in zones,
				   so trying to read a sector just after a faulty sector is
				   most likely a waste of time.
				*/
				sliceToRead=sliceToRead->next; 
				break;
			case 3:
				// Internal error of sliceSlpit because this set of parameters prevent split by 3
				exit(5); // TODO
				break;
			case -1:
				// Memory error
				exit(4); //TODO
				break;
			default:
				// API error, all necessary cases are already listed
				exit(6); // TODO
			}
	}
	return slices;
}

int tryRecoverUntilError(slice_t *sliceToRead, address_t *firstError, char *src, char *dst, char*ddOpts) {
	//TODO : implement realy that
	char ddinvocation[256];
	int res;
	address_t seek, count;

	c++; //XXX This is a debug counter

	seek=sliceToRead->begin;
	count=sliceToRead->end - seek + 1;
	res=snprintf(ddinvocation, 255, "dd %s %s %s seek=%lld skip=%lld count=%lld", src, dst, ddOpts, seek, seek, count);
	puts(ddinvocation);

/*
	// Simulate that we have systematically a read error at first sector
	*firstError=sliceToRead->begin;
	res=EIO;
*/
	// Simulate that we have systematically a read error at last sector
	*firstError=sliceToRead->end;
	res=EIO;

/*
	// Simulate that we have systematically a read error at first sector
	// Simulate for each read, tha we have an error just in the middle if read for mor than one sector
	if ( sliceToRead->begin == sliceToRead->end ) {
		res=0;
	} else {
		*firstError=(sliceToRead->begin + sliceToRead->end)/2;
		res=EIO;
	}
*/
/*
	// Simulate for each read a pseudo random error position and generate some cases of full read without error
	int error=sliceToRead->begin + rand()%count;
	if ( error % 42 == 0 ) {
		res=0;
	} else {
		res=EIO;
		*firstError=error;
	}
*/

	return res;
}