#ifndef _Tools_IniFile_h_
#define _Tools_IniFile_h_

#include "Misc/list_tem.hpp"

// JAT 7/11/06 to get Asura_Unicode_Char
#include "Core/Asura_String.h"

struct IniFileEnum
{
	char* EnumString;
	int EnumValue;

	friend bool operator== (const IniFileEnum &a, const IniFileEnum &b){return &a==&b;}
	friend bool operator!= (const IniFileEnum &a, const IniFileEnum &b){return &a!=&b;}
	
};

struct IniTextSection
{
	IniTextSection(IniTextSection* _parent);
	~IniTextSection();

	char* SectionName;
	char* SectionStart;
	int SectionStartLine;
	IniTextSection* Parent;
	List<IniTextSection*> SubSections;

	IniTextSection* GetSubSection(const char* name);
	IniTextSection* GetSubSectionByIndex(int iIndex);
	void GetSectionNameList(List<char*>&);
	int GetNumberOfSections();
	
};


struct Tools_IniFile
{
	Tools_IniFile(const char* filename,bool bCheckNetwork = true);
	~Tools_IniFile();

	//loads file if not already loaded (or previously attempted)
	//returns whether file has been loaded succesfully.
	//(Called automatically by the rest of the functions anyway)
	bool LoadIniFile(); 

	bool SetFilename(const char* filename,bool bCheckNetwork = true);
	const char* GetFilename() const {return Filename;} 

	void Reset();
	
	//get  a list of all section names that are children of the current section
	List<char*> GetSectionNameList();
	int GetNumberOfSections();
	
	
	//moves to start of named section.
	//If step_into is set to true , then this becomes the current parent section
	//(so GetSectionNameList will get the children of the new section)
	const char* GetIniTextSection(const char* section,bool stepIn=false);
	const char* GetIniTextSectionByIndex(int iSectionIndex,bool stepIn=false);
	//Go to the section above in the hierarchy (but not above the root)
	const char* GetParentSection();
	//Basically returns to the start of the file
	const char* GetRootSection();

	const char* GetCurrentSectionName();

	//read in the next line into the buffer. False if no more to read in section.
	//(Skips any lines containing nothing but whitespace or comments)
	bool GetNextIniTextLine();
	//Get the next comma seperated value as an int. False if nothing is left on the line.
	bool GetNextOnLine(int& output);
	//Get the next comma seperated value as a float. False if nothing is left on the line.
	bool GetNextOnLine(float& output);
	//Get the next comma seperated value as a string (must be in quotes). False if nothing is left on the line.
	bool GetNextOnLine(Asura_String& output);
	//Reads in the current line skipping spaces at start/end
	bool GetString(Asura_String& output);

	 
	//Get String that is given in format 'identifier = data' String left as is.
	//If bStripQuotes then start/end quotes will be removed
	bool GetStringInCurrentSection(const char* identifier,class Asura_String& outputString, bool bStripQuotes = false);
	//Get Int that is given in format 'identifier = data'
	bool GetIntInCurrentSection(const char* identifier,int& outputNumber);
	
	//Get Unsigned Int that is given in format 'identifier = data'
	bool GetUIntInCurrentSection(const char* identifier,u_int& outputNumber);

	//Get float that is given in format 'identifier = data'
	bool GetFloatInCurrentSection(const char* identifier,float& outputNumber);
	
	//Get bool that is given in format 'identifier = yes/no/true/false...'
	bool GetBoolInCurrentSection(const char* identifier,bool& outputBool);

	//List all the identifiers that make up entries in the format 'identifier = data'
	void ListIdentifiersInCurrentSection(List<Asura_String>& xIdentifierList);
	
	bool Loaded; //true if file has been loaded sucessfully
	bool Error; //true if attempt to load file has been made , and failed
	
	char*  LineBuffer; //buffer containing current Line
	int LineBufferSize;
	int LineIndex;//index number for current line (well well)

private :
	bool GetNextLine();
	void BuildSectionList();
	bool EnumValFromString(const char* buffer,int& output);

	void Initialise();
	void Shutdown();


	char* Filename;
	char* IniTextStart;
	char* IniTextPos;
	char*  LinePos;
	
	void LoadIniFileEnumerations();
	List<IniFileEnum> EnumerationList;
	
	IniTextSection* RootSection;
	IniTextSection* CurrentRootSection;
	IniTextSection* CurrentSection;


} ;

class Tools_TabbedStringTable
{
public :
	Tools_TabbedStringTable(const char* pszFilename,bool bCheckNetwork = true);
	~Tools_TabbedStringTable();

	bool m_bError;
	int m_iWidth;
	int m_iHeight;

	const char* GetEntry(int iLine,int iCol) const;

private:
	char* m_pcBuffer;
	char*** m_pppcTable;
};


class Tools_UnicodeTabbedStringTable
{
public :
	Tools_UnicodeTabbedStringTable(const char* pszFilename,bool bCheckNetwork = true);
	~Tools_UnicodeTabbedStringTable();

	bool IsError() const {return m_bError;}

	int GetWidth() const {return m_iWidth;}
	int GetHeight() const {return m_iHeight;}

	const Asura_UnicodeChar* GetEntry(int iLine,int iCol) const;


private:

	bool m_bError;
	int m_iWidth;
	int m_iHeight;

	char* m_pcBuffer;
	Asura_UnicodeChar*** m_pppwcTable;
};



void ListIdentifiersInBuffer(const char* pszBuffer,List<Asura_String>& xIdentifierList);
bool GetStringFromBuffer(const char* identifier,const char* buffer,class Asura_String& outputString,bool bStripQuotes = false);
bool GetIntFromBuffer(const char* identifier,const char* buffer,int& outputNumber);
bool GetBoolFromBuffer(const char* identifier,const char* buffer,bool& outputNumber);
bool GetFloatFromBuffer(const char* identifier,const char* buffer,float& outputNumber);


#endif //_Tools_IniFile_h_
