/*
  defines Settings - class that stores all the settings used by bob_dom_bob and 
  bob_dom_cut when loading/saving bob1/cut1 data
*/

#ifndef SETTINGS_INCLUDED
#define SETTINGS_INCLUDED

#include "../common/ext_list.h"

class Settings
{
	public:
#ifdef X2BC_USE_INI_FORMATS
		template <class Ty1, class Ty2>
		class pair
		{
			public:
				Ty1 left;
				Ty2 right;
				
				pair(const Ty1 &val1, const Ty2 &val2) { left=val1; right=val2; }
				pair(const pair &other) { left=other.left; right=other.right; }
				pair() { }
		};

		struct NumberFormat
		{
			enum OutputFormat
			{
				Float,
				Integer
			};
			char type;
			double multiplier;
			OutputFormat outformat;
		};
		
		class StatFormat
		{
			public:
				struct token
				{
					int count;
					char type;
					char *data;
					NumberFormat *numFormat;
					
					token() { data=0; }
					~token() { delete[] data; }
				};
				int id;
			
			private:
				typedef ext::list<token*> TokenList;
				
			public:
				typedef TokenList::iterator iterator;
				typedef TokenList::const_iterator const_iterator;
				
				TokenList tokens;
				bool issueWarning;
				TokenList::size_type cumulativeTokenCount;
				
				StatFormat() { issueWarning=false; cumulativeTokenCount=0; }
				~StatFormat()
				{
					for(iterator &it=tokens.begin(); it!=tokens.end(); ++it){
						delete *it;
					}
				}
		};
		
		typedef pair<const char *, const char*> conststringpair;
#endif // defined(X2BC_USE_INI_FORMATS)

		enum ErrorType{
			Error,
			Warning
		};
		
		enum ErrorCodes
		{
			E_BadConstantDeclaration,
			E_BadFormatDeclaration,
			E_SectionEmpty,
			W_LineIgnored,
			W_ConstantAlwaysZero
		};
		
		enum SwitchValue
		{
			on,
			off,
			notSet
		};
		
		struct ErrorMsg
		{
			ErrorType type;
			ErrorCodes code;
			char message[255];
		};
	
	private:
		typedef ext::list<ErrorMsg*> ErrorList;
#ifdef X2BC_USE_INI_FORMATS 
		typedef ext::list<StatFormat*> FormatList;
#endif

	public:
		typedef ErrorList::iterator ErrorIterator;
#ifdef X2BC_USE_INI_FORMATS
		typedef FormatList::iterator iterator;
		typedef FormatList::const_iterator const_iterator;
#endif

	private:
#ifdef X2BC_USE_INI_FORMATS
		typedef bool ParsePairCallback(const char *pszSectionName, conststringpair &);
		typedef ext::list<NumberFormat*> NumberFormatList;
		
		NumberFormatList m_constants;
#endif
		
		bool m_bOutputWarnings; // write warnings to file
		bool m_bConvert;				// convert values
		bool m_bStatFormatWarnings; // make warning if format is marked with warning sign
		bool m_bXtraPntInfo; // whether extra point info is outputed to BOD
		bool m_bXtraX3BobInfo; // extra x3 bob info
		//SwitchValue m_X3BOB; // force/suppress extra bob3 info loading

		void error(ErrorType type, ErrorCodes code, const char *format, ...);

#ifdef X2BC_USE_INI_FORMATS
		char * readSection(const char *pszSection, const char *pszFileName, size_t *size);
		conststringpair parsePair(const char *left, const char *right);
		bool parseLines(const char *pszSectionName, char *pszData, size_t size, ParsePairCallback *callback);
		
		bool parseStatFormat(const char *pszSectionName, conststringpair &p);
		bool parseFormatString(const char *pszSectionName, StatFormat *f, char *format);
		
		NumberFormat * findNumberFormat(char ch);
#endif

	public:
		ErrorList errors;
#ifdef X2BC_USE_INI_FORMATS 
		FormatList formats;
		
		bool parseConstant(const char *pszSectionName, conststringpair &p);
		bool parseFormat(const char *pszSectionName, conststringpair &p);
#endif
		
		bool loadINI(const char *pszFileName);
		
		bool outputWarnings() const { return m_bOutputWarnings; }
		void outputWarnings(bool val) { m_bOutputWarnings=val; }
		bool convert() const { return m_bConvert; }
		void convert(bool val) { m_bConvert=val; }
		bool statFormatWarnings() const { return m_bStatFormatWarnings; }
		void statFormatWarnings(bool val) { m_bStatFormatWarnings=val; }
		bool extraPntInfo() const { return m_bXtraPntInfo; }
		void extraPntInfo(bool val) { m_bXtraPntInfo=val; }
		bool extraX3BobInfo() const { return m_bXtraX3BobInfo; }
		void extraX3BobInfo(bool val) { m_bXtraX3BobInfo=val; }
		//SwitchValue X3BOB() const { return m_X3BOB; }
		//void X3BOB(SwitchValue val) { m_X3BOB=val; }

		void clearErrors()
		{
			for(ErrorIterator &it=errors.begin(); it!=errors.end(); ++it){
				delete *it;
			}
			errors.clear();
		}
		
		Settings() { outputWarnings(false); convert(true); statFormatWarnings(true); extraPntInfo(true); /*X3BOB(notSet);*/ }
		
		~Settings()
		{
#ifdef X2BC_USE_INI_FORMATS
			for(iterator &it=formats.begin(); it!=formats.end(); ++it){
				delete *it;
			}
#endif
			clearErrors();
		}
		
#ifdef X2BC_USE_INI_FORMATS 
		const StatFormat* findStatFormat(int ID) const
		{
			for(const_iterator &it=formats.begin(); it!=formats.end(); ++it){
				if(it->id==ID) return *it;
			}
			return 0;
		}
#endif
};

#endif // !defined(SETTINGS_INCLUDED)