// intellectual property is bullshit bgdc

#include "midix.hpp"

#ifdef __AVR__
#include "board.hpp"
#else
#define PIN_SET(...)
#define PIN_CLR(...)
#endif

#include <stdbool.h>
#include <stddef.h>
#include <inttypes.h>

void midix::rxc()
{
	int c = m_serport.recv();

	if (c < 0)
	{
		m_message.command = MIDI_ICMD_NOP;
		m_message_pos = 0;
		if (m_receiving_sysex)
		{
			m_receiving_sysex = false;
			m_sysex_buf_avail = true;
		}
	}
	else if (m_receiving_sysex)
	{
		if (c == MIDI_CMD_END_SYSEX)
		{
			if (m_message_pos < MIDIX_SYSEX_LEN)
				m_sysex_buf[m_message_pos] = 0;
			else
				m_sysex_buf[MIDIX_SYSEX_LEN - 1] = 0;

			send();
		}
		else if (m_message_pos < MIDIX_SYSEX_LEN)
			m_sysex_buf[m_message_pos++] = c;
	}
	else if (c == MIDI_CMD_START_SYSEX)
	{
		if (m_sysex_buf_avail)
		{
			m_message.command = MIDI_ICMD_SYSEX;
			m_message.content = m_sysex_buf;
			m_message_pos = 0;
			m_receiving_sysex = true;
			m_sysex_buf_avail = false;
		}
		else
		{
			m_message.command = MIDI_ICMD_SYSEX_OVERFLOW;
			send();
		}
	}
	else if (c >= 0x80)
	{
		m_message.command = (uint8_t) c;
		m_message_pos = 1;
	}
	else
	{
		if (m_message_pos <= sizeof(m_message.arguments))
		{
			m_message.arguments[m_message_pos - 1] = c;
			m_message_pos++;
		}

		if (m_message.command &&
			m_message_pos == midi_num_args(m_message.command) + 1)
		{
			send();
		}
	}
}

void midix::dre()
{
	uint8_t c;
	bool has_c = m_outbuf.pop(c);

	if (has_c)
		m_serport.send(c);
	else
		m_serport.dreie(false);
}

void midix::send(uint8_t const * msg)
{
	uint8_t b;
	while ((b = *msg++))
	{
		while (!m_outbuf.push(b));
		m_serport.dreie(true);
	}
}

void midix::send_sysex(uint8_t const * msg)
{
	send((uint8_t const *) "\xF0");
	send(msg);
	send((uint8_t const *) "\xF7");
}

void midix::sysex_release_buffer(uint8_t * buf)
{
	assert(!m_sysex_buf_avail);
	assert(buf == &m_sysex_buf[0]);
	buf[0] = 0;
	m_sysex_buf_avail = true;
}
