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

#define BUFFER_SIZE 100
#define FILE_HEADER_STRING "__info2_image_file_format__" // 27byte lang

// TODO Implementieren Sie geeignete Hilfsfunktionen für das Lesen der Bildserie aus einer Datei
static int checkHeader(FILE *file)
{

    int headerlen = strlen(FILE_HEADER_STRING);

    char readHeader[headerlen + 1];

    size_t elementsRead = fread(readHeader, 1, headerlen, file);

    if (elementsRead != headerlen)
    {
        printf("Header länge ist nicht wie erwartet\n");
        return 0;
    }

    readHeader[headerlen] = '\0';

    if (strcmp(FILE_HEADER_STRING, readHeader) != 0)
    {
        printf("Header ist nicht wie erwartet\n");
        return 0;
    }

    return 1;
}

static int readMetadata(FILE *file, unsigned int *count, unsigned int *width, unsigned int *height)
{
    unsigned short tempCount = 0;
    unsigned short tempWidth = 0;
    unsigned short tempHeight = 0;

    if (fread(&tempCount, sizeof(unsigned short), 1, file) != 1) return 0;
    if (fread(&tempWidth, sizeof(unsigned short), 1, file) != 1) return 0;
    if (fread(&tempHeight, sizeof(unsigned short), 1, file) != 1) return 0;

    *count = (unsigned int)tempCount;
    *width = (unsigned int)tempWidth;
    *height = (unsigned int)tempHeight;

    return 1;
}

static int readImage(FILE *file, GrayScaleImageSeries *series, unsigned int index)
{
    unsigned int numPixels = series->images[index].height * series->images[index].width;

    series->images[index].buffer = calloc(numPixels, sizeof(GrayScalePixelType));
    if (series->images[index].buffer == NULL)
        return 0;

    if (fread(series->images[index].buffer, sizeof(GrayScalePixelType), numPixels, file) != numPixels)
    {
        free(series->images[index].buffer);
        return 0;
    }

    if (fread(&series->labels[index], sizeof(unsigned char), 1, file) != 1)
    {
        free(series->images[index].buffer);
        return 0;
    }

    return 1;
}

// TODO Vervollständigen Sie die Funktion readImages unter Benutzung Ihrer Hilfsfunktionen
GrayScaleImageSeries *readImages(const char *path)
{
    GrayScaleImageSeries *series = NULL;
    series = malloc(sizeof(GrayScaleImageSeries));
    if (series == NULL)
        return NULL;

    unsigned int count = 0;
    unsigned int width = 0;
    unsigned int height = 0;

    FILE *file = fopen(path, "rb");

    if (file == NULL)
    {
        perror("Fehler beim öffnen der Datei\n");
        free(series);
        return NULL;
    }

    if (checkHeader(file) != 1)
    {
        printf("Fehler bei checkHeader\n");
        free(series);
        fclose(file);
        return NULL;
    }

    if (readMetadata(file, &count, &width, &height) != 1)
    {
        printf("Fehler bei readMetadata\n");
        free(series);
        fclose(file);
        return NULL;
    }

    series->count = count;
    series->labels = calloc(sizeof(unsigned char), count);
    series->images = calloc(sizeof(GrayScaleImage), count);

    if (series->labels == NULL || series->images == NULL)
    {
        printf("Speicherfehler bei Arrays\n");
        free(series->labels);
        free(series->images);
        free(series);
        fclose(file);
        return NULL;
    }

    for (int i = 0; i < series->count; i++)
    {
        series->images[i].height = height;
        series->images[i].width = width;

        if (readImage(file, series, i) != 1)
        {
            printf("Fehler bei readImage bei Bild Nummer: %d\n", i + 1);

            for (int j = 0; j < i; j++)
            {
                free(series->images[j].buffer);
            }
            free(series->images);
            free(series->labels);
            free(series);

            fclose(file);
            return NULL;
        }
    }

    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;

    if (series->images != NULL) {
        for (int i = 0; i < series->count; i++)
        {
            free(series->images[i].buffer);
        }
        free(series->images);
    }

    free(series->labels); //der container (series) muss existieren, labels kann Null sein

    free(series);

}