#include <string.h>
#include <png.h>
#include "webp/encode.h"
#include "utils.h"

static int MyWriter(const uint8_t* data, size_t data_size, const WebPPicture* const pic) {
  FILE* const out = (FILE*)pic->custom_ptr;
  return data_size ? (fwrite(data, data_size, 1, out) == 1) : 1;
}

int png_to_webp(FILE* input, FILE* output, int targetSize) {
    WebPPicture picture;

#ifdef HAS_DEBUG
  clock_t t;
  t = clock();
#endif
  png_image image;
  memset(&image, 0, sizeof image);
  image.version = PNG_IMAGE_VERSION;
  DEBUG("reading png");
  if (!png_image_begin_read_from_stdio(&image, input)) {
    ERROR("png_image_begin_read_from_stdio");
    return 1;
  }
  DEBUG("allocate");
  png_bytep buffer;
  image.format = PNG_FORMAT_RGBA;
  buffer = malloc(PNG_IMAGE_SIZE(image));
  if (buffer == NULL) {
    ERROR("png_malloc");
    png_image_free(&image);
    return 1;
  }
  DEBUG("start reading");
  if (!png_image_finish_read(&image, NULL, buffer, 0, NULL)) {
    ERROR("png_image_finish_read");
    png_image_free(&image);
    free(buffer);
    return 1;
  }

  /////////////////////////////////////////////
  // encode to webp
  DEBUG("start encoding");
  if (!WebPPictureInit(&picture)) {
    ERROR("WebPPictureInit");
    png_image_free(&image);
    free(buffer);
    return 1;
  }
  picture.width = image.width;
  picture.height = image.height;
  if(!WebPPictureAlloc(&picture)) {
    ERROR("WebPPictureAlloc");
    png_image_free(&image);
    free(buffer);
    return 1;
  }
  DEBUG("start encoding import");
  WebPPictureImportRGBA(&picture, buffer, PNG_IMAGE_ROW_STRIDE(image));
  png_image_free(&image);
  free(buffer);

  WebPConfig webp_config_output;
  picture.writer = MyWriter;
  picture.custom_ptr = output;
  DEBUG("start encoding config init");
  if (!WebPConfigInit(&webp_config_output)) {
    ERROR("ERR config init");
    WebPPictureFree(&picture);
    return 1;
  }
  webp_config_output.method = 0;
  webp_config_output.quality = 30;
  if (!WebPValidateConfig(&webp_config_output)) {
    ERROR("ERR WEB VALIDATION");
    WebPPictureFree(&picture);
    return 1;
  }
  DEBUG("rescale start");
  if (image.width > targetSize && image.height > targetSize) {
    float ratioHeight = (float) image.height / targetSize;
    float ratioWidth = (float) image.width / targetSize;
    float ratio = ratioWidth > ratioHeight ? ratioHeight : ratioWidth;
    if (!WebPPictureRescale(&picture, image.width / ratio, image.height / ratio)) {
      DEBUG("ERR Rescale");
      WebPPictureFree(&picture);
      return 1;
    }
  }
  DEBUG("encoder start");
  WebPEncode(&webp_config_output, &picture);
  DEBUG("encoder done");
  WebPPictureFree(&picture);
  DEBUG("cleaning up");
  return 0;
}

int png_to_png(FILE* input, FILE* output, int targetSize) {
#ifdef HAS_DEBUG
  clock_t t;
  t = clock();
#endif
  png_image image;
  memset(&image, 0, sizeof image);
  image.version = PNG_IMAGE_VERSION;
  DEBUG("> reading png");
  if (!png_image_begin_read_from_stdio(&image, input)) {
    DEBUG("png_image_begin_read_from_stdio");
    return 1;
  }
  DEBUG("> allocate");
  png_bytep buffer;
  image.format = PNG_FORMAT_RGBA;
  buffer = malloc(PNG_IMAGE_SIZE(image));
  if (buffer == NULL) {
    DEBUG("png_malloc");
    png_image_free(&image);
    return 1;
  }
  DEBUG("> start reading");
  if (!png_image_finish_read(&image, NULL, buffer, 0, NULL)) {
    DEBUG("png_image_finish_read");
    png_image_free(&image);
    free(buffer);
    return 1;
  }

  DEBUG("> write");
  if (!png_image_write_to_stdio(&image, output, 0, buffer, 0, NULL)) {
    DEBUG("png_image_write_to_stdio");
    png_image_free(&image);
    free(buffer);
    return 1;
  }

  DEBUG("> end");
  png_image_free(&image);
  free(buffer);
  return 0;
}
