#ifndef WORLD_BUILD_H
#define WORLD_BUILD_H
#include <flecs.h>
#include <string>
#include <list>
#include <map>
namespace ECS
{
struct GameWorldData {
	std::vector<flecs::entity> npcs;
	std::vector<flecs::entity> vehicles;
	std::vector<flecs::entity> settlements;
};
struct GameWorld {
	struct GameWorldData *data;
	struct Parameter {
		int type;
	};
	struct IntegerParameter : public Parameter {
		int value;

	public:
		IntegerParameter(int value)
			: value(value)
		{
		}
		int get()
		{
			return value;
		}
	};
	template <class T> struct ValueParameter : public Parameter {
		T value;

	public:
		ValueParameter(const T &value)
			: value(value)
		{
		}
		T get()
		{
			return value;
		}
		const T &get() const
		{
			return value;
		}
	};
	struct Command {
		virtual int
		operator()(const std::vector<Parameter *> &args) = 0;
	};
	struct QueueTask {
		Command *command;
		std::vector<Parameter *> args;
	};
	std::map<std::string, Command *> commands;
	std::list<QueueTask> queue;
	int command(const std::string &cmd,
		    const std::vector<Parameter *> &args)
	{
		if (commands.find(cmd) != commands.end())
			return (*commands.at(cmd))(args);
		return -1;
	}
	void queue_command(const std::string &cmd,
			   const std::vector<Parameter *> &args)
	{
		if (commands.find(cmd) != commands.end()) {
			QueueTask task{ commands.at(cmd), args };
			queue.push_back(task);
		}
	}
	void queue_command(Command *cmd, const std::vector<Parameter *> &args)
	{
		QueueTask task{ cmd, args };
		queue.push_back(task);
	}
	template <class CommandType> void add_command(const std::string &name)
	{
		CommandType *cmd = new CommandType();
		commands[name] = cmd;
	}
	ValueParameter<int> *allocate_int(int value)
	{
		ValueParameter<int> *ret = new ValueParameter<int>(value);
		ret->type = 0;
		return ret;
	}
	ValueParameter<std::string> *allocate_string(const std::string &value)
	{
		ValueParameter<std::string> *ret =
			new ValueParameter<std::string>(value);
		ret->type = 1;
		return ret;
	}
	ValueParameter<flecs::entity> *allocate_entity(flecs::entity value)
	{
		ValueParameter<flecs::entity> *ret =
			new ValueParameter<flecs::entity>(value);
		ret->type = 2;
		return ret;
	}
	ValueParameter<bool> *allocate_boolean(bool value)
	{
		ValueParameter<bool> *ret = new ValueParameter<bool>(value);
		ret->type = 3;
		return ret;
	}
};
struct GameWorldModule {
	GameWorldModule(flecs::world &ecs);
};
}
#endif