#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "imageInput.h"

#define BUFFER_SIZE 100
#define FILE_HEADER_STRING "__info2_image_file_format__"

// TODO Implementieren Sie geeignete Hilfsfunktionen für das Lesen der Bildserie aus einer Datei

int checkString (FILE *file){ //Checks if String at the start of File equals expected Format (0 for wrong 1 for right)
	if (file == NULL){ //returns 0 for empty file
		return 0;
	}
	char expectedString[] = FILE_HEADER_STRING;
	char actualString[BUFFER_SIZE];

	rewind(file);
	size_t bytesRead = fread(actualString, 1,27 , file); //Stores Bytes of start of File to actualString
	if (bytesRead != 27){
		return 0;
	} //Returns 0 if File is to short
	actualString[27] = '\0';

	if (strcmp(actualString, expectedString) != 0){
		return 0;
	}
	else{
		return 1;
	}	
}

void setParameters(FILE* file, unsigned int* imageCount, unsigned int* width, unsigned int* height);
int allocateMemory(GrayScaleImageSeries *series, const int imageCount, const int width, const int height);
// TODO Vervollständigen Sie die Funktion readImages unter Benutzung Ihrer Hilfsfunktionen


GrayScaleImageSeries *readImages(const char *path)
{
	FILE* file = fopen(path, "rb");
    if(!(checkString(file))){
        fclose(file);
		return NULL;
    }
	// TODO open binary file from file name
    unsigned int width, height; //uninitialised Variables, will be set by setparamters


    GrayScaleImageSeries *series = malloc(sizeof(GrayScaleImageSeries)); //Reserving memory for series

    setParameters(file, &(series->count), &width, &height); //setting parameters taken from image file

    if(!allocateMemory(series, series->count, width, height)){
        clearSeries(series); //If Memory couldnt be correctly allocated a clearing is necessary
        fclose(file);
        return NULL;
    }



    //Getting image data
	for(unsigned int i = 0; i < series->count ; i++){ //Iterating for every image
        for(unsigned int j = 0; j < width * height; j++){ //Iterating for every pixel
		fread(&(series->images[i].buffer[j]), sizeof(GrayScalePixelType), 1, file);
        }
	}
	fclose(file);
    return series;
}

// TODO Vervollständigen Sie die Funktion clearSeries, welche eine Bildserie vollständig aus dem Speicher freigibt
void clearSeries(GrayScaleImageSeries *series)
{
    if (!series)
        return;

    //Freeing Pixelbuffer for every image
	for(unsigned int i = 0; i < series->count; i++)
	{
		free(series->images[i].buffer);
	}
    free(series->images); //Freeing Images array

    free(series->labels); //Freeing Labels
    free(series); //Freeing Main Structure

}
void setParameters(FILE* file, unsigned int* imageCount, unsigned int* width, unsigned int* height) { // sets the parameters

	char buffer[3];

	fseek(file, 27, SEEK_SET);
	fread(buffer, 1, 3, file);
    if(fread(buffer, 1, 3, file) != 3){
        *imageCount = 0;
        *width = 0;
        *height = 0;


        return;} //Stops if file is too short and clean up

	*imageCount = (int) buffer[0];


    *width = (int) buffer[1];

    *height = (int) buffer[2];
	// TODO allocate memory for labels array (in imageInput.h) -> Done in allocate Memory
	
	// TODO read from file and write in 2d arry, write label in labels array, repeat for imageCount	-> done in readImages	
}

int allocateMemory(GrayScaleImageSeries *series, const int imageCount, const int width, const int height) {
    series->count = imageCount; //counts number of images in series

    series->images = malloc (sizeof(GrayScaleImage) * imageCount); //Reserving Memory for Images Array
    if (series->images == NULL)
        return 0;


    series->labels = malloc (series->count * sizeof(unsigned char)); //One Label for every Image
    if (series->labels == NULL){
        return 0;}

	for (int i = 0; i < imageCount; i++) { //Reserving Memory for every Images Pixelbuffer and setting width and height
	    series->images[i].width = width;
        series->images[i].height = height;

        series->images[i].buffer =  malloc(width * height * sizeof(unsigned char)); // allocates memory for every image in the series
        if (series->images[i].buffer == NULL){
            for (int j = 0; j < i; j++){
                free(series->images[j].buffer);
                }
            free(series->images);
            free(series->labels);
            return 0;
        }

	}
    return 1;
}