#include "base/exception.hpp"
#include "base/objectlock.hpp"
#include "base/utility.hpp"
#include "base/convert.hpp"
#include "base/debug.hpp"
#include "base/dependencygraph.hpp"
#include "base/logger.hpp"
#include "base/function.hpp"
#include "base/configobject.hpp"
#include "base/configtype.hpp"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-variable"
namespace icinga
{

TypeImpl<JournaldLogger>::TypeImpl()
{ }

TypeImpl<JournaldLogger>::~TypeImpl()
{ }

String TypeImpl<JournaldLogger>::GetName() const
{
	return "JournaldLogger";
}

int TypeImpl<JournaldLogger>::GetAttributes() const
{
	return 0;
}

Type::Ptr TypeImpl<JournaldLogger>::GetBaseType() const
{
	return Logger::TypeInstance;
}

int TypeImpl<JournaldLogger>::GetFieldId(const String& name) const
{
	int offset = Logger::TypeInstance->GetFieldCount();

	switch (static_cast<int>(Utility::SDBM(name, 1))) {
		case 102:
			if (name == "facility")
				return offset + 0;

			break;
		case 105:
			if (name == "identifier")
				return offset + 1;

			break;
	}

	return Logger::TypeInstance->GetFieldId(name);
}

Field TypeImpl<JournaldLogger>::GetFieldInfo(int id) const
{
	int real_id = id - Logger::TypeInstance->GetFieldCount();
	if (real_id < 0) { return Logger::TypeInstance->GetFieldInfo(id); }
	switch (real_id) {
		case 0:
			return {0, "String", "facility", "facility", nullptr, 2, 0};
		case 1:
			return {1, "String", "identifier", "identifier", nullptr, 2, 0};
		default:
			throw std::runtime_error("Invalid field ID.");
	}
}

int TypeImpl<JournaldLogger>::GetFieldCount() const
{
	return 2 + Logger::TypeInstance->GetFieldCount();
}

ObjectFactory TypeImpl<JournaldLogger>::GetFactory() const
{
	return TypeHelper<JournaldLogger, false>::GetFactory();
}

int TypeImpl<JournaldLogger>::GetActivationPriority() const
{
	return -100;
}

void TypeImpl<JournaldLogger>::RegisterAttributeHandler(int fieldId, const Type::AttributeHandler& callback)
{
	int real_id = fieldId - Logger::TypeInstance->GetFieldCount(); 
	if (real_id < 0) { Logger::TypeInstance->RegisterAttributeHandler(fieldId, callback); return; }
	switch (real_id) {
		case 0:
			ObjectImpl<JournaldLogger>::OnFacilityChanged.connect(callback);
			break;
		case 1:
			ObjectImpl<JournaldLogger>::OnIdentifierChanged.connect(callback);
			break;
		default:
			throw std::runtime_error("Invalid field ID.");
	}
}

void ObjectImpl<JournaldLogger>::Validate(int types, const ValidationUtils& utils)
{
	Logger::Validate(types, utils);

	if (2 & types)
		ValidateFacility(Lazy<String>([this]() { return GetFacility(); }), utils);
	if (2 & types)
		ValidateIdentifier(Lazy<String>([this]() { return GetIdentifier(); }), utils);
}

void ObjectImpl<JournaldLogger>::SimpleValidateFacility(const Lazy<String>& value, const ValidationUtils& utils)
{
}

void ObjectImpl<JournaldLogger>::SimpleValidateIdentifier(const Lazy<String>& value, const ValidationUtils& utils)
{
}

ObjectImpl<JournaldLogger>::ObjectImpl()
{
	SetFacility(GetDefaultFacility(), true);
	SetIdentifier(GetDefaultIdentifier(), true);
}

ObjectImpl<JournaldLogger>::~ObjectImpl()
{ }

void ObjectImpl<JournaldLogger>::SetField(int id, const Value& value, bool suppress_events, const Value& cookie)
{
	int real_id = id - Logger::TypeInstance->GetFieldCount(); 
	if (real_id < 0) { Logger::SetField(id, value, suppress_events, cookie); return; }
	switch (real_id) {
		case 0:
			SetFacility(value, suppress_events, cookie);
			break;
		case 1:
			SetIdentifier(value, suppress_events, cookie);
			break;
		default:
			throw std::runtime_error("Invalid field ID.");
	}
}

Value ObjectImpl<JournaldLogger>::GetField(int id) const
{
	int real_id = id - Logger::TypeInstance->GetFieldCount(); 
	if (real_id < 0) { return Logger::GetField(id); }
	switch (real_id) {
		case 0:
			return GetFacility();
		case 1:
			return GetIdentifier();
		default:
			throw std::runtime_error("Invalid field ID.");
	}
}

void ObjectImpl<JournaldLogger>::ValidateField(int id, const Lazy<Value>& lvalue, const ValidationUtils& utils)
{
	int real_id = id - Logger::TypeInstance->GetFieldCount(); 
	if (real_id < 0) { Logger::ValidateField(id, lvalue, utils); return; }
	switch (real_id) {
		case 0:
			ValidateFacility(lvalue, utils);
			break;
		case 1:
			ValidateIdentifier(lvalue, utils);
			break;
		default:
			throw std::runtime_error("Invalid field ID.");
	}
}

void ObjectImpl<JournaldLogger>::NotifyField(int id, const Value& cookie)
{
	int real_id = id - Logger::TypeInstance->GetFieldCount(); 
	if (real_id < 0) { Logger::NotifyField(id, cookie); return; }
	switch (real_id) {
		case 0:
			NotifyFacility(cookie);
			break;
		case 1:
			NotifyIdentifier(cookie);
			break;
		default:
			throw std::runtime_error("Invalid field ID.");
	}
}

Object::Ptr ObjectImpl<JournaldLogger>::NavigateField(int id) const
{
	int real_id = id - Logger::TypeInstance->GetFieldCount(); 
	if (real_id < 0) { return Logger::NavigateField(id); }
	throw std::runtime_error("Invalid field ID.");
}

String ObjectImpl<JournaldLogger>::GetFacility() const
{
	return m_Facility.load();
}

String ObjectImpl<JournaldLogger>::GetIdentifier() const
{
	return m_Identifier.load();
}

void ObjectImpl<JournaldLogger>::SetFacility(const String& value, bool suppress_events, const Value& cookie)
{
	m_Facility.store(value);
	if (!suppress_events) {
		NotifyFacility(cookie);
	}

}

void ObjectImpl<JournaldLogger>::SetIdentifier(const String& value, bool suppress_events, const Value& cookie)
{
	m_Identifier.store(value);
	if (!suppress_events) {
		NotifyIdentifier(cookie);
	}

}

void ObjectImpl<JournaldLogger>::NotifyFacility(const Value& cookie)
{
	auto *dobj = dynamic_cast<ConfigObject *>(this);
	if (!dobj || dobj->IsActive())
		OnFacilityChanged(static_cast<JournaldLogger *>(this), cookie);
}

void ObjectImpl<JournaldLogger>::NotifyIdentifier(const Value& cookie)
{
	auto *dobj = dynamic_cast<ConfigObject *>(this);
	if (!dobj || dobj->IsActive())
		OnIdentifierChanged(static_cast<JournaldLogger *>(this), cookie);
}

String ObjectImpl<JournaldLogger>::GetDefaultFacility() const
{
	 return "LOG_USER"; 
}

String ObjectImpl<JournaldLogger>::GetDefaultIdentifier() const
{
	return String();
}


boost::signals2::signal<void (const intrusive_ptr<JournaldLogger>&, const Value&)> ObjectImpl<JournaldLogger>::OnFacilityChanged;


boost::signals2::signal<void (const intrusive_ptr<JournaldLogger>&, const Value&)> ObjectImpl<JournaldLogger>::OnIdentifierChanged;

void ObjectImpl<JournaldLogger>::ValidateFacility(const Lazy<String>& lvalue, const ValidationUtils& utils)
{
	SimpleValidateFacility(lvalue, utils);
}

void ObjectImpl<JournaldLogger>::ValidateIdentifier(const Lazy<String>& lvalue, const ValidationUtils& utils)
{
	SimpleValidateIdentifier(lvalue, utils);
}

}
#pragma GCC diagnostic pop
