#ifndef CONFIG_FILE_H
#define CONFIG_FILE_H

#include <qcolor.h>
#include <qdom.h>
#include <qmap.h>
#include <qrect.h>
#include <qsize.h>
#include <qstring.h>
#include <qstringlist.h>

/**
	Klasa reprezentująca plik XML-owy z zapisem konfiguracji programu
**/
class XmlConfigFile
{
	private:
		QDomDocument DomDocument;
		void write(const QString& f = QString::null);

	public:
		/**
			Otwiera plik i go wczytuje
		**/
		XmlConfigFile();
		/**
			Wczytuje plik konfiguracyjny z dysku
		**/
		void read();
		/**
			Zapisuje na dysk zawartość konfiguracji
		**/
		void sync();
		/**
			Zapisuje do wybranego pliku kopię konfiguracji
		**/
		void saveTo(const QString &filename);

		void makeBackup();

		/**
			Zwraca glowny element konfiguracji
		**/
		QDomElement rootElement();
		/**
			Dodaje nowy element i przypisuje do rodzica.
		**/
		QDomElement createElement(QDomElement parent, const QString& tag_name);
		/**
			Zwraca pierwszy element lub element typu null jesli nie znajdzie.
		**/
		QDomElement findElement(QDomElement parent, const QString& tag_name) const;
		/**
			Zwraca pierwszy element ktorego dany atrybut ma dana wartosc
			lub element typu null jesli nie znajdzie.
		**/
		QDomElement findElementByProperty(QDomElement parent, const QString& tag_name,
			const QString& property_name, const QString& property_value) const;
		/**
			Zwraca pierwszy element lub dodaje nowy i przypisuje do rodzica.
		**/
		QDomElement accessElement(QDomElement parent, const QString& tag_name);
		/**
			Zwraca pierwszy element ktorego dany atrybut ma dana wartosc
			lub dodaje nowy i przypisuje do rodzica (ustawia rowniez zadany
			atrybut na zadana wartosc).
		**/
		QDomElement accessElementByProperty(QDomElement parent, const QString& tag_name,
			const QString& property_name, const QString& property_value);
		/**
			Usuwa wszystkie dzieci elementu.
		**/
		void removeChildren(QDomElement parent);
};

extern XmlConfigFile* xml_config_file;

/**
	Klasa reprezentująca tekstowy plik konfiguracyjny (format INI)
**/
class PlainConfigFile {

	private:
		void write() const;
		bool changeEntry(const QString &group, const QString &name, const QString &value);
		QString getEntry(const QString &group, const QString &name, bool *ok = 0) const;

		QString filename;
		QMap<QString, QMap<QString, QString> > groups;
		mutable QString activeGroupName;
		mutable QMap<QString, QString> *activeGroup;
		PlainConfigFile(const PlainConfigFile &);
		PlainConfigFile &operator=(const PlainConfigFile &);

	public:
		/**
			Otwiera plik filename i go wczytuje
		**/
		PlainConfigFile(const QString &filename);
		/**
			Wczytuje plik konfiguracyjny z dysku
		**/
		void read();
		/**
			Zapisuje na dysk zawartość konfiguracji
		**/
		void sync() const;
		/**
			Zwraca całą sekcję "name"
		**/
		QMap<QString, QString>& getGroupSection(const QString& name);

