#pragma once
#include <unistd.h>

#ifdef	__cplusplus

#include <sstream>
#include <list>

#include "PDAC"

namespace PDAC {

namespace details {

void writeUdevRuleFile(const std::string &source, const std::string &session, const std::string &dev_name, const std::string &text);

template <class RulesMap>
inline void generateUdevRule(const DevConst *dev, const RulesMap &rules, const std::string &source, const std::string &session) {

	dev->validate();

	std::list<const ItemConst *> dev_rules;
	for(const auto &rule_name : dev->rules()) {
		auto r = rules.find(rule_name);
		if(r == end(rules))
			throw Exception("Rule " + rule_name + " for device " + dev->name() + " not found");
		dev_rules.push_back(std::get<1>(*r));
	}

	std::ostringstream out;
	dev->writeUdevRule(dev_rules, out);

	writeUdevRuleFile(source, session, dev->name(), out.str());
}

const std::string &source_type_local();

} // namespace details

/**
 * @brief removeUdevRules Удаление правил Udev, заданных
 *  типом источника @param source и идентификатором сессии @param session
 * @param source тип источника: "local", "sss", "ald"...
 * @param session идентификатор сессии, имеющий смысл для конкретного источника
 * @return В случае ошибки выбрасывает исключения
 */
void removeUdevRules(const std::string &source, const std::string &session);

/**
 * @brief removeLocalUdevRules Удаление правил Udev для источника "local"
 * @return В случае ошибки выбрасывает исключения
 */
void removeLocalUdevRules();

/**
 * @brief generateUdevRules Генерация правил Udev, заданных
 *  типом источника @param source и идентификатором сессии @param session
 * @param source тип источника: "local", "sss", "ald"...
 * @param session идентификатор сессии, имеющий смысл для конкретного источника
 * @return В случае ошибки выбрасывает исключения
 */
template <class DevList, class RulesMap>
inline void generateUdevRules(const DevList &devs, const RulesMap &rules, const std::string &source, const std::string &session) {

	removeUdevRules(source, session);

	for(const auto &dev : devs) {
		if(!dev->isEnabled())
			continue;
		details::generateUdevRule(dev, rules, source, session);
	}
}

/**
 * @brief generateUdevRules Генерация правил Udev для источника "local"
 * @return В случае ошибки выбрасывает исключения
 */
template <class DevList, class RulesMap>
inline void generateLocalUdevRules(const DevList &devs, const RulesMap &rules) {
	generateUdevRules(devs, rules, details::source_type_local(), std::string());
}

/**
 * @brief checkAnyRuleExistance Проверка наличия как минимум одного правила Udev,
 *  для указанного источника @param source и сессии @param session
 * @param source тип источника: "local", "sss", "ald"...
 * @param session идентификатор сессии, имеющий смысл для конкретного источника
 * @return Возвращает true, если найден хотя бы один файл. В случае ошибки выбрасывает исключения.
 */
bool checkAnyRuleExistance(const std::string &source, const std::string &session);

/**
 * @brief checkAnyLocalRuleExistance Проверка наличия как минимум одного правила Udev для источника "local"
 * @return Возвращает true, если найден хотя бы один файл. В случае ошибки выбрасывает исключения.
 */
bool checkAnyLocalRuleExistance();

} // namespace PDAC

#endif // __cplusplus

#ifdef	__cplusplus
extern "C" {
#endif

#define PDAC_RULE_PARAMETER_DEVICE_NAME			"DEVNAME"
#define PDAC_RULE_PARAMETER_DEVICE_EXPRESSION	"DEVEXPR"
#define PDAC_RULE_PARAMETER_OWNER				"OWNER"
#define PDAC_RULE_PARAMETER_GROUP				"GROUP"
#define PDAC_RULE_PARAMETER_MODE				"MODE"			// представление, совместимое с stroul(,,0)
#define PDAC_RULE_PARAMETER_MAC_LEVEL			"MACLEVEL"		// представление, совместимое с stroul(,,0)
#define PDAC_RULE_PARAMETER_MAC_CATEGORIES		"MACCAT"		// представление, совместимое с stroul(,,0)
#define PDAC_RULE_PARAMETER_AUDIT_SUCCESS		"AUDITSUCC"		// представление, совместимое с stroul(,,0)
#define PDAC_RULE_PARAMETER_AUDIT_FAILURES		"AUDITFAIL"		// представление, совместимое с stroul(,,0)
#define PDAC_RULE_PARAMETER_RULE_EXPRESSION		"RULEXPR"

struct PDAC_RULE_PARAMETER {
	const char 	*name;			// Имя параметра из PDAC_RULE_PARAMETER_*
	const char 	*value;
};

/**
 * @brief generateUdevRule Генерация правила udev для клиентов, использующих только C.
 * @param source тип источника: "local", "sss", "ald"...
 * @param session идентификатор сессии, имеющий смысл для конкретного источника
 * @param param_count количество параметров правила в @param params
 * @param params параметры праила для формирования правила правила
 * @return Возвращает 0 в случае успеха, и не 0 в случае ошибки.
 */
extern int generateUdevRule(const char *source, const char *session, size_t param_count, const struct PDAC_RULE_PARAMETER *params);

/**
 * @brief removeUdevRules Удаление правил udev для клиентов, использующих только C.
 * @param source тип источника: "local", "sss", "ald"...
 * @param session идентификатор сессии, имеющий смысл для конкретного источника
 */
extern int removeUdevRules(const char *source, const char *session);

#ifdef	__cplusplus
}
#endif
