/*
 *  Copyright 1994-2022 Olivier Girondel
 *
 *  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 "context.h"
#include "pthread_utils.h"


uint32_t version = 0;
uint32_t options = BO_SFX | BO_SCHEMES;
enum LayerMode mode = LM_OVERLAY;
char desc[] = "Critters demo";
char dname[] = "Critters";

struct Critter {
  Pixel_t color;     /* critter color */
  Point2d_t pos;    /* critter position */
};


static struct Critter *critters = NULL;
static uint16_t nb_critters = 0;

#define SAFE 50
#define STEP 50


/* da funky function */
static void
randomize(struct Critter *c)
{
  c->color = b_rand_uint32_range(1, 254);
  /* TODO better random start */
  c->pos.x = b_rand_uint32_range(MINX+SAFE, MAXX-SAFE);
  c->pos.y = b_rand_uint32_range(MINY+SAFE, MAXY-SAFE);
}


void
run(Context_t *ctx)
{
  Buffer8_t *dst = passive_buffer(ctx);
  uint16_t i;

  Buffer8_clear(dst);

  if (!xpthread_mutex_lock(&ctx->input->mutex)) {
    /* foreach input */
    for (i = 0; i  < nb_critters; i++) {
      /* compute deltas */
      float dx = ctx->input->data[A_LEFT ][i] * STEP;
      float dy = ctx->input->data[A_RIGHT][i] * STEP;

      /* compute new target */
      Point2d_t tmp;
      tmp.x = critters[i].pos.x + dx;
      tmp.y = critters[i].pos.y + dy;

      /* draw */
      draw_line(dst, critters[i].pos.x, critters[i].pos.y, tmp.x, tmp.y, critters[i].color);

      /* if a critter is out of screen, reset it */
      if ((tmp.x < MINX) || (tmp.y < MINY)
          || (tmp.x > MAXX) || (tmp.y > MAXY)) {
        randomize(&critters[i]);
      } else {
        /* update position */
        critters[i].pos.x = tmp.x;
        critters[i].pos.y = tmp.y;
      }
      xpthread_mutex_unlock(&ctx->input->mutex);
    }
  }
}


static void
randomize_all(void)
{
  int i;

  for (i = 0; i < nb_critters; i++) {
    randomize(&critters[i]);
  }
}


void
on_switch_on(Context_t *ctx)
{
  randomize_all();
}


int8_t
create(Context_t *ctx)
{
  nb_critters = ctx->input->size;

  critters = xcalloc(nb_critters, sizeof(struct Critter));
  if (NULL == critters) {
    xerror("pas de critter, trop dure la vie\n");
  }

  randomize_all();

  return 1;
}


void
destroy(Context_t *ctx)
{
  if (NULL != critters) {
    xfree(critters);
  }
}