		/**
			Zwraca listę sekcji
		**/
		QStringList getGroupList() const;
		/**
			Zapisuje wartość "value" do grupy "group" w pole "name"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QString do wpisania
		**/
		void writeEntry(const QString &group,const QString &name, const QString &value);
		/**
			Zapisuje wartość "value" do grupy "group" w pole "name"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość char* do wpisania
		**/
		void writeEntry(const QString &group,const QString &name, const char *value);
		/**
			Zapisuje wartość "value" do grupy "group" w pole "name"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość int do wpisania
		**/
		void writeEntry(const QString &group,const QString &name, const int value);
		/**
			Zapisuje wartość "value" do grupy "group" w pole "name"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość double do wpisania
		**/
		void writeEntry(const QString &group,const QString &name, const double value);
		/**
			Zapisuje wartość "value" do grupy "group" w pole "name"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość bool do wpisania
		**/
		void writeEntry(const QString &group,const QString &name, const bool value);
		/**
			Zapisuje wartość "value" do grupy "group" w pole "name"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QRect do wpisania
		**/
		void writeEntry(const QString &group,const QString &name, const QRect &value);
		/**
			Zapisuje wartość "value" do grupy "group" w pole "name"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QSize do wpisania
		**/
		void writeEntry(const QString &group,const QString &name, const QSize &value);
		/**
			Zapisuje wartość "value" do grupy "group" w pole "name"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QColor do wpisania
		**/
		void writeEntry(const QString &group,const QString &name, const QColor &value);
		/**
			Zapisuje wartość "value" do grupy "group" w pole "name"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QFont do wpisania
		**/
		void writeEntry(const QString &group,const QString &name, const QFont &value);
		/**
			Zapisuje wartość "value" do grupy "group" w pole "name"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QPoint do wpisania
		**/
		void writeEntry(const QString &group,const QString &name, const QPoint &value);
		/**
			Zwraca wartość pola "name" z grupy "group"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param def domyślna wartość pola
			@return wartość danego pola, jeśli nie istnieje zwracana
			jest wartość "def"
		**/
		QString readEntry(const QString &group,const QString &name, const QString &def = QString::null) const;
		/**
			Zwraca wartość pola "name" z grupy "group"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param def domyślna wartość pola
			@return wartość danego pola, jeśli nie istnieje zwracana
			jest wartość "def"
		**/
		int readNumEntry(const QString &group,const QString &name, int def = 0) const;
		/**
			Zwraca wartość pola "name" z grupy "group"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param def domyślna wartość pola
			@return wartość danego pola, jeśli nie istnieje zwracana
			jest wartość "def"
		**/
		unsigned int readUnsignedNumEntry(const QString &group,const QString &name, unsigned int def = 0) const;
		/**
			Zwraca wartość pola "name" z grupy "group"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param def domyślna wartość pola
			@return wartość danego pola, jeśli nie istnieje zwracana
			jest wartość "def"
		**/
		double readDoubleNumEntry(const QString &group,const QString &name, double def = 0.0) const;
		/**
			Zwraca wartość pola "name" z grupy "group"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param def domyślna wartość pola
			@return wartość danego pola, jeśli nie istnieje zwracana
			jest wartość "def"
		**/
		bool readBoolEntry(const QString &group,const QString &name, bool def = false) const;
		/**
			Zwraca wartość pola "name" z grupy "group"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param def domyślna wartość pola
			@return wartość danego pola, jeśli nie istnieje zwracana
			jest wartość "def"
		**/
		QRect readRectEntry(const QString &group,const QString &name, const QRect *def = 0L) const;
		/**
			Zwraca wartość pola "name" z grupy "group"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param def domyślna wartość pola
			@return wartość danego pola, jeśli nie istnieje zwracana
			jest wartość "def"
		**/
		QSize readSizeEntry(const QString &group,const QString &name, const QSize *def = 0L) const;
		/**
			Zwraca wartość pola "name" z grupy "group"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param def domyślna wartość pola
			@return wartość danego pola, jeśli nie istnieje zwracana
			jest wartość "def"
		**/
		QColor readColorEntry(const QString &group,const QString &name, const QColor *def = 0L) const;
		/**
			Zwraca wartość pola "name" z grupy "group"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param def domyślna wartość pola
			@return wartość danego pola, jeśli nie istnieje zwracana
			jest wartość "def"
		**/
		QFont readFontEntry(const QString &group,const QString &name, const QFont *def = 0L) const;
		/**
			Zwraca wartość pola "name" z grupy "group"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param def domyślna wartość pola
			@return wartość danego pola, jeśli nie istnieje zwracana
			jest wartość "def"
		**/
		QPoint readPointEntry(const QString &group,const QString &name, const QPoint *def = 0L) const;
		/**
			Usuwa pole "name" z grupy "group"
			@param group nazwa grupy
			@param name nazwa pola w grupie
		**/
		void removeVariable(const QString &group, const QString &name);
		/**
			Tworzy pole "name" w grupie "group" jeśli ono nie istnieje
			i ustawia wartość na "value"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QPoint do wpisania
		**/
		void addVariable(const QString &group,const QString &name, const QString &value);
		/**
			Tworzy pole "name" w grupie "group" jeśli ono nie istnieje
			i ustawia wartość na "value"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QPoint do wpisania
		**/
		void addVariable(const QString &group,const QString &name, const char *value);
		/**
			Tworzy pole "name" w grupie "group" jeśli ono nie istnieje
			i ustawia wartość na "value"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QPoint do wpisania
		**/
		void addVariable(const QString &group,const QString &name, const int value);
		/**
			Tworzy pole "name" w grupie "group" jeśli ono nie istnieje
			i ustawia wartość na "value"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QPoint do wpisania
		**/
		void addVariable(const QString &group,const QString &name, const double value);
		/**
			Tworzy pole "name" w grupie "group" jeśli ono nie istnieje
			i ustawia wartość na "value"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QPoint do wpisania
		**/
		void addVariable(const QString &group,const QString &name, const bool value);
		/**
			Tworzy pole "name" w grupie "group" jeśli ono nie istnieje
			i ustawia wartość na "value"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QPoint do wpisania
		**/
		void addVariable(const QString &group,const QString &name, const QRect &value);
		/**
			Tworzy pole "name" w grupie "group" jeśli ono nie istnieje
			i ustawia wartość na "value"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QPoint do wpisania
		**/
		void addVariable(const QString &group,const QString &name, const QSize &value);
		/**
			Tworzy pole "name" w grupie "group" jeśli ono nie istnieje
			i ustawia wartość na "value"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QPoint do wpisania
		**/
		void addVariable(const QString &group,const QString &name, const QColor &value);
		/**
			Tworzy pole "name" w grupie "group" jeśli ono nie istnieje
			i ustawia wartość na "value"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QPoint do wpisania
		**/
		void addVariable(const QString &group,const QString &name, const QFont &value);
		/**
			Tworzy pole "name" w grupie "group" jeśli ono nie istnieje
			i ustawia wartość na "value"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QPoint do wpisania
		**/
		void addVariable(const QString &group,const QString &name, const QPoint &value);
};

