#ifndef H_SimpleXML_H
#define H_SimpleXML_H

#include <string>

namespace SimpleXML
{	 // ################################################################################################
// #################################################################################################

// BUGBUG remove & use string_view
class str_view
{
public:
	const char *ps;
	const char *pe;

public:
	constexpr str_view() : ps(nullptr), pe(nullptr) {}
	constexpr str_view(const char *_Str) : ps(_Str), pe(_Str) {}
	constexpr str_view(const char *_Str, size_t _Len) : ps(_Str), pe(_Str + _Len) {}
	constexpr str_view(const char *_Beg, const char *_End) : ps(_Beg), pe(_End) {}
	bool empty() const noexcept { return ps >= pe; }
	size_t size() const noexcept { return static_cast<size_t>(pe - ps); }
	const char *data() const noexcept { return ps; }
	const char *begin() const noexcept { return ps; }
	const char *end() const noexcept { return pe; }
};

constexpr str_view operator""_v(const char *_Str, size_t _Len) noexcept
{
	return (str_view(_Str, _Len));
}
inline bool operator==(const str_view &Lhs, const str_view &Rhs)
{
	size_t l_len = Lhs.pe - Lhs.ps;

	if (l_len != (size_t)(Rhs.pe - Rhs.ps)) {
		return false;
	}
	return !(memcmp(Lhs.ps, Rhs.ps, l_len));
}

inline bool operator!=(const str_view &Lhs, const str_view &Rhs)
{
	return !(Lhs == Rhs);
}

// #################################################################################################

enum class cbRet
{
	Stop,
	Continue,
	ContinueSkipAttr
};

class IParseCallback
{
public:
	virtual ~IParseCallback() {}
	virtual cbRet OnTag(int top, const str_view *path, const str_view &attr) const = 0;
	virtual cbRet OnBody(int top, const str_view *path, const str_view &body) const = 0;
	virtual cbRet OnAttr(int top, const str_view *path, const str_view &name, const str_view &val) const = 0;
};

// #################################################################################################

enum class parseRet
{
	Ok,
	BadArgs,		  // bad argument(s)
	UnexpectedEnd,	  // unexpected end of data
	UnexpectedChr,	  // unexpected symbol
	BadEndTag,		  // tag end mismatch
	DepthOvflow,	  // depth overflow
	EqualMissed,	  // = missed
	QuoteMissed,	  // ' or " missed
	COUNT
};

// !Note: ---------------------------------------------------------------------
// 1) Multibyte only! (supposed UTF8 decoding in callback)
// 2) &Entity; should be decoded in callback -- can be found in attribute value
// 3) <![CDATA[should be decoded in callback]]> -- can be found inside body
// 4) <?any content skipped ?>
// 5) <!-- comment also skipped silently -->
// 6) <!DOCTYPE IGNORED ... > ... ]]>
//-----------------------------------------------------------------------------
parseRet parse(const char *xml, size_t size, const IParseCallback *cb);

// #################################################################################################
}	 // namespace SimpleXML
#endif	  // H_SimpleXML_H
