#include "Uarte.h"
#include "app_uart.h"
#include "MessageType.h"
#include  "Device.h"
#include "nrfx_log.h"
#include "nrf_log_ctrl.h"

template class UarteInst<0>;
template class UarteInst<1>;

Uarte::Uarte(int _inst_no)
	: inst_no(_inst_no) {
}

Uarte::~Uarte() {
	this->UnInit();
}

void Uarte::Init(nrfx_uarte_config_t *_config) {
	_config->p_context = this;
	this->config = *_config;
	this->Start();
}

void Uarte::UnInit() {
	nrfx_uarte_rx_abort(&this->uartei);
	nrfx_uarte_uninit(&this->uartei);
	this->initialized = false;
}
void Uarte::Start() {
	this->datalen = 0;
	this->initialized = false;
	ret_code_t err;
	do {
		err  = nrfx_uarte_init(&this->uartei, &this->config, Uarte::UarteHandler);
	} while (err == NRF_ERROR_BUSY);
	APP_ERROR_CHECK(err);
	
	//nrfx_uarte_rx_enable(&this->uartei);
	
	err = nrfx_uarte_rx(&this->uartei, this->rxbuffer, UARTE_RX_BUFFER_SIZE);
	err = nrfx_uarte_rx(&this->uartei, this->second_rxbuffer, UARTE_RX_BUFFER_SIZE);
	APP_ERROR_CHECK(err);
	this->initialized = true;
}

void Uarte::Reset() {
	this->UnInit();
	this->Start();
}

void Uarte::Write(uint8_t type, void* data, uint16_t len) {
	if (!this->initialized) {
		return;
	}
	
	uint16_t length_with_type = len + 1;
	txbuffer.AppendToBuffer(&length_with_type, sizeof(length_with_type));
	txbuffer.AppendToBuffer(&type, 1);
	if (len > 0) {
		txbuffer.AppendToBuffer((uint8_t *)data, len);
	}
}

void Uarte::RawWrite(const void* data, uint16_t len) {
	if (!this->initialized) {
		return;
	}
	txbuffer.AppendToBuffer((uint8_t *)data, len);
}

void Uarte::SendNextPacket() {
	if (!this->initialized) {
		return;
	}
	
	this->pending_transmit = this->txbuffer.UsedSpace() != 0;
	if (!this->pending_transmit) {
		return;
	}
	
	uint16_t length = this->txbuffer.ReadNextPacket(&this->currentPacket[2]);
	if (!length) {
		return;
	}
			
	*((uint16_t *)&this->currentPacket[0]) = length;
	
	
	ret_code_t err_code;
	do {
		err_code = nrfx_uarte_tx(&this->uartei, this->currentPacket, UARTE_TX_PACKET_SIZE);
		if (err_code == NRF_ERROR_BUSY) {
			NRF_LOG_INFO("UART BUSY: length: %i", length + 1);
		}
		APP_ERROR_CHECK(err_code);
	} while (err_code == NRF_ERROR_BUSY);
	//NRF_LOG_INFO("WRITING OVER UART: err %i, length: %i", err_code, sending_length);
}
void Uarte::Send() {
	if (!this->initialized) {
		return;
	}
	if (!this->pending_transmit) {
		this->SendNextPacket();
	}
}



void Uarte::HandleReceivePacket(const nrfx_uarte_xfer_evt_t* p_rx_transfer) {
	this->datalen = *(uint16_t*)p_rx_transfer->p_data;
	
	if (this->OnDataCb) {
		this->OnDataCb(this, p_rx_transfer->p_data, (this->datalen + sizeof(this->datalen)));
	}
	this->datalen = 0;
	ret_code_t err = nrfx_uarte_rx(&this->uartei, p_rx_transfer->p_data, UARTE_RX_BUFFER_SIZE);	
	APP_ERROR_CHECK(err);
}

void Uarte::OnEvent(nrfx_uarte_event_t const * p_event) {
	
	switch (p_event->type) {
	case NRFX_UARTE_EVT_ERROR: {
			NRF_LOG_ERROR("Error occured on Uart: %i", p_event->data.error.error_mask);
		
			if (this->OnErrorCb) {
				this->OnErrorCb(this, p_event->data.error.error_mask);
			}
		}break;
	case NRFX_UARTE_EVT_TX_DONE: {
		
			if (this->OnTxCompleteCb) {
				this->OnTxCompleteCb(this, p_event->data.rxtx.p_data, p_event->data.rxtx.bytes);
			}
			this->SendNextPacket();
		}break;
	case NRFX_UARTE_EVT_RX_DONE: {
			const nrfx_uarte_xfer_evt_t* rx = &p_event->data.rxtx;		
			this->HandleReceivePacket(rx);
		}break;
	}
}

void Uarte::UarteHandler(nrfx_uarte_event_t const * p_event, void * p_context) {
	((Uarte*)p_context)->OnEvent(p_event);
}


template<int INST_NO>
UarteInst<INST_NO>::UarteInst()
	: Uarte(INST_NO) {
	this->uartei = this->GetInstance();
	this->pending_transmit = false;
}
