/**
 * Copyright (c) 2021 Dominic Masters
 * 
 * This software is released under the MIT License.
 * https://opensource.org/licenses/MIT
 */

#include "queue.h"

void queueInit(queue_t *queue) {
  queue->timeline = 0;
  queue->count = 0;
  queue->current = ANIMATION_QUEUE_START;
}

queueaction_t * queueNext(queue_t *queue) {
  queueaction_t *action;

  // Is there a currently running action? If so, end it.
  if(queue->current != ANIMATION_QUEUE_START) {
    action = queue->items + queue->current;
    if(action->onEnd != NULL) action->onEnd(queue, action, queue->current);
  }

  // Prepare to go to next action if there is a next action.
  queue->current++;
  queue->actionStarted = queue->timeline;
  if(queue->current >= queue->count) return NULL;

  // Go to next action, start it.
  action = queue->items + queue->current;
  if(action->onStart != NULL) action->onStart(queue, action, queue->current);
  return action;
}

queueaction_t * queueAdd(queue_t *queue) {
  queueaction_t *action;
  action = queue->items + queue->count;
  
  action->index = queue->count;
  action->data = NULL;
  action->onStart = NULL;
  action->onUpdate = NULL;
  action->onEnd = NULL;

  queue->count++;
  return action;
}

void queueUpdate(queue_t *queue, engine_t *engine) {
  queueaction_t *action;
  queue->timeline += engine->time.delta;
  if(queue->current >= queue->count) return;

  action = queue->items + queue->current;
  if(action->onUpdate != NULL) {
    action->onUpdate(queue, action, queue->current);
  }
}

void queueDispose(queue_t *queue) {
  queueaction_t *action;
  if(queue->current >= queue->count) return;
  action = queue->items + queue->current;
  if(action->onEnd != NULL) action->onEnd(queue, action, queue->current);
}


void _queueDelayUpdate(queue_t *queue, queueaction_t *action, uint8_t i) {
  float n = queue->timeline - queue->actionStarted;
  if(n < queue->delays[i]) return;
  queueNext(queue);
}

queueaction_t * queueDelay(queue_t *queue, float delay) {
  queueaction_t *action = queueAdd(queue);
  queue->delays[action->index] = delay;
  action->onUpdate = &_queueDelayUpdate;
  return action;
}