#include <alsa/asoundlib.h>
#include <log.h>
#include <pthread.h>

#include "types.h"

#include "config.h"

void midi_open(MidiDevice *device, const char *name) {
  strlcpy(device->name, name, STR_LEN);
  device->input = NULL;
  device->output = NULL;

  snd_rawmidi_open(&device->input, &device->output, name, SND_RAWMIDI_NONBLOCK);

  device->connected = device->input != NULL && device->output != NULL;

  if (device->connected) {
    log_info("(%s) MIDI open", name);
  } else {
    log_warn("(%s) MIDI open failed", name);
  }
}

void midi_write(MidiDevice device, unsigned char code, unsigned char value) {
  if (!device.connected) {
    return;
  }

  unsigned char buffer[3];

  buffer[0] = 0xB0;
  buffer[1] = code;
  buffer[2] = value;

  snd_rawmidi_write(device.output, buffer, 3);
}

void midi_close(MidiDevice *device) {
  if (device->connected) {
    snd_rawmidi_close(device->input);
    snd_rawmidi_close(device->output);
    device->connected = false;
  }
}

void *midi_background_listen(void *args) {
  MidiBackgroundReadArgs *process_args = (MidiBackgroundReadArgs *)args;
  MidiDevice *device = process_args->device;
  Context *context = process_args->context;

  int bytes_read;
  snd_rawmidi_info_t *info;
  unsigned char buffer[3];

  log_info("(%s) background acquisition started", device->name);

  snd_rawmidi_info_malloc(&info);

  while (!context->stop && snd_rawmidi_info(device->output, info) == 0) {
    bytes_read = snd_rawmidi_read(device->input, buffer, 3);
    if (bytes_read == 3) {
      process_args->event_callback(buffer[1], buffer[2]);
    }
  }

  snd_rawmidi_info_free(info);

  if (context->stop) {
    log_info("(%s) background acquisition stopped by main thread",
             device->name);
  } else {
    log_info("(%s) background acquisition stopped after error", device->name);
    midi_close(device);
  }
  pthread_exit(NULL);
}