/**
	Klasa reprezentująca plik z zapisem konfiguracji programu
**/
class ConfigFile {

	private:
		bool changeEntry(const QString &group, const QString &name, const QString &value);
		QString getEntry(const QString &group, const QString &name, bool *ok = 0) const;

		QString filename;
	public:
		/**
			Otwiera plik filename i go wczytuje
		**/
		ConfigFile(const QString &filename);
		/**
			Zapisuje na dysk zawartość konfiguracji
		**/
		void sync() const;
		/**
			Zapisuje wartość "value" do grupy "group" w pole "name"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QString do wpisania
		**/
		void writeEntry(const QString &group,const QString &name, const QString &value);
		/**
			Zapisuje wartość "value" do grupy "group" w pole "name"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość char* do wpisania
		**/
		void writeEntry(const QString &group,const QString &name, const char *value);
		/**
			Zapisuje wartość "value" do grupy "group" w pole "name"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość int do wpisania
		**/
		void writeEntry(const QString &group,const QString &name, const int value);
		/**
			Zapisuje wartość "value" do grupy "group" w pole "name"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość double do wpisania
		**/
		void writeEntry(const QString &group,const QString &name, const double value);
		/**
			Zapisuje wartość "value" do grupy "group" w pole "name"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość bool do wpisania
		**/
		void writeEntry(const QString &group,const QString &name, const bool value);
		/**
			Zapisuje wartość "value" do grupy "group" w pole "name"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QRect do wpisania
		**/
		void writeEntry(const QString &group,const QString &name, const QRect &value);
		/**
			Zapisuje wartość "value" do grupy "group" w pole "name"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QSize do wpisania
		**/
		void writeEntry(const QString &group,const QString &name, const QSize &value);
		/**
			Zapisuje wartość "value" do grupy "group" w pole "name"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QColor do wpisania
		**/
		void writeEntry(const QString &group,const QString &name, const QColor &value);
		/**
			Zapisuje wartość "value" do grupy "group" w pole "name"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QFont do wpisania
		**/
		void writeEntry(const QString &group,const QString &name, const QFont &value);
		/**
			Zapisuje wartość "value" do grupy "group" w pole "name"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QPoint do wpisania
		**/
		void writeEntry(const QString &group,const QString &name, const QPoint &value);
		/**
			Zwraca wartość pola "name" z grupy "group"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param def domyślna wartość pola
			@return wartość danego pola, jeśli nie istnieje zwracana
			jest wartość "def"
		**/
		QString readEntry(const QString &group,const QString &name, const QString &def = QString::null) const;
		/**
			Zwraca wartość pola "name" z grupy "group"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param def domyślna wartość pola
			@return wartość danego pola, jeśli nie istnieje zwracana
			jest wartość "def"
		**/
		int readNumEntry(const QString &group,const QString &name, int def = 0) const;
		/**
			Zwraca wartość pola "name" z grupy "group"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param def domyślna wartość pola
			@return wartość danego pola, jeśli nie istnieje zwracana
			jest wartość "def"
		**/
		unsigned int readUnsignedNumEntry(const QString &group,const QString &name, unsigned int def = 0) const;
		/**
			Zwraca wartość pola "name" z grupy "group"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param def domyślna wartość pola
			@return wartość danego pola, jeśli nie istnieje zwracana
			jest wartość "def"
		**/
		double readDoubleNumEntry(const QString &group,const QString &name, double def = 0.0) const;
		/**
			Zwraca wartość pola "name" z grupy "group"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param def domyślna wartość pola
			@return wartość danego pola, jeśli nie istnieje zwracana
			jest wartość "def"
		**/
		bool readBoolEntry(const QString &group,const QString &name, bool def = false) const;
		/**
			Zwraca wartość pola "name" z grupy "group"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param def domyślna wartość pola
			@return wartość danego pola, jeśli nie istnieje zwracana
			jest wartość "def"
		**/
		QRect readRectEntry(const QString &group,const QString &name, const QRect *def = 0L) const;
		/**
			Zwraca wartość pola "name" z grupy "group"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param def domyślna wartość pola
			@return wartość danego pola, jeśli nie istnieje zwracana
			jest wartość "def"
		**/
		QSize readSizeEntry(const QString &group,const QString &name, const QSize *def = 0L) const;
		/**
			Zwraca wartość pola "name" z grupy "group"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param def domyślna wartość pola
			@return wartość danego pola, jeśli nie istnieje zwracana
			jest wartość "def"
		**/
		QColor readColorEntry(const QString &group,const QString &name, const QColor *def = 0L) const;
		/**
			Zwraca wartość pola "name" z grupy "group"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param def domyślna wartość pola
			@return wartość danego pola, jeśli nie istnieje zwracana
			jest wartość "def"
		**/
		QFont readFontEntry(const QString &group,const QString &name, const QFont *def = 0L) const;
		/**
			Zwraca wartość pola "name" z grupy "group"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param def domyślna wartość pola
			@return wartość danego pola, jeśli nie istnieje zwracana
			jest wartość "def"
		**/
		QPoint readPointEntry(const QString &group,const QString &name, const QPoint *def = 0L) const;
		/**
			Usuwa pole "name" z grupy "group"
			@param group nazwa grupy
			@param name nazwa pola w grupie
		**/
		void removeVariable(const QString &group, const QString &name);
		/**
			Tworzy pole "name" w grupie "group" jeśli ono nie istnieje
			i ustawia wartość na "value"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QPoint do wpisania
		**/
		void addVariable(const QString &group,const QString &name, const QString &value);
		/**
			Tworzy pole "name" w grupie "group" jeśli ono nie istnieje
			i ustawia wartość na "value"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QPoint do wpisania
		**/
		void addVariable(const QString &group,const QString &name, const char *value);
		/**
			Tworzy pole "name" w grupie "group" jeśli ono nie istnieje
			i ustawia wartość na "value"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QPoint do wpisania
		**/
		void addVariable(const QString &group,const QString &name, const int value);
		/**
			Tworzy pole "name" w grupie "group" jeśli ono nie istnieje
			i ustawia wartość na "value"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QPoint do wpisania
		**/
		void addVariable(const QString &group,const QString &name, const double value);
		/**
			Tworzy pole "name" w grupie "group" jeśli ono nie istnieje
			i ustawia wartość na "value"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QPoint do wpisania
		**/
		void addVariable(const QString &group,const QString &name, const bool value);
		/**
			Tworzy pole "name" w grupie "group" jeśli ono nie istnieje
			i ustawia wartość na "value"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QPoint do wpisania
		**/
		void addVariable(const QString &group,const QString &name, const QRect &value);
		/**
			Tworzy pole "name" w grupie "group" jeśli ono nie istnieje
			i ustawia wartość na "value"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QPoint do wpisania
		**/
		void addVariable(const QString &group,const QString &name, const QSize &value);
		/**
			Tworzy pole "name" w grupie "group" jeśli ono nie istnieje
			i ustawia wartość na "value"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QPoint do wpisania
		**/
		void addVariable(const QString &group,const QString &name, const QColor &value);
		/**
			Tworzy pole "name" w grupie "group" jeśli ono nie istnieje
			i ustawia wartość na "value"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QPoint do wpisania
		**/
		void addVariable(const QString &group,const QString &name, const QFont &value);
		/**
			Tworzy pole "name" w grupie "group" jeśli ono nie istnieje
			i ustawia wartość na "value"
			@param group nazwa grupy
			@param name nazwa pola w grupie
			@param value wartość QPoint do wpisania
		**/
		void addVariable(const QString &group,const QString &name, const QPoint &value);
};

//TODO: po wydaniu 0.4 trzeba zmienić nazwę na config_file i wywalić define'a
extern ConfigFile *config_file_ptr;
#define config_file (*config_file_ptr)

#endif
