#ifndef KADU_MODULES_H
#define KADU_MODULES_H

#include <qhbox.h>
#include <qobject.h>
#include <qstring.h>
#include <qstringlist.h>
#include <qtranslator.h>

class QLabel;
class QListView;
class QListViewItem;

/**
	Zastępuje klasę QLibrary na specyficzne potrzeby Kadu.
	\class Library
	\brief Biblioteki dzielone.
**/
class Library : public QObject
{
	private:
		QString FileName;
		void* Handle;
		
	public:
		/**
			\fn Library(const QString& file_name)
			Konstruktor przydzielający dany plik dla tego obiektu biblioteki dzielonej.
			\param file_name nazwa pliku biblioteki dzielonej.
		**/
		Library(const QString& file_name);
		~Library();

		/**
			\fn bool load()
			Ładuje przydzieloną bibliotekę dzieloną do pamięci.
		**/
		bool load();

		/**
			\fn void* resolve(const QString& symbol_name)
			Tłumaczy nazwę symbolu na funkcję z załadowanej biblioteki dzielonej.
			\param symbol_name nazwa symbolu do przetłumaczenia.
			\return wskaźnik do prztłumaczonego symbolu.
		**/
		void* resolve(const QString& symbol_name);

		/**
			\fn QString error()
			\return treść błędu, jaki wystąpił podczas ładowanie biblioteki dzielonej.
		**/
		QString error();
};

/**
	\struct ModuleInfo
	\brief Informacje o module.
**/
struct ModuleInfo
{
	QStringList depends; /*!< Jakie inne moduły są wymagane przez ten moduł. */
	QStringList conflicts; /*!< Z jakimi modułami ten moduł konfliktuje. */
	QStringList provides; /*!< Jaką cechę dostarcza ten moduł. */
	QString description; /*!< Opis modułu. */
	QString author; /*!< Autor modułu. */
	bool load_by_def; /*!< Czy moduł jest domyślnie ładowany, czy nie? */
};

/**
	Klasa reprezentująca okno dialogowe, służące do ładowanie i wyładowywania modułów.
	Ładowanie/wyładowywanie, oraz inne operacje na modułach z poziomu C++ dokonywane
	są za pomocą klasy ModulesManager. Ta klasa tworzy jedynie okno dialogowe, będące
	interfejsem do ww. klasy dla użytkownika Kadu.
	\class ModulesDialog
	\brief "Zarządca modułów"
**/
class ModulesDialog : public QHBox
{
	Q_OBJECT
	
	private:
		QListView* lv_modules;
		QLabel* l_moduleinfo;
		
	private slots:
		void loadItem();
		void unloadItem();
		void moduleAction(QListViewItem *);
		void itemsChanging();
		void getInfo();
		void refreshList();
		void keyPressEvent(QKeyEvent *);
	
	public:
		/**
			\fn ModulesDialog()
			Konstruktor standardowy.
		**/
		ModulesDialog();
		~ModulesDialog();
};

/**
	Ta klasa odpowiada za obsługę modułów Kadu.
	\class ModulesManager
	\brief Zarządzanie modułami
**/
class ModulesManager : public QObject
{
	Q_OBJECT

	private:
		typedef int InitModuleFunc();
		typedef void CloseModuleFunc();
		/**
			\struct StaticModule
			\brief Informacje o statycznym module.
		**/
		struct StaticModule
		{
			InitModuleFunc* init; /*!< Wskaźnik do funkcji inicjalizującej moduł. */
			CloseModuleFunc* close; /*!< Wskaźnik do funkcji deinicjalizującej moduł. */
		};
		/**
			Lista statycznych modułów wypełniania
			przez kod generowany przez configure.
		**/
		QMap<QString,StaticModule> StaticModules;
		/**
			Informacje o aktywnym module
			statycznym bądź zewnętrznym.
			Dla modułu statycznego lib==NULL.
			\struct Module
			\brief Informacje o aktywnym module.
		**/
		struct Module
		{
			Library* lib; /*!< Wskaźnik do obiektu biblioteki dzielonej. */
			CloseModuleFunc* close; /*!< Wskaźnik do funkcji deinicjalizującej moduł. */
			QTranslator* translator; /*!< Wskaźnik do obiektu tłumaczącego dla tego modułu. */
			ModuleInfo info; /*!< Informacje o module. */
			int usage_counter; /*!< Licznik użycia modułu. */
		};
		/**
			Lista aktywnych modułów
			statycznych bądź zewnętrznych.
		**/
		QMap<QString,Module> Modules;	
		/**
		**/
		ModulesDialog* Dialog;
		/**
			Ładuje plik z tłumaczeniem. Zwraca NULL jeśli wystąpił
			błąd.
		**/
		QTranslator* loadModuleTranslation(const QString& module_name);
		/**
			Sprawdza czy dostępne są moduły z listy
			zależności danego modułu. W razie czego
			stara się je załadować jeśli są dostępne.
			@param module_info informacje o module
		**/
		bool satisfyModuleDependencies(const ModuleInfo& module_info);
		/**
			Zwiększa liczniki użycia modułów używanych
			przez dany moduł.
			@param module_info informacje o module
		**/
		void incDependenciesUsageCount(const ModuleInfo& module_info);
		/**
			Rejestruje moduł statyczny. Funcja wywoływana
			dla wszystkich modułów statycznych przez kod
			wygenerowany przez configure.
		**/
		void registerStaticModule(const QString& module_name,
			InitModuleFunc* init,CloseModuleFunc* close);
		/**
			Rejestruje moduły statyczne. Kod funkcji jest
			generowany przez configure.
		**/
		void registerStaticModules();
		
		/**
			Skupia wszystkie tłumaczenia w jednej hierarchii
		**/
		QObject *translators;

