/*
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; either version 2
 *  of the License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  Author: g0tsu
 *  Email:  g0tsu at dnmx.0rg
 */

#include <libcaptcha.h>
#include <stdio.h>
#include <math.h>
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <global.h>

lc_bmp * lc_generate_noise(lc_bmp *pattern, int w, int h) {
  lc_bmp *bmp = lc_create_3ch_bmp(w, h);
  int rsize = w * h + 1;
  int rp = 3, mp;
  char *bytes = malloc(rsize * sizeof(char));

  lc_random_bytes(bytes, rsize);

  for (int y = 0; y < h; y++) {
    for (int x = 0; x < w; x++, rp++) {

    if (rp >= rsize)
      rp = 3;

      if (pattern && *(pattern->buffer + y * w + x) != 0) {
         mp = bytes[rp];
         mp = (mp > 0x32 ? 0xFA : mp - 0xAA);

        *(bmp->buffer + (3 * (y * w + x)))     = mp;
        *(bmp->buffer + (3 * (y * w + x)) + 1) = bytes[rp - 2] + 0x8A;
        *(bmp->buffer + (3 * (y * w + x)) + 2) = bytes[rp - 1] + 0x8A;
      } else if (!pattern) {
        *(bmp->buffer + (3 * (y * w + x)))     = bytes[rp - 1];
        *(bmp->buffer + (3 * (y * w + x)) + 1) = bytes[rp - 2];
        *(bmp->buffer + (3 * (y * w + x)) + 2) = bytes[rp];
      }
    }
  }

  free(bytes);

  return bmp;
}

#define CHECK(x) (x > 0xff ? 0xff: x - 0xaf )

void lc_colorize_sepia(lc_bmp *bmp) {
  for (int y = 0; y < bmp->h; y++) {
    for (int x = 0; x < bmp->w; x++) {
      uint8_t r = *(bmp->buffer + (3 * (y * bmp->w + x)));
      uint8_t g = *(bmp->buffer + (3 * (y * bmp->w + x)) + 1);
      uint8_t b = *(bmp->buffer + (3 * (y * bmp->w + x)) + 2);

      if (r == 0)
        continue;

      *(bmp->buffer + (3 * (y * bmp->w + x))) = (uint8_t) CHECK((b * 0.131f + g * 0.534f + r * 0.272f));
      *(bmp->buffer + (3 * (y * bmp->w + x)) + 1) = (uint8_t) CHECK((b * 0.168f + g * 0.686f + r * 0.349f));
      *(bmp->buffer + (3 * (y * bmp->w + x)) + 2) = (uint8_t) CHECK((b * 0.189f + g * 0.769f + r * 0.393f));
    }
  }
}

void lc_place_bmp_shape(lc_bmp *bmp, lc_bmp *shape, int x, int y) {
  for (int yo = y, yi = 0; yi < shape->h; yo++, yi++) {
    for (int xo = x, xi = 0; xi < shape->w; xo++, xi++) {
      if (yo < bmp->h && xo < bmp->w) {
        *(bmp->buffer + (3 * (yo * bmp->w + xo))) = *(shape->buffer + (3 *(yi * shape->w + xi)));
        *(bmp->buffer + (3 * (yo * bmp->w + xo)) + 1) = *(shape->buffer + (3 *(yi * shape->w + xi)) + 1);
        *(bmp->buffer + (3 * (yo * bmp->w + xo)) + 2) = *(shape->buffer + (3 *(yi * shape->w + xi)) + 2);
      }
    }
  }
}

lc_bmp * lc_generate_square_shapes(int w, int h, int space, int step) {
  int y, x;
  lc_bmp *bmp = lc_create_3ch_bmp(w, h);

  for (y = 0; y < h; y += step) {
    for (x = 0; x < w; x += step) {
      lc_bmp *shape = lc_generate_square(step - space, step - space);
      lc_place_bmp_shape(bmp, shape, x, y);
      lc_free(shape);
    }
  }

  return bmp;
}

lc_bmp *lc_generate_square(int w, int h) {
  lc_bmp *bmp = lc_create_3ch_bmp(w, h);
  uint8_t bytes[3];

  lc_random_bytes(&bytes, 3);

  for (int i = 0; i < 3; i++)
    bytes[i] = (bytes[i] > 0x6a ? bytes[i]: bytes[i] + 0x77);

  for (int y = 0; y < h; y++) {
    for (int x = 0; x < w; x++) {
      *(bmp->buffer + (3 * (y * bmp->w + x))) = bytes[0];
      *(bmp->buffer + (3 * (y * bmp->w + x)) + 1) = bytes[1];
      *(bmp->buffer + (3 * (y * bmp->w + x)) + 2) = bytes[2];
    }
  }

  return bmp;
}

lc_bmp *lc_generate_circle(int w, int h, int r) {
  lc_bmp *bmp = lc_create_3ch_bmp(w, h);

  return bmp;
}

