#ifndef __PDACFILE__
#define __PDACFILE__

#include <algorithm>
#include <memory>
#include "PDAC"

namespace PDAC {

template <class T>
class Container
{
protected:

	static void deleteItem(T *item) { if(item) delete item; }

public:

	Container() {}
	~Container() { clear(); }

	const std::map<std::string, T *> &content() const { return _content; }

	void clear() {
		for(auto &i : _content)
			deleteItem(i.second);
		_content.clear();
	}

	virtual void load() = 0;
	virtual void create(const T &item) = 0;
	virtual void update(const std::string &name, const T &item) = 0;
	virtual void remove(const std::string &name) = 0;

protected:

	virtual void updateCreate(const std::string &name, const T& item, bool isUpdate) = 0;

	std::map<std::string, T *> _content;

};

//******************************************************************************
typedef std::map<std::string, Dev *> MapDevices;
typedef Container<Dev> DevicesContainer;

class DevicesFile : public DevicesContainer {
public:
	static DevicesFile *instance();
	~DevicesFile() {}

	void load();
	void create(const Dev &device);
	void update(const std::string &name, const Dev &device);
	void remove(const std::string &name);

	class const_iterator {
	public:
		// std::iterator<> is deprecated now
		using iterator_category = std::bidirectional_iterator_tag;
		using value_type = const DevConst *;
		using difference_type = ptrdiff_t;
		using pointer = const DevConst *;
		using reference = const DevConst *&;

	public:
		const DevConst *operator*() { return std::get<1>(*_cur); }
		bool operator!=(const const_iterator &i) const { return _cur != i._cur; }
		const const_iterator& operator++() { ++_cur; return (*this); }

	private:
		friend class DevicesFile;
		const_iterator(MapDevices::const_iterator cur) : _cur(cur) {} // private constructor for begin, end

	private:
		MapDevices::const_iterator _cur;
	};

	const_iterator begin() const { return const_iterator(content().begin()); }
	const_iterator end() const { return const_iterator(content().end()); }

protected:

	DevicesFile(): DevicesContainer() {}
	void updateCreate(const std::string &name, const Dev &dev, bool isUpdate);
};

//******************************************************************************
typedef std::map<std::string, Rule *> MapRules;
typedef Container<Rule> RulesContainer;

class RulesFile: public RulesContainer {
public:
	static RulesFile *instance();
	~RulesFile() {}

	void load();
	void create(const Rule &rule);
	void update(const std::string &name, const Rule &rule);
	void remove(const std::string &name);

protected:

	RulesFile(): RulesContainer() {}
	void updateCreate(const std::string &name, const Rule &rule, bool isUpdate);
};

//
// PDAC main configuration
//
class ConfigurationFile  {
public:
	static std::unique_ptr<ConfigurationFile> create(const char *file = DEFAULT_ADM_CONFIG_PATH);
	static std::unique_ptr<ConfigurationFile> create();

	void save(const char *file);

	Configuration &configuration() throw() { return _config; }
	void configuration(const Configuration &c) { _config = c; }

	bool state_resolved() const throw() { return _resolved; }
	void resolve_state();

	static const char *state_value(bool state) throw();
	static bool state_value(const char *str) throw();

protected:
	ConfigurationFile() {}
	ConfigurationFile(const char *file);

private:
	Configuration	_config;
	bool			_resolved = false;		// state not resolved by configuration file (may be absent)
};

} /* namespace PDAC */

#endif /* __PDACFILE__ */
