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

#pragma once
#include "../../libs.h"
#include "../../util/array.h"

#define ANIMATION_QUEUE_ITEM_MAX 128
#define ANIMATION_QUEUE_START 0xFF

typedef struct _queueaction_t queueaction_t;
typedef struct _queue_t queue_t;

/**
 * Callback for queue events.
 * @param conversation Conversation this text is attached to.
 * @param text Text item that is being used in the callback
 * @param i Index of the item in the queue.
 */
typedef void queuecallback_t(queue_t *queue, queueaction_t *action, uint8_t i);

typedef struct _queueaction_t {
  /** Index that the action is within the queue */
  uint8_t index;

  /** Pointer to any custom user data */
  void *data;

  /** Callback to fire the moment the action is active in the queue */
  queuecallback_t *onStart;

  /** Callback to fire when this action has ended */
  queuecallback_t *onEnd;

  /** Callback to fire every update of this queue while action is active. */
  queuecallback_t *onUpdate;
} queueaction_t;

typedef struct _queue_t {
  /** Array of items within the queue. */
  queueaction_t items[ANIMATION_QUEUE_ITEM_MAX];
  uint8_t count;

  /** Current index within the array of actions that is currently processing */
  uint8_t current;
  
  /** Internal timeline tracking */
  float timeline;

  /** Time that the current aciton started */
  float actionStarted;

  /** Delay Queue Item Storage */
  float delays[ANIMATION_QUEUE_ITEM_MAX];
} queue_t;

/**
 * Initialize the queue set.
 * @param queue Queue to initialize.
 */
void queueInit(queue_t *queue);

/**
 * Goes to the next action, or start the queue  if this is the first action.
 * @param queue Queue to skip to the next action.
 * @returns Action that was just started.
 */
queueaction_t * queueNext(queue_t *queue);

/**
 * Add a queue action to the queue.
 * @param convo Queue to add to.
 * @return Pointer to the queue action that was added.
 */
queueaction_t * queueAdd(queue_t *queue);

/**
 * Updates the queue logic.
 * @param convo Queue to update.
 * @param delta Time delta to tick the queue by.
 */
void queueUpdate(queue_t *queue, float delta);

/**
 * Dispose the queue when finished.
 * @param queue Queue to dispose.
 */
void queueDispose(queue_t *queue);

/**
 * Restacks the queue. The restack process essentially rewinds the queue so that
 * the current items move back to position 0, and allows you to add more items
 * to the queue again. Because the memory does shift, and the indexes do change
 * a lot of your pointers will break, make sure you re-reference all your 
 * pointers.
 * 
 * @param queue Queue to restack.
 */
void queueRestack(queue_t *queue);

/** Callbacks for Queue Delay Action */
void _queueDelayUpdate(queue_t *queue, queueaction_t *action, uint8_t i);
/**
 * Adds a delay action to a queue.
 * @param queue Queue to add to.
 * @param delay Delay time (in seconds) to have.
 * @return Pointer to the action added to the queue.
 */
queueaction_t * queueDelay(queue_t *queue, float delay);