/*
 *  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 "constants.h"
#include "brandom.h"
#include "imagefader.h"
#include "images.h"
#include "globals.h"


ImageFader_t *
ImageFader_new(const uint16_t size)
{
  ImageFader_t *imgf = xcalloc(1, sizeof(ImageFader_t));

  imgf->on = 0;
  imgf->cur = Image8_new();
  if (NULL != images) {
    imgf->dst = images->imgs[0];
  }
  imgf->fader = Fader_new(BUFFSIZE);
  imgf->shf = Shuffler_new(size);
  Shuffler_set_mode(imgf->shf, Context_get_shuffler_mode(BD_IMAGES));

  ImageFader_set(imgf);

  return imgf;
}


void
ImageFader_delete(ImageFader_t *imgf)
{
  Image8_delete(imgf->cur);
  Fader_delete(imgf->fader);
  Shuffler_delete(imgf->shf);
  xfree(imgf);
}


void
ImageFader_init(ImageFader_t *imgf)
{
  Fader_t *fader = imgf->fader;
  uint32_t i;
  const Buffer8_t *src = imgf->cur->buff;
  const Buffer8_t *dst = imgf->dst->buff;

  Fader_init(fader);
  for (i = BUFFSIZE; i--; ) { /* i < BUFFSIZE; i++) { */
    /* delta values for fading */
    fader->delta[i] = (long)(
                        ((float)dst->buffer[i] - (float)src->buffer[i])
                        / (float)(fader->max)
                        * MFACTOR);

    /* initial values for fading */
    /* fader->tmp[i] = (float)src->buffer[i]; */
    fader->tmp[i] = (uint32_t)src->buffer[i]*MFACTOR;
  }
  Fader_start(fader);
}


void
ImageFader_run(ImageFader_t *imgf)
{
  Fader_t *fader = imgf->fader;
  const uint32_t elapsed = Fader_elapsed(fader);

#ifdef DEBUG_FADERS
  printf("If ");
#endif
  Fader_start(fader);
  fader->faded += elapsed;

  if (fader->faded < fader->max) {
    /* now do some fading stuff #~{@ */
    /* we spent (elapsed) msecs */
    Pixel_t *ptr = imgf->cur->buff->buffer;
    /*     float   *tmp = fader->tmp; */
    /*     float   *delta = fader->delta; */
    uint32_t   *tmp = fader->tmp;
    long   *delta = fader->delta;
    uint32_t i;

    for (i = BUFFSIZE; i--; ptr++, tmp++, delta++)
      /**ptr = (Pixel_t)(*tmp += (elapsed * *delta));*/
    {
      *ptr = (Pixel_t)((*tmp += (elapsed * *delta))/MFACTOR);
    }
  } else {
    /* we're done */
    fader->fading = 0;
    /* copy, just in case */
    Image8_copy(imgf->dst, imgf->cur);
  }
}


void
ImageFader_set(ImageFader_t *imgf)
{
  if (NULL != imgf) {
    Fader_t *fader = imgf->fader;

    imgf->dst = images->imgs[fader->target];

    if (NULL != imgf->dst->name) {
#ifdef DEBUG_IMAGEFADER
      VERBOSE(printf("[i] Using image '%s'\n", imgf->dst->name));
#endif
    } else {
      xerror("Image without name, WTF #@!\n");
    }

    ImageFader_init(imgf);
    fader->fading = 1;
  }
}


void
ImageFader_prev(ImageFader_t *imgf)
{
  if (NULL != imgf) {
    DEC(imgf->fader->target, images->size);
    ImageFader_set(imgf);
  }
}


void
ImageFader_prev_n(ImageFader_t *imgf, const uint16_t n)
{
  if (NULL != imgf) {
    for (uint16_t i = 0; i < n; i++) {
      DEC(imgf->fader->target, images->size);
    }
    ImageFader_set(imgf);
  }
}


void
ImageFader_next(ImageFader_t *imgf)
{
  if (NULL != imgf) {
    INC(imgf->fader->target, images->size);
    ImageFader_set(imgf);
  }
}


void
ImageFader_next_n(ImageFader_t *imgf, const uint16_t n)
{
  if (NULL != imgf) {
    for (uint16_t i = 0; i < n; i++) {
      INC(imgf->fader->target, images->size);
    }
    ImageFader_set(imgf);
  }
}


void
ImageFader_random(ImageFader_t *imgf)
{
  if (NULL != imgf) {
    imgf->fader->target = Shuffler_get(imgf->shf);
    ImageFader_set(imgf);
  }
}


void
ImageFader_use(ImageFader_t *imgf, const uint16_t index)
{
  if (NULL != imgf) {
    if (index < images->size) {
      imgf->fader->target = index;
      ImageFader_set(imgf);
    }
  }
}


int
ImageFader_ring(const ImageFader_t *imgf)
{
  if (NULL != imgf) {
    const Fader_t *fader = imgf->fader;

    return (fader->fading && ((Timer_elapsed(fader->timer) * MFACTOR) > 0));
  } else {
    return 0;
  }
}