	private slots:
		void dialogDestroyed();
	
	public:	
		/**
			\fn static void initModule()
			Inicjalizuje obsługę modułów. Metoda ta wywoływana jest przy starcie Kadu, przez jego rdzeń.
		**/
		static void initModule();

		/**
			\fn static void closeModule()
			Deinicjalizuje obsługę modułów. Metoda ta jest wywoływana przy zamykaniu Kadu, przez jego rdzeń.
		**/
		static void closeModule();

		/**
			\fn ModulesManager()
			Standardowy konstruktor.
		**/
		ModulesManager();
		~ModulesManager();

		/**
			\fn QStringList staticModules() const
			\return listę modułów wkompilowanych
			statycznie w plik wykonywalny Kadu.
		**/
		QStringList staticModules() const;

		/**
			\fn QStringList installedModules() const
			\return listę modułów zainstalowanych jako
			dzielone biblioteki (shared libraries).
		**/
		QStringList installedModules() const;

		/**
			\fn QStringList loadedModules() const
			\return listę modułów załadowanych do pamięci
			jako dzielone biblioteki (shared libraries).
		**/
		QStringList loadedModules() const;

		/**
			\fn QStringList unloadedModules() const
			\return listę modułów zainstalowanych jako
			dzielone biblioteki (shared libraries)
			i nie załadowanych aktualnie do pamięci.
		**/
		QStringList unloadedModules() const;

		/**
			\fn QStringList activeModules() const
			\return listę aktywnych modułów.
			Uwzględniane są zarówno aktywne moduły
			statyczne jak i zewnętrzne.
		**/
		QStringList activeModules() const;

		/**
			\fn bool moduleInfo(const QString& module_name, ModuleInfo& info) const
			Pobiera do info informacje o danym module.
			\param[in] module_name nazwa modułu, dla którego należy pobrać informację.
			\param[out] info struktura, w której te informacje należy umieścić.
			\return true, jeśli się udało, w przeciwnym wypadku false.
		**/
		bool moduleInfo(const QString& module_name, ModuleInfo& info) const;

		/**
			\fn bool moduleIsStatic(const QString& module_name) const
			Sprawdza czy podany moduł jest wkompilowany statycznie.
			\param module_name nazwa modułu.
			\return true, jeśli moduł jest wkompilowany, false jeśli nie jest.
		**/
		bool moduleIsStatic(const QString& module_name) const;

		/**
			\fn bool moduleIsInstalled(const QString& module_name) const
			Sprawdza czy podany moduł jest zainstalowany
			w katalogu z modułami zewnętrznymi.
			\param module_name nazwa modułu.
			\return true, jeśli moduł jest zainstalowany, false jeśli nie jest.
		**/
		bool moduleIsInstalled(const QString& module_name) const;

		/**
			\fn bool moduleIsLoaded(const QString& module_name) const
			Sprawdza czy podany moduł zewnętrzny jest załadowany.
			\param module_name nazwa modułu.
			\return true, jeśli moduł jest załadowany, false jeśli nie jest.
		**/
		bool moduleIsLoaded(const QString& module_name) const;

		/**
			\fn bool moduleIsActive(const QString& module_name) const
			Sprawdza czy podany moduł jest aktywny.
			Działa dla modułów statycznych i załadowanych
			zewnętrznych.
			\param module_name nazwa modułu.
			\return true, jeśli moduł jest aktywny, false jeśli nie jest.
		**/
		bool moduleIsActive(const QString& module_name) const;

		/**
			\fn bool conflictsWithLoaded(const QString &module_name, const ModuleInfo& module_info) const
			Sprawdza czy podany moduł konfliktuje
			z jakimś innym załadowanym modułem.
			\param module_name nazwa modułu.
			\param module_info informacje o module.
			\return true, jeśli moduł konfliktuje, false jeśli nie.
		**/
		bool conflictsWithLoaded(const QString &module_name, const ModuleInfo& module_info) const;
		
	public slots:
		/**
			\fn bool activateModule(const QString& module_name)
			Aktywuje moduł statyczny jeśli jest dostępny
			lub ładuje do pamięci i aktywuje moduł zewnętrzny.
			Przez aktywacje rozumie się wywołanie funkcji *_init z modułu.
			\param module_name nazwa modułu.
			\return true jeśli aktywacja przebiegła bezproblemowo, false w przeciwnym wypadku.
		**/
		bool activateModule(const QString& module_name);

		/**
			\fn bool deactivateModule(const QString& module_name, bool force=false)
			Deaktywuje moduł statyczny lub deaktywuje i usuwa z pamięci moduł zewnętrzny.
			\param module_name nazwa modułu.
			\return true jeśli dezaktywacja przebiegła bezproblemowo, false w przeciwnym wypadku.
		**/		
		bool deactivateModule(const QString& module_name, bool force=false);

		/**
			\fn void showDialog()
			Wyświetla okno dialogowe "Zarządcy modułów", czyli tworzy i pokazuje klasę ModulesDialog.
		**/
		void showDialog();

		/**
			\fn void moduleIncUsageCount(const QString& module_name)
			Zwiększa licznik użycia modułu o 1.
			\param module_name nazwa modułu.
		**/
		void moduleIncUsageCount(const QString& module_name);

		/**
			\fn void moduleDecUsageCount(const QString& module_name)
		 	Zmniejsza licznik użycia modułu o 1.
			\param module_name nazwa modułu.
		**/
		void moduleDecUsageCount(const QString& module_name);

		/**
			\fn void saveLoadedModules()
			Zapisuje do pliku konfiguracyjnego listę załadowanych
			modułów.
		**/
		void saveLoadedModules();
};

extern ModulesManager* modules_manager;

#endif
