#ifndef __PDAC__
#define __PDAC__

#include <exception>
#include <string>
#include <list>
#include <map>
#include <memory>

#include <parsec/pdp_common.h>
#include <parsec/parsec_aud.h>
#include <parsec/pdp.h>

namespace PDAC
{

#ifndef DEFAULT_CONFIG_RULES_PATH
#define DEFAULT_CONFIG_RULES_PATH "/etc/parsec/PDAC/rules.cfg"
#endif

#ifndef DEFAULT_CONFIG_DEVICES_PATH
#define DEFAULT_CONFIG_DEVICES_PATH "/etc/parsec/PDAC/devices.cfg"
#endif

#ifndef DEFAULT_ADM_CONFIG_PATH
#define DEFAULT_ADM_CONFIG_PATH "/etc/parsec/pdac-adm.conf"
#endif // DEFAULT_ADM_CONFIG_PATH

struct pdpl_dtor {
	void operator()(PDPL_T *p) { pdpl_put(p); }
};
using pdpl_ptr_t = std::unique_ptr<PDPL_T, pdpl_dtor>;

class Rule;
typedef std::list<std::string> StringList;
typedef std::map<std::string, Rule *> MapRules;

//******************************************************************************

class Exception : public std::exception {
public:

	Exception() throw();
	Exception(const std::string &message) throw();
	Exception( const Exception &ex) throw();
	virtual ~Exception() throw();

	const char *what() const throw();

protected:
	std::string _message;
};

//******************************************************************************
class ItemConst
{
public:
//	virtual ~ItemConst(); /* 4 proper cleanup */

	virtual bool isEnabled() const = 0;
	virtual const std::string &name() const = 0;
	virtual const std::string &description() const = 0;
	virtual const StringList &expressions() const = 0;

	void writeExpressions(std::ostream &out) const;
};

class Item : public virtual ItemConst
{
public:
	Item();
	virtual ~Item() {};

	bool isEnabled() const;
	void setEnabled(bool isEnabled);

	const std::string &name() const;
	void setName(const std::string &name);

	const std::string &description() const;
	void setDescription(const std::string &description);

	StringList &expressions();
	const StringList &expressions() const;

protected:

	bool 		_isEnabled = false;

	std::string _name;
	std::string _description;

	StringList 	_expressions;

};
//******************************************************************************
typedef ItemConst RuleConst;

class Rule : public Item
{
	friend class RulesFile;
};
//******************************************************************************
class DevConst: public virtual ItemConst
{
public:
//	virtual ~DevConst(); /* 4 proper cleanup */

	virtual const std::string &user() const = 0;
	virtual const std::string &group() const = 0;
	virtual int mode() const = 0;

///??? PDPL eatreference

	virtual const PDPL_T* label() const = 0;
	virtual std::string labelToString() const = 0;

	virtual PDP_LEV_T getLev() const = 0;
	virtual PDP_ILEV_T getILev() const = 0;
	virtual PDP_CAT_T  getCat() const = 0;
	virtual PDP_TYPE_T getType() const = 0;

	virtual uint32_t succAudit() const = 0;
	virtual uint32_t failAudit() const = 0;

	virtual const StringList &rules() const = 0;

	void validate() const;
	void writeUdevRule(std::list<const ItemConst *> &rules, std::ostream &out) const;
};

class Dev : public Item, public DevConst
{
	friend class DevicesFile;

public:

	Dev();
	Dev( const Dev & /*devicePDAC*/ );
	virtual ~Dev();

	const Dev &operator=( const Dev & /*devicePDAC*/ );

	const std::string &user() const;
	void setUser(const std::string &user);

	const std::string &group() const;
	void setGroup(const std::string &group);

	int mode() const;
	void setMode( int mode );

	const PDPL_T* label() const;
	std::string labelToString() const;

	PDP_LEV_T getLev() const;
	PDP_ILEV_T getILev() const;
	PDP_CAT_T  getCat() const;
	PDP_TYPE_T getType() const;

	void setLev( PDP_LEV_T /*lev*/ );
	void setILev( PDP_ILEV_T /*iLev*/ );
	void setCat( PDP_CAT_T /*cat*/ );
	void setType( PDP_TYPE_T /*type*/ );

	uint32_t succAudit() const;
	uint32_t failAudit() const;

	void setSuccAudit( uint32_t /*succ*/ );
	void setFailAudit( uint32_t /*fail*/ );

	StringList &rules();
	const StringList &rules() const;

protected:

	std::string 	_owner;
	std::string		_group;

	int 			_mode;
	pdpl_ptr_t		_pdpLabel;
	parsec_audit_t 	_audit;

	StringList 		_rules;

};

// DAC main configuration
struct Configuration {
	Configuration() {}
	Configuration(const Configuration &c) : _state(c._state) {}

	bool state() const throw() { return _state; }
	void state(bool value) throw() { _state = value; }

private:
	bool	_state = false;
};

} /* namespace PDAC */

#endif /* __PDAC__ */
