/*
Nome: Mario
Cognome: Montanari
Classe: 3AIN
Data: 05/05/2025

Funzione di Shaker Sort che ordina direttamente su un file
*/

#include <iostream>

using namespace std;

typedef struct {
	int value;
} basetype;

void fshakerSort(FILE * file);
void swapInFile(FILE * file, int i, int j);
void fprint(const char * filename);

int main(void) {
	const char * filename = "data.bin";
	
	// Apertura del file
	FILE * file = fopen(filename, "r+b");
	
	if (file != NULL) {
		fshakerSort(file);  // Esegui lo shaker sort
		fprint(filename);   // Stampa il risultato
		
		fclose(file);       // Chiudi il file
	} else {
		perror("Errore nell'aprire il file");
	}
	
	return 0;
}

void fshakerSort(FILE * file) {
	// Spostati alla fine del file per ottenere il numero di elementi
	fseek(file, 0, SEEK_END);
	long n = ftell(file) / sizeof(basetype);
	
	if (n < 2) {
		return;  // Se il file ha meno di due elementi, non è necessario ordinare
	}
	
	rewind(file);  // Torna all'inizio del file
	
	int left = 0;
	int right = n - 1;
	bool swapped = true;
	
	while (left < right && swapped) {
		swapped = false;
		
		// Passaggio da sinistra verso destra
		for (int i = left; i < right; i++) {
			basetype a, b;
			
			// Leggi i due valori da scambiare
			fseek(file, i * sizeof(basetype), SEEK_SET);
			fread(&a, sizeof(basetype), 1, file);
			
			fseek(file, (i + 1) * sizeof(basetype), SEEK_SET);
			fread(&b, sizeof(basetype), 1, file);
			
			if (a.value > b.value) {
				swapInFile(file, i, i + 1);  // Effettua lo swap se i valori sono nell'ordine sbagliato
				swapped = true;
			}
		}
		
		right--;  // Riduci l'area da esaminare
		
		// Passaggio da destra verso sinistra
		for (int i = right; i > left; i--) {
			basetype a, b;
			
			fseek(file, (i - 1) * sizeof(basetype), SEEK_SET);
			fread(&a, sizeof(basetype), 1, file);
			
			fseek(file, i * sizeof(basetype), SEEK_SET);
			fread(&b, sizeof(basetype), 1, file);
			
			if (a.value > b.value) {
				swapInFile(file, i - 1, i);  // Effettua lo swap se i valori sono nell'ordine sbagliato
				swapped = true;
			}
		}
		
		left++;  // Espandi l'area da esaminare
	}
}

void swapInFile(FILE * file, int i, int j) {
	if (i == j) {
		return;  // Nessun bisogno di fare uno swap se gli indici sono uguali
	}
	
	basetype a, b;
	
	// Leggi i valori da scambiare
	fseek(file, i * sizeof(basetype), SEEK_SET);
	if (fread(&a, sizeof(basetype), 1, file) != 1) {
		cout << "Errore di lettura (i)!" << endl;
		return;
	}
	
	fseek(file, j * sizeof(basetype), SEEK_SET);
	if (fread(&b, sizeof(basetype), 1, file) != 1) {
		cout << "Errore di lettura (j)!" << endl;
		return;
	}

	// Scrivi i valori scambiati
	fseek(file, i * sizeof(basetype), SEEK_SET);
	if (fwrite(&b, sizeof(basetype), 1, file) != 1) {
		cout << "Errore di scrittura (i)!" << endl;
		return;
	}
	
	fseek(file, j * sizeof(basetype), SEEK_SET);
	if (fwrite(&a, sizeof(basetype), 1, file) != 1) {
		cout << "Errore di scrittura (j)!" << endl;
		return;
	}
}

void fprint(const char * filename) {
	FILE * file = fopen(filename, "rb");
	
	if (file != NULL) {
		basetype temp;
		
		while (fread(&temp, sizeof(basetype), 1, file) == 1) {
			cout << temp.value << " ";  // Stampa i valori letti
		}
		
		cout << endl;
		
		fclose(file);
	} else {
		perror("Errore nell'aprire il file per la lettura");
	}
}