/*
 *  Copyright 1994-2022 Olivier Girondel
 *  Copyright 2014-2022 Frantz Balinski
 *
 *  This file is part of lebiniou.
 *
 *  lebiniou 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.
 *
 *  lebiniou 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.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with lebiniou. If not, see <http://www.gnu.org/licenses/>.
 */

#include "brandom.h"
#include "context.h"
#include "translation.h"
#include "point2d.h"


uint32_t version = 0;
uint32_t options = BO_DISPLACE;
char desc[] = "Poly-spirals effect";
char dname[] = "Spirals";

static Translation_t *t_spiral = NULL;


#define NUMCENTERS  (16)

static Point2d_t  centers[NUMCENTERS];


#define DELTA_ANGLE  (M_PI_4)


static void init_params(void);
static Map_t cth_spiral(const short, const short);

static inline float
hypof(const float x, const float y)
{
  return sqrtf(x*x + y*y);
}


int8_t
create(Context_t *ctx)
{
  t_spiral = Translation_new(&cth_spiral, &init_params);

  return 1;
}


void
destroy(Context_t *ctx)
{
  if (NULL != t_spiral) {
    Translation_delete(t_spiral);
  }
}


void
run(Context_t *ctx)
{
  Translation_run(t_spiral, ctx);
}


void
on_switch_on(Context_t *ctx)
{
  Translation_batch_init(t_spiral);
}


static void
init_params(void)
{
  for (int16_t i = 0; i < NUMCENTERS; i++) {
    centers[i].x = b_rand_uint32_range(MINX, MAXX + 1);
    centers[i].y = b_rand_uint32_range(MINY, MAXY + 1);
  }
}


static Map_t
cth_spiral(const short xx, const short yy)
{
  Map_t m;
  float dx, dy;
  float radius = hypof(WIDTH >> 2, HEIGHT >> 2);
  float x = xx;
  float y = yy;

  for (int16_t i = 0; i < NUMCENTERS; i++) {
    float cx = centers[i].x;
    float cy = centers[i].y;

    if ((y == MINY) || (y == MAXY)) {
      dx = ((cx - x) * 3) / 4;
      dy = cy - y;
    } else if ((x == MINX) || (x == MAXX)) {
      dx = cx - x;
      dy = ((cy - y) * 3) / 4;
    } else {
      dx = x - cx;
      dy = y - cy;

      float dist = hypof(dx, dy);
      if (dist < radius) {
        float ang = atan2f(dy, dx) - DELTA_ANGLE;
        dist /= 10;
        dx = -sinf(ang) * dist;
        dy =  cosf(ang) * dist;
      } else {
        dx = dy = 0;
      }
    }

    x += dx;
    y += dy;
  }

  m.map_x = x;
  m.map_y = y;

  return m;
}
