#ifndef __PDACUdev__
#define __PDACUdev__

#include <fstream>

#include <unistd.h>

#include "PDAC"

namespace PDAC
{

using namespace std;

const string DefaultUdevLocalRulesFilePrefix="/etc/udev/rules.d/99zz_PDAC_";
const string DefaultUdevNonlocalRulesFilePrefix="/var/run/udev/rules.d/99zz_PDAC_";

string openUdevRuleFile(ofstream& ofs, const DevConst* dev, const string& sessonID, const string& prefix);

template <class RulesMap>
void genUdevRule(const DevConst* dev, const RulesMap &rules, const string& sessonID, const string& prefix)
{
	dev->validate();

	ofstream ofs;
	string fileName=openUdevRuleFile(ofs,dev,sessonID,prefix);

	try{
		dev->writeUdevRuleHeader(ofs);

		const StringList& devRulesNames=dev->rules();
		if(!devRulesNames.empty())
			for(StringList::const_iterator rulesNamesCI=devRulesNames.begin(); rulesNamesCI!=devRulesNames.end(); ++rulesNamesCI)
			{
				typename RulesMap::const_iterator rulesCI=rules.find(*rulesNamesCI);
				if(rulesCI==rules.end()) throw Exception("Rule 4 device not found");

				(*rulesCI).second->writeExpressions(ofs);
			}

		dev->writeUdevRuleFooter(ofs);
	}catch(Exception &e)
	{
		unlink(fileName.c_str());
		throw;
	}

	ofs.close();
}

/**
 * @brief rmUdevRules Удаление правил Udev сооответсвующих сессии @param sessionID
 * @param sessionID идентификатор сессии
 * @param prefix префикс файлов правил Udev, рекомендуется использовать значение по-умолчанию
 * @return В случае ошибки выбрасывает исключения
 */
void rmUdevRules(const string &sessionID, const string &prefix=DefaultUdevLocalRulesFilePrefix);

/**
 * @brief genUdevRules Генерация правил Udev сооответсвующих сессии @param sessionID
 * @param devs список устройств, контейнер, предосталяющий итератор последовательного доступа к элементам типа const DevConst*
 * @param rules хеш таблица правил доступа, контейнер, предосталяющий ассицоативный доступ к элементам типа const RulesConst*
 * @param sessionID идентификатор сессии
 * @param prefix префикс файлов правил Udev, рекомендуется использовать значение по-умолчанию
 * @return В случае ошибки выбрасывает исключения
 */
template <class DevList, class RulesMap>
void genUdevRules(const DevList &devs, const RulesMap &rules, const string& sessonid, const string &prefix)
{
	rmUdevRules(sessonid);

	for(typename DevList::const_iterator devsCI=devs.begin(); devsCI!=devs.end(); ++devsCI)
	{
		const DevConst *dev=*devsCI;
		if(!dev->isEnabled()) continue;

		genUdevRule(dev,rules,sessonid,prefix);
	}
}

} /* namespace PDAC */

#endif /* __PDACUdev__ */
