#pragma once
#include <mutex>
#include <map>
#include <memory>
#include <ModuleGenerator.h>
#include <ProcessorGenerator.h>
#include <OptimizerGenerator.h>

#define REGISTER_MODULE(CLASS) registerModuleGenerator<CLASS>(#CLASS);
#define REGISTER_PROCESSOR(CLASS) registerProcessorGenerator<CLASS>(#CLASS);
#define REGISTER_OPTIMIZER(CLASS) registerOptimizerGenerator<CLASS>(#CLASS);

namespace mdd {
	class Registration {
	private:
		std::map<std::string, std::shared_ptr<IModuleGenerator>> _modules;
		std::map<std::string, std::shared_ptr<IProcessorGenerator>> _processors;
		std::map<std::string, std::shared_ptr<IOptimizerGenerator>> _optimizers;
		//std::mutex _mutex;
	public:
		template<class MODULE_CLASS>
		void registerModuleGenerator(const std::string& name) {
			auto generator = std::make_shared<ModuleGenerator<MODULE_CLASS>>();
			if (generator != nullptr)
			{
				//_mutex.lock();
				_modules[name] = generator;
				//_mutex.unlock();
			}
		}

		template<class PROCESSOR_CLASS>
		void registerProcessorGenerator(const std::string& name) {
			auto generator = std::make_shared<ProcessorGenerator<PROCESSOR_CLASS>>();
			if (generator != nullptr)
			{
				//_mutex.lock();
				_processors[name] = generator;
				//_mutex.unlock();
			}
		}

		template<class OPTIMIZER_CLASS>
		void registerOptimizerGenerator(const std::string& name) {
			auto generator = std::make_shared<OptimizerGenerator<OPTIMIZER_CLASS>>();
			if (generator != nullptr)
			{
				//_mutex.lock();
				_optimizers[name] = generator;
				//_mutex.unlock();
			}
		}
		Registration();
		IModule::Ptr generateModule(const std::string& name);
		std::vector<std::string> getModules();

		IProcessor::Ptr generateProcessor(const std::string& name);
		std::vector<std::string> getProcessors();

		IOptimizer::Ptr generateOptimizer(const std::string& name);
		std::vector<std::string> getOptimizers();
	};
}

