#pragma once

#include <inttypes.h>
#include "crc16.hpp"

template<unsigned packetSize>
class UartBlock
{
public:
	static const unsigned kPacketSize=packetSize;
	UartBlock() : qosMsg(0), qosSync(0), qosFullSync(0), pos(0) { }
	virtual void onMsg(uint8_t* buffer) = 0;
	virtual void send(const uint8_t* buffer, unsigned len) = 0;
	void onChar(uint8_t c)
	{
		if (!(pos || (c==kMarker)))
			return;
		buffer[pos++] = c;
		if (pos != kPacketSize)
			return;
		uint16_t packetCrc = (buffer[kPacketSize-2]<<8)+buffer[kPacketSize-1];
		if (packetCrc == CRC16::compute(buffer+1, kPacketSize-3)) {
			qosMsg++;
			onMsg(buffer+1);
			pos = 0;
		} else {
			unsigned i = 1;
			while ((i<kPacketSize) && (buffer[i]!=kMarker))
				i++;
			for (unsigned j=0; j<kPacketSize-i; j++)
				buffer[j] = buffer[j+i];
			pos = kPacketSize - i;
			if (pos)
				qosSync++;
			else
				qosFullSync++;
		}
	}

	void sendMsg(const uint8_t* buffer)
	{
		uint8_t b = kMarker;
		send(&b, 1);
		send(buffer, kPacketSize-3);
		uint16_t packetCrc = CRC16::compute(buffer, kPacketSize-3);
		b = packetCrc >> 8;
		send(&b, 1);
		b = packetCrc & 0xff;
		send(&b, 1);
	}

	unsigned long qosMsg;
	unsigned long qosSync;
	unsigned long qosFullSync;

private:
	static const uint8_t kMarker = 0x3A;

	uint8_t buffer[kPacketSize];
	uint8_t pos;
};
