/// © MiroZ 2024

#ifndef __WRITER_H__
#define __WRITER_H__

#include <stdint.h>
#include <stdarg.h>
#include <string.h>

#include <esp_log.h>

class Parser
{
protected:
	uint32_t m_delimiter = 0;
	char * m_buffer = nullptr;
	uint32_t m_num_seps = 0;
	char m_seps[16] = {0};

	bool isDelimiter(char c)
	{
		for(int n = 0; n < m_num_seps; n++)
		{
			if(c == m_seps[n])
				return true;
		}
		return false;
	}

	bool isDelimiter(uint32_t loc)
	{
		return isDelimiter(m_buffer[loc]);
	}

public:

	bool hasMore(uint32_t location)
	{
		if(m_buffer[location] == 0)
			return false;
		return true;
	}

	uint32_t getNthDelimiter(uint32_t nth, uint32_t start = 0)
	{
		if(nth == 0)
			return 0;
		
		uint32_t count = 0;

		if(isDelimiter(m_buffer[start]))
		{
			start++;
		}

		for(uint32_t n = 0 ;; n++)
		{
			if(isDelimiter(m_buffer[n+start]) || m_buffer[n+start] == 0)
			{
				count++;
				if(count == nth)
					return n + start;
			}
			if(m_buffer[n + start] == 0)
			{
				return 0xffffffff;
			}

		}
		return 0xffffffff;
	}

	uint32_t getNextDelimiter(uint32_t start)
	{
		return getNthDelimiter(1, start);
	}

	bool getElementAt(uint32_t index, char * value, uint32_t value_len)
	{
		uint32_t start = getNthDelimiter(index);

		if(!hasMore(start))
			return false;

		uint32_t end = getNextDelimiter(start);
		uint32_t copied = 0;
		
		for(uint32_t n = start; n < end; n++)
		{
			if(copied >= value_len)
				return false;
			
			if(isDelimiter(n))
				continue;;

			value[copied++] = m_buffer[n];
		}
		value[copied++] = 0;
		return true;
	}

	bool elementIs(uint32_t index, const char * value)
	{
		uint32_t start = getNthDelimiter(index);

		if(!hasMore(start))
			return false;

		if(isDelimiter(start))
			start++;

		for(uint32_t n = 0 ;;  n++)
		{
			if(value[n] == 0)
				return true;

			if(m_buffer[n + start] != value[n])
				return false;

			if(m_buffer[n + start] == 0)
				return false;
		}

		return true;
	}

public:

	Parser(const char * separators){strncpy(m_seps, separators, sizeof(m_seps)-1); m_num_seps = strlen(separators); }
	Parser(char * str, const char * separators) : Parser(separators) {m_buffer = str;}
};

class ReaderWriter : public Parser
{
protected:
	uint32_t m_buffer_len = 0;
	uint32_t m_available = 0;
	uint32_t m_write_ptr = 0;
	
public:
	void reset();
	uint32_t append(const char * str);
	uint32_t appendf(const char * format, ... );
	uint32_t append(int32_t value, uint32_t base = 10);
	uint32_t append(char c);
	char * getBuffer();
	uint32_t getLen();
	// reader stuff
	void copyString(const char *str);

public:
	ReaderWriter(uint32_t buffer_len);
	virtual ~ReaderWriter();
};


#endif // __WRITER_H__