#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

static int checkHeader (FILE *file)
{
    char header [strlen (FILE_HEADER_STRING) +1]; //Ermittle die Länge des Strings, +1 wegen Null

    size_t gelesen = fread (header, sizeof(char), strlen(FILE_HEADER_STRING), file);
    if (gelesen != strlen (FILE_HEADER_STRING))
        return -1;
    
    header [strlen (FILE_HEADER_STRING)] = '\0';

    if (strcmp(header, FILE_HEADER_STRING) == 0) {
        return 1;
    } else {
        return -1;
    }

}

static unsigned short readShort (FILE *file)
{
    unsigned char bytes [2];
    if (fread(bytes, sizeof(unsigned char), 2, file) != 2)
        return 0;
    return (bytes [1] << 8) | bytes [0];    //Big-Endian -> Little-Endian

}

static GrayScaleImage readSingleImage (FILE *file, unsigned short width, unsigned short height)
{
    GrayScaleImage img;
    img.width = width;
    img.height = height;
    img.buffer = NULL;
    
    //Speicher für Pixel reservieren
    size_t pixelCount = width * height;
    img.buffer = malloc(pixelCount * sizeof(GrayScalePixelType));
        if (img.buffer == NULL){
            img.width = 0;
            img.height = 0;
            return img;
        }

    //Pixel einlesen
    size_t gelesenPixels = fread (img.buffer, sizeof(GrayScalePixelType), pixelCount, file);
    if (gelesenPixels != pixelCount) {
        img.buffer = NULL;
        img.width = 0;
        img.height = 0;
    }

    return img;
}

static unsigned char readLabel (FILE *file)
{
    unsigned char label = 0;
    
    size_t gelesen = fread (&label, sizeof(unsigned char), 1, file);
        if (gelesen == 0)
        return 0;

    return label;
}

// TODO Vervollständigen Sie die Funktion readImages unter Benutzung Ihrer Hilfsfunktionen
GrayScaleImageSeries *readImages(const char *path)
{
    GrayScaleImageSeries *series = NULL;
    
    FILE *file = fopen(path, "rb"); 
    if (file == NULL) {
        return NULL; 
    }

    if (checkHeader(file) != 1) {
        return NULL;
    }
    
    unsigned short count = readShort(file);
    unsigned short width = readShort(file);
    unsigned short height = readShort(file);

    series = malloc (sizeof(GrayScaleImageSeries));
    if (series == NULL)
        return NULL;
    
    series->count = count;
    series->images = malloc (count * sizeof(GrayScaleImage));
    series->labels = malloc (count * sizeof(unsigned char));

    if (series->images == NULL || series->labels == NULL)
        return NULL;

    for (unsigned int i = 0; i < count; i++)
    {
        series->images[i] = readSingleImage(file, width, height);
        series->labels[i] = readLabel(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 == NULL) {
            return;
        }
        // Alle Bilder durchgehen und deren Buffer freigeben
        for (int i = 0; i < series->count; i++) {
            if (series->images[i].buffer != NULL) {
                free(series->images[i].buffer);
                series->images[i].buffer = NULL;
            }
        }
        // Arrays freigeben
        if (series->images != NULL) {
            free(series->images);
            series->images = NULL;
        }
        if (series->labels != NULL) {
            free(series->labels);
            series->labels = NULL;
        }
        // Schließlich die gesamte Serie freigeben
        free(series);
}