/*
 *  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>

#define PI 3.14151592654

static uint32_t lc_rotated_height(int width, int height, double angle){
    return round(fabs(cos(angle)) * width+fabs(sin(angle)) * height);
}

static uint32_t lc_rotated_width(int width, int height, double angle){
    return round(fabs(sin(angle)) * width+fabs(cos(angle)) * height);
}

static lc_bmpGlyph * lc_rotate_bmp_1(uint8_t *buffer, int width, int height, double angle) {
  const float _cos = cos(angle);
  const float _sin = sin(angle);
  lc_bmpGlyph *nglyph;

  nglyph  = malloc(sizeof(*nglyph));

  if (!nglyph) {
    errno = ENOMEM;
    return NULL;
  }

/*  nglyph->w = MAX(width, height) + height / 3;*/
/*  nglyph->h = MAX(width, height) + width / 3;*/
  nglyph->w = lc_rotated_width(width, height, angle);
  nglyph->h = lc_rotated_height(width, height, angle);

  nglyph->buffer = calloc(sizeof(uint8_t), nglyph->w * nglyph->h);
  nglyph->type = LC_TYPE_GLYPH;

  if (!nglyph->buffer) {
    errno = ENOMEM;
    free(nglyph);
    return NULL;
  }

  const double hwd = (double) nglyph->w / 2;
  const double hhd = (double) nglyph->h / 2;
  const double hws = (double) width / 2;
  const double hhs = (double) height / 2;

  for (int32_t x = 0 - hwd; x < nglyph->w - hwd; x++) {
    for (int32_t y = 0 - hhd; y < nglyph->h - hhd; y++) {
      int32_t X = round(x*_cos + y*_sin + hws);
      int32_t Y = round(y*_cos - x*_sin + hhs);

      if (Y < height && Y > 0 && X < width && X > 0) {
        *(nglyph->buffer + ((y + (int32_t)hhd) * nglyph->w) +
            x + (int32_t)hwd) = *(buffer + (Y * width) + X);
      }
    }
  }

  return nglyph;
}

lc_bmpGlyph * lc_rotate_glyph(lc_bmpGlyph *glyph, int angle) {
  double a = angle * PI / 180;
  return lc_rotate_bmp_1(glyph->buffer, glyph->w, glyph->h, a);
}
