/*
	ZIniReader.hpp
	Author: James Russell <jcrussell@762studios.com>
	Created: 4/27/2012

	Purpose:	
	
	Parses INI file format in memory.

	(File Begin)

	# This is a commented line
	; This is too

	[SectionA]
	Key1=Value1
	Key2 =Value2
	Key3= Value3
	Key4 = Value4

	[SectionB]
	Key1 = Value1

	...

	(File End)

	Comments must be on their own line.  Sections must be unique to a file.  Keys can be repeated, 
	but the final value seen is the value recorded.

	ZIniReader class does no I/O - it merely parses in-memory representations.

	The data structures it provides a read-only, but you can get a mutable copy of its data as 
	a ZRegistry object.  The data above would be loaded into a registry with the following layout:

	Root
	|
	+-> SectionA
	|   |
	|   +-> Key1 (Value1)
	|   +-> Key2 (Value2)
	|   +-> Key3 (Value3)
	|   +-> Key4 (Value4)
	|
	+-> SectionB
	    |
		+-> Key1 (Value1)

	License:

	TODO
*/

#ifndef _ZINIREADER_HPP
#define _ZINIREADER_HPP

#include <ZUtil/ZKVTree.hpp>

/*
IniReader class.
*/
class ZIniReader
{
public:
	/*
	Default constructor.
	*/
	ZIniReader() 
		: ErrorMessage() { }

	/*
	Destructor.
	*/
	~ZIniReader()
		{ ClearData(); }

	/*
	public ZIniReader::Read

	Reads an INI file stored as a ZString.

	@param _iniData - string holding the data of an ini file, which will be parsed
	@return (bool) - True if successful, false if failure. Use GetErrorString() to get the message
	*/
	bool Read(const ZString& _iniData) 
	{ return Read(_iniData.Data(), _iniData.Length()); }

	/*
	public ZIniReader::Read

	Reads an INI file stored as memory block

	@param data - Pointer to INI data
	@param length - Length of INI data
	@return (bool) - true if successful, false if failure (use GetErrorString() to get the message)
	*/
	bool Read(const char* data, size_t length);

	/*
	public ZIniReader::GetErrorString

	Gets the error message generated while loading the data if loading failed.  If loading
	the data was successful, this returns an empty string.

	@return (const ZString&) - error message string
	*/
	const ZString& GetErrorString() 
		{ return ErrorMessage; }

	/*
	public ZIniReader::GetSection

	Looks up a section by name and returns a pointer to the ZHashMap object. If the
	section does not exist, NULL is returned. The hashmap contains a list of key-value pairs
	found for that section

	@param sectionName - The name of the section
	@return (const ZHashMap<ZString, ZString>*) - The section, or NULL if it does not exist
	*/
	const ZHashMap<ZString, ZString>* GetSection(const ZString& sectionName);

	/*
	public ZIniReader::GetSection

	Looks up a section by ordinal and returns a pointer to the ZHashMap object. Sections
	are given in order of appearance in the file. The hashmap contains a list of key-value pairs
	found for that section.

	@param index - The index of the section, between 0 and GetSectionCount() - 1
	@return (const ZHashMap<ZString, ZString>*) - The section
	*/
	const ZHashMap<ZString, ZString>* GetSection(size_t index) 
		{ return Sections[index]; }

	/*
	public ZIniReader::GetSectionCount

	Gets the number of sections parsed. If Read() returned true, this will be at least one.
	@return (size_t) - The number of sections parsed.
	*/
	size_t GetSectionCount() 
		{ return Sections.Size(); }

	/*
	public ZIniReader::GetSectionName

	Gets the name for a section by ordinal. Sections names are given in order of appearance
	in the file.

	@param index - The index of the section, between 0 and GetSectionCount()-1
	@return (const ZString&) - The section name
	*/
	const ZString& GetSectionName(size_t index) 
		{ return SectionNames[index]; }

	/*
	public ZIniReader::GetKVTree

	Populates a ZKVTree using the read values.  If loading the data has failed,
	no data is entered.

	To get values in the kv-tree, use the path string 'Section.Key'.

	@param _kvtree - the kv-tree to contain the parsed ini values
	@return (void)
	*/
	void GetKVTree(ZKVTree& _kvtree);

private:
	DISABLE_COPY_AND_ASSIGN(ZIniReader);

	ZString ErrorMessage;													// Error Message (if an error has happened)

	ZHashMap<ZString, ZHashMap<ZString, ZString>*> StringSectionMap;		// String -> Hashmap table
	ZArray<ZHashMap<ZString, ZString>*> Sections;							// Linear order in which sections were found
	ZArray<ZString> SectionNames;											// Name of sections parsed

	void SetError(const char* message, uint32_t line);						// Sets the error message
	void ClearData();														// Clears previously read section data

};

#endif

