#ifndef MODULES_H
#define MODULES_H

#include <qstring.h>
#include <qobject.h>
#include <qstringlist.h>
#include <qdialog.h>
#include <qlistview.h>
#include <qtranslator.h>
#include <qlabel.h>
#include <qhbox.h>

/**
	Zastępuje klasę QLibrary na specyficzne potrzeby Kadu
**/
class Library : public QObject
{
	private:
		QString FileName;
		void* Handle;
		
	public:
		Library(const QString& file_name);
		~Library();
		bool load();
		void* resolve(const QString& symbol_name);
		QString error();
};

/**
 informacje o module
**/
struct ModuleInfo
{
	/**
	 jakie inne moduły są wymagane przez ten moduł
	**/
	QStringList depends;
	/**
	 z jakimi modułami ten moduł konfliktuje
	**/
	QStringList conflicts;
	/**
	 jaką cechę dostarcza ten moduł
	**/
	QStringList provides;
	/**
	 opis
	**/
	QString description;
	/**
	 autor modułu
	**/
	QString author;
};

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:
		ModulesDialog();
		~ModulesDialog();
};

class ModulesManager : public QObject
{
	Q_OBJECT

	private:
		typedef int InitModuleFunc();
		typedef void CloseModuleFunc();
		/**
			Informacje o statycznym module.
		**/
		struct StaticModule
		{
			InitModuleFunc* init;
			CloseModuleFunc* close;
		};
		/**
			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
		{
			Library* lib;
			CloseModuleFunc* close;
			QTranslator* translator;
			ModuleInfo info;
			int usage_counter;
		};
		/**
			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();

	private slots:
		void dialogDestroyed();
	
	public:	
		static void initModule();
		static void closeModule();
		ModulesManager();
		~ModulesManager();
		/**
			Zwraca listę modułów wkompilowanych
			statycznie w plik wykonywalny kadu
		**/
		QStringList staticModules() const;
		/**
			Zwraca listę modułów zainstalowanych jako
			dzielone biblioteki (shared libraries)
		**/
		QStringList installedModules() const;
		/**
			Zwraca listę modułów załadowanych do pamięci
			jako dzielone biblioteki (shared libraries)
		**/
		QStringList loadedModules() const;
		/**
			Zwraca listę modułów zainstalowanych jako
			dzielone biblioteki (shared libraries)
			i nie załadowanych aktualnie do pamięci
		**/		
		QStringList unloadedModules() const;
		/**
			Zwraca listę aktywnych modułów.
			Uwzględniane są zarówno aktywne moduły
			statyczne jak i zewnętrzne.
		**/
		QStringList activeModules() const;
		/**
			Pobiera do info informacje o module module_name jesli
			sie to udalo zwraca true w przeciwnym wypadku false		 
		**/		
		bool moduleInfo(const QString& module_name, ModuleInfo& info) const;
		/**
			Sprawdza czy podany moduł jest wkompilowany statycznie.
			@param module_name nazwa modułu
		**/
		bool moduleIsStatic(const QString& module_name) const;
		/**
			Sprawdza czy podany moduł jest zainstalowany
			w katalogu z modułami zewnętrznymi.
			@param module_name nazwa modułu
		**/
		bool moduleIsInstalled(const QString& module_name) const;
		/**
			Sprawdza czy podany moduł zewnętrzny jest załadowany
			@param module_name nazwa modułu
		**/		
		bool moduleIsLoaded(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
		**/
		bool moduleIsActive(const QString& module_name) 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
		**/
		bool conflictsWithLoaded(const QString &module_name, const ModuleInfo& module_info) const;
		
	public slots:
		void showDialog();
		/**
		 	Zwiększa licznik użycia modułu o 1
			@param module_name nazwa modułu
		**/
		void moduleIncUsageCount(const QString& module_name);
		/**
		 	Zmniejsza licznik użycia modułu o 1
			@param module_name nazwa modułu
		**/
		void moduleDecUsageCount(const QString& module_name);
		/**
			Zapisuje do pliku konfiguracyjnego listę załadowanych
			modułów.
		**/
		void saveLoadedModules();
		/**
			Aktywuje moduł statyczny jeśli jest dostępny
			lub ładuje do pamięci i aktywuje moduł zewnętrzny.
			@param module_name nazwa modułu
		**/
		bool activateModule(const QString& module_name);
		/**
			Deaktywuje moduł statyczny lub
			deaktywuje i usuwa z pamięci moduł zewnętrzny.
			@param module_name nazwa modułu
		**/		
		bool deactivateModule(const QString& module_name, bool force=false);
};

extern ModulesManager* modules_manager;

#endif
