#include "ciff.h"
#include <stdio.h>
#include <jpeglib.h>
#include <stdlib.h>
#include <string.h>

CIFF *read_ciff(FILE *file)
{

    if (!file)
    {
        printf("Failed to open file!\n");
        return NULL;
    }

    CIFF *ciff = malloc(sizeof(CIFF));
    if (!ciff)
    {
        printf("Failed to allocate memory for CIFF structure\n");
        fclose(file);
        return NULL;
    }

    // Read the header
    if (
    fread(ciff->magic, sizeof(uint32_t), 1, file)  != 1 ||
    fread(&ciff->header_size, sizeof(uint64_t), 1, file)  != 1 ||
    fread(&ciff->content_size, sizeof(uint64_t), 1, file)  != 1 ||
    fread(&ciff->width, sizeof(uint64_t), 1, file)  != 1 ||
    fread(&ciff->height, sizeof(uint64_t), 1, file)  != 1 ) {
        printf("Failed to read CIFF header!\n");
        free(ciff);
        fclose(file);
        return NULL;
    }
    if (ciff->width * ciff->height*3 < ciff->content_size)
    {
        printf("w:%ld h:%ld s:%ld",ciff->width,ciff->height,ciff->content_size);
        printf("Invalid CIFF size!\n");
        ciff->content_size = ciff->width * ciff->height*3;
    }
    // Ensure the file is actually a CIFF file
    if (strncmp(ciff->magic, "CIFF", 4) != 0)
    {
        printf("File is not a CIFF file\n");
        free(ciff);
        fclose(file);
        return NULL;
    }

    // Read the caption
    ciff->caption = malloc(ciff->header_size); // overestimate the size
    if (!ciff->caption)
    {
        printf("Failed to allocate memory for caption\n");
        free(ciff);
        fclose(file);
        return NULL;
    }

    char c;
    size_t i = 0;
    do
    {
        fread(&c, sizeof(char), 1, file);
        ciff->caption[i++] = c;
    } while (c != '\n');
    ciff->caption[i] = '\0'; // null-terminate the string
    size_t caption_lenth = i;
    // Read the tags
    size_t tags_size = ciff->header_size - sizeof(char) * 4 - sizeof(uint64_t) * 4 - caption_lenth; // Size for the rest of the header
    ciff->tags = malloc(tags_size * sizeof(char));
    if (!ciff->tags)
    {
        printf("Failed to allocate memory for tags\n");
        free(ciff->caption);
        free(ciff);
        fclose(file);
        return NULL;
    }

    if (fread(ciff->tags, tags_size, sizeof(uint8_t), file) != 1)
    {
        printf("Failed to read tags!\n");
        free(ciff->caption);
        free(ciff);
        fclose(file);
        return NULL;
    }

    // Read the pixels
    ciff->pixels = malloc(ciff->content_size);
    if (!ciff->pixels)
    {
        printf("Failed to allocate memory for pixel data\n");
        free(ciff->caption);
        free(ciff);
        fclose(file);
        return NULL;
    }
    fread(ciff->pixels, ciff->content_size, 1, file);

    return ciff;
}

void generate_jpg(CIFF *ciff, const char *out_filename)
{
    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr jerr;

    FILE *outfile = fopen(out_filename, "wb");
    if (!outfile)
    {
        printf("Failed to open output file: %s\n", out_filename);
        return;
    }

    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_compress(&cinfo);

    jpeg_stdio_dest(&cinfo, outfile);

    cinfo.image_width = ciff->width;
    cinfo.image_height = ciff->height;
    cinfo.input_components = 3;     // number of color components per pixel
    cinfo.in_color_space = JCS_RGB; // color space of input image

    jpeg_set_defaults(&cinfo);

    jpeg_start_compress(&cinfo, TRUE);

    JSAMPROW row_pointer[1];
    while (cinfo.next_scanline < cinfo.image_height)
    {
        row_pointer[0] = &ciff->pixels[cinfo.next_scanline * ciff->width * 3];
        jpeg_write_scanlines(&cinfo, row_pointer, 1);
    }

    jpeg_finish_compress(&cinfo);

    fclose(outfile);

    jpeg_destroy_compress(&cinfo);
}

void free_ciff(CIFF *ciff)
{
    free(ciff->caption);
    free(ciff->pixels);
    free(ciff->tags);
    free(ciff);
}
