#include <png.h>
#include <stdlib.h>
#include <string.h>

#include "backend.h"
#include "image.h"

void write_png_func(png_structp png_ptr, png_bytep data, png_size_t length) {
  qad_screen_buffer_t *screen_buffer =
      (qad_screen_buffer_t *)png_get_io_ptr(png_ptr);
  size_t nsize = screen_buffer->buffer_size + length;

  if (screen_buffer->buffer)
    screen_buffer->buffer = realloc(screen_buffer->buffer, nsize);
  else
    screen_buffer->buffer = malloc(nsize);

  if (screen_buffer->buffer == NULL) {
    return;
  }

  memcpy(screen_buffer->buffer + screen_buffer->buffer_size, data, length);
  screen_buffer->buffer_size += length;
}

void write_png(void *ptr, int width, int height, int pitch, int bpp, int rgb,
               qad_screen_buffer_t *screen_buffer) {
  png_structp png_ptr;
  png_infop png_info_ptr;
  jmp_buf png_jmpbuf;
  int colour_type = PNG_COLOR_TYPE_RGB;

  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  png_info_ptr = png_create_info_struct(png_ptr);

  setjmp(png_jmpbuf);

  png_set_compression_level(png_ptr, 1);

  png_set_write_fn(png_ptr, screen_buffer, write_png_func, NULL);
  png_set_IHDR(png_ptr, png_info_ptr, width, height, 8, colour_type,
               PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
               PNG_FILTER_TYPE_DEFAULT);
  png_write_info(png_ptr, png_info_ptr);

  // TODO: Big assumption
  if (bpp == 32) {
    if (!rgb)
      png_set_bgr(png_ptr);
    png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
  }

  for (int j = 0; j < height; ++j) {
    png_const_bytep pointer = (png_const_bytep)ptr;
    pointer += j * pitch;
    setjmp(png_jmpbuf);
    png_write_row(png_ptr, pointer);
  }

  setjmp(png_jmpbuf);
  png_write_end(png_ptr, NULL);
  png_destroy_write_struct(&png_ptr, &png_info_ptr);
}
