#ifndef __EVENTS_H
#define __EVENTS_H

#include "stm32g441xx.h"

#include <stdint.h>

typedef enum {
  BTN_PRESS_PREV,
  BTN_PRESS_R2D,
  BTN_PRESS_OK,
  BTN_PRESS_NEXT
} ButtonPressEvent;

typedef enum { ENC0, ENC1 } Encoder;
typedef enum { ENC_CHANGE_INC, ENC_CHANGE_DEC } EncoderChangeDirection;
typedef struct {
  Encoder encoder;
  EncoderChangeDirection dir;
} EncoderChangeEvent;

typedef enum { EV_BTN_PRESS, EV_ENC_CHANGE } EventType;

typedef struct {
  EventType type;
  union {
    ButtonPressEvent btn_press;
    EncoderChangeEvent enc_change;
  };
} Event;

#define EVENT_QUEUE_SIZE 32
typedef struct {
  Event ring_buffer[EVENT_QUEUE_SIZE];
  uint16_t read_idx;
  uint16_t write_idx;
} EventQueue;

/**
 * @brief Push an event to the back of the queue.
 *
 * The event is deep-copied to the queue, so it can be deallocated after the
 * call is complete.
 */
void event_push(Event* ev);
/**
 * @brief Pop an event from the start of the queue.
 *
 * The value in the queue may be overwritten with the next event_push() call.
 * Since that call can happen in an interrupt, i.e. is probably out of control
 * of the event_pop() caller, we return by value here.
 */
Event event_pop();

uint16_t event_num_pending();
uint16_t event_num_free();

void handle_events();

#endif // __EVENTS_H
