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

Scrivere un programma che replica le funzionalità base dell'editor
esadecimale Hexed.it

1) Funzione che visualizza in esadecimale il valore dei byte contenuti
   nel nomeFile ricevuto come parametro:
      - Andare 1a capo ogni LunRiga byte;
         - LunRiga = 16;
         - LunRiga chiesto in input dal main e passato alla funzione;
         - LunRiga letto dal file di testo editor16.ini contenente una
		   riga ad esempio  “LunRiga 16”.

2) Funzione che riceve nomeFile come parametro, chiede all’utente l’offset
   di un byte del file, mostra il valore (little-endian) di:
      - Un byte in decimale ed esadecimale;
      - Un intero 32 bit;
      - Un float 32 bit.
*/

#include <iostream>
#include <iomanip>

using namespace std;

void creaFileBin(const char * filename);
void visualizzaEsadecimale(const char * filename, int lungRiga);
void visualizzaEsadecimaleFile(const char * inputFile, const char * outputFile);
void mostraValoriOffset(const char * filename);

int main(void) {
	creaFileBin("file_esadecimale.bin");
	
	return 0;
}

void creaFileBin(const char * filename) {
	int lungRiga;
	
	cout << "Inserisci lungRiga: ";
	cin >> lungRiga;
	
	FILE * file = fopen(filename, "wb");
	
	if (file != NULL) {		
		for (int i = 0; i < 50; i++) {
			fwrite(&i, sizeof(int), 1, file);
		}
		
		fclose(file);
	} else {
		perror("Error (source)");
	}
	
	visualizzaEsadecimale("file_esadecimale.bin", lungRiga);
	// visualizzaEsadecimaleFile("file_esadecimale.bin", "editor16.ini");
	mostraValoriOffset("file_esadecimale.bin");
}

void visualizzaEsadecimale(const char * filename, int lungRiga) {
	FILE * file = fopen(filename, "rb");
	
	if (file != NULL) {
		char valoreEsadecimale;
		int count = 0;
		
		while (fread(&valoreEsadecimale, sizeof(char), 1, file) == 1) {
			cout << setw(2) << setfill('0') << hex << (int)valoreEsadecimale << " ";
			count++;
			
			if (count % lungRiga == 0) {
				cout << endl;
			}
		}
		
		fclose(file);
	} else {
		perror("Error (source)");
	}
}

void visualizzaEsadecimaleFile(const char * inputFile, const char * outputFile) {
	FILE * fileIn = fopen(inputFile, "rb");
	
	if (fileIn != NULL) {
		FILE * fileOut = fopen(outputFile, "rt");
		
		if (fileOut != NULL) {
			int lungRiga = 0;
			char line[1000+1];
			
			if (fgets(line, sizeof(line), fileOut) != NULL) {
				char * token = strtok(line, " \t");
				token = strtok(NULL, " \t\n");
				
				if (token != NULL) {
					lungRiga = atoi(token);
					cout << "LunRiga letto dal file: " << lungRiga << endl;
				} else {
					cout << "Errore nella lettura della riga." << endl;
					fclose(fileIn);
					fclose(fileOut);
					return;
				}
			} else {
				cout << "Errore nella lettura della riga." << endl;
				fclose(fileIn);
				fclose(fileOut);
				return;
			}
			
			unsigned char valore;
			int count = 0;
			
			while (fread(&valore, sizeof(char), 1, fileIn) == 1) {
				cout << setw(2) << setfill('0') << hex << (int)valore << " ";
				count++;
				
				if (count % lungRiga == 0) {
					cout << endl;
				}
			}
			
			fclose(fileOut);
		} else {
			perror("Error (destination)");
		}
		
		fclose(fileIn);
	} else {
		perror("Error (source)");
	}
}

void mostraValoriOffset(const char * filename) {
	FILE * file = fopen(filename, "rb");
	
	if (file == NULL) {
		perror("Errore apertura file");
		return;
	}
	
	int offset;
	
	cout << "\nInserisci offset del byte da leggere: ";
	cin >> offset;
	
	if (fseek(file, offset, SEEK_SET) != 0) {
		cout << "Errore: offset non valido." << endl;
		fclose(file);
		return;
	}
	
	fseek(file, 0, SEEK_END);
	long fileSize = ftell(file);
	rewind(file);
	
	if (offset < 0 || offset >= fileSize) {
	    cout << "Errore: offset fuori dai limiti del file." << endl;
	    fclose(file);
	    return;
	}
	
	unsigned char byte;
	
	if (fread(&byte, sizeof(byte), 1, file) != 1) {
		cout << "Errore nella lettura del byte." << endl;
		fclose(file);
		return;
	}
	
	cout << "\nByte letto all'offset " << offset << ": " 
		<< dec << (int)byte << " (DEC) | "
		<< hex << setw(2) << setfill('0') << (int)byte << " (HEX)" << endl;
	
	if (fseek(file, offset, SEEK_SET) != 0) {
		cout << "Errore nel seek per lettura int." << endl;
		fclose(file);
		return;
	}
	
	int valoreInt;
	
	if (fread(&valoreInt, sizeof(valoreInt), 1, file) == 1) {
		cout << "Valore intero (32 bit): " << dec << valoreInt << endl;
	} else {
		cout << "Errore lettura int." << endl;
	}
	
	if (fseek(file, offset, SEEK_SET) != 0) {
		cout << "Errore nel seek per lettura float." << endl;
		fclose(file);
		return;
	}
	
	float valoreFloat;
	
	if (fread(&valoreFloat, sizeof(valoreFloat), 1, file) == 1) {
		cout << "Valore float (32 bit): " << fixed << setprecision(8)  << valoreFloat << endl;
	} else {
		cout << "Errore lettura float." << endl;
	}
	
	fclose(file);
}