#ifndef VIEWFORMAT_HPP
#define VIEWFORMAT_HPP

#include "../JuceLibraryCode/JuceHeader.h"

class AParser
{
public:
	virtual void parse(char **ppStream)
	{
		printf("%s\n", extractField(ppStream));
	}

protected:
	AParser() {}
	~AParser() {}

	struct Field
	{
		Field(const char *_name, AParser &_member, bool &hasTag)
		: name(_name)
		, member(_member)
		, m_hasTag(hasTag)
		{
			m_hasTag = false;
		}
		const char *name;
		AParser &member;
		bool &m_hasTag;
	};

	char *extractField(char **ppStream)
	{
		static char field[256];
		char *pStream = *ppStream;
		char *pField = field;

		skip(&pStream);

		for (size_t i=0; i < sizeof(field); i++)
		{
			if (*pStream == ',')
				break;

			if (*pStream == ';')
				break;

			if (*pStream == '=')
				break;

			*(pField++) = *(pStream++);
		}
		*pField = 0;
		*ppStream = pStream;

		return field;
	}

private:
	void skip(char **ppStream)
	{
		while ((**ppStream == '\\') || (**ppStream == '?') || (**ppStream == ',') || (**ppStream == ';') || (**ppStream == '=') || (**ppStream <= 0x20))
		{
			(*ppStream)++;
		};

	}
};

// ?BBOX=1.0, 2.0, 3.0, 4.0?CAMERA/Pos=1.0, 2.0, 3.0
class ViewFormat : private AParser
{
private:
	struct Bbox : public AParser
	{
		float n, e, s, w;

		void parse(char **ppStream)
		{
			n = String(extractField(ppStream)).getFloatValue();
			e = String(extractField(ppStream)).getFloatValue();
			s = String(extractField(ppStream)).getFloatValue();
			w = String(extractField(ppStream)).getFloatValue();
		}
	};

	struct Camera : public AParser
	{
		float lookatLon, lookatLat, lookatRange, lookatTilt, lookatHeading;

		void parse(char **ppStream)
		{
			lookatLon = String(extractField(ppStream)).getFloatValue();
			lookatLat = String(extractField(ppStream)).getFloatValue();
			lookatRange = String(extractField(ppStream)).getFloatValue();
			lookatTilt = String(extractField(ppStream)).getFloatValue();
			lookatHeading = String(extractField(ppStream)).getFloatValue();
		}
	};

	struct View : public AParser
	{
		float horizFov, vertFov, horizPixels, vertPixels, terrainEnabled;

		void parse(char **ppStream)
		{
			horizFov = String(extractField(ppStream)).getFloatValue();
			vertFov = String(extractField(ppStream)).getFloatValue();
			horizPixels = String(extractField(ppStream)).getFloatValue();
			vertPixels = String(extractField(ppStream)).getFloatValue();
			terrainEnabled = String(extractField(ppStream)).getFloatValue();
		}
	};

	AParser::Field fieldBbox;
	AParser::Field fieldCamera;
	AParser::Field fieldView;
	AParser::Field *fields[3];

public:
	bool has_bbox;
	Bbox bbox;

	bool has_camera;
	Camera camera;

	bool has_view;
	View view;

	ViewFormat()
	: fieldBbox(AParser::Field("BBox", bbox, has_bbox))
	, fieldCamera(AParser::Field("Camera", camera, has_camera))
	, fieldView(AParser::Field("View", view, has_view))
	{
		fields[0] = &fieldBbox;
		fields[1] = &fieldCamera;
		fields[2] = &fieldView;
	}
	~ViewFormat() {}

	void parse(const char *pStream)
	{
		char *pSubStream = (char*)pStream;

		for (unsigned i=0; i < sizeof(fields)/sizeof(*fields); i++)
		{
			char *pField = extractField(&pSubStream);
			if (!stricmp(pField, fields[i]->name))
			{
				fields[i]->member.parse(&pSubStream);
				fields[i]->m_hasTag = true;
			}
		}
	}

};

#endif // VIEWFORMAT_HPP
