#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<Function>::TypeImpl()
{ }

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

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

int TypeImpl<Function>::GetAttributes() const
{
	return 1;
}

Type::Ptr TypeImpl<Function>::GetBaseType() const
{
	return Object::TypeInstance;
}

int TypeImpl<Function>::GetFieldId(const String& name) const
{
	int offset = 0;

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

			break;
		case 100:
			if (name == "deprecated")
				return offset + 3;

			break;
		case 110:
			if (name == "name")
				return offset + 0;

			break;
		case 115:
			if (name == "side_effect_free")
				return offset + 2;

			break;
	}

	return -1;
}

Field TypeImpl<Function>::GetFieldInfo(int id) const
{
	switch (id) {
		case 0:
			return {0, "String", "name", "name", nullptr, 2, 0};
		case 1:
			return {1, "Array", "arguments", "arguments", nullptr, 2, 0};
		case 2:
			return {2, "Boolean", "side_effect_free", "side_effect_free", nullptr, 2, 0};
		case 3:
			return {3, "Boolean", "deprecated", "deprecated", nullptr, 2, 0};
		default:
			throw std::runtime_error("Invalid field ID.");
	}
}

int TypeImpl<Function>::GetFieldCount() const
{
	return 4;
}

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

int TypeImpl<Function>::GetActivationPriority() const
{
	return 0;
}

void TypeImpl<Function>::RegisterAttributeHandler(int fieldId, const Type::AttributeHandler& callback)
{
	switch (fieldId) {
		case 0:
			ObjectImpl<Function>::OnNameChanged.connect(callback);
			break;
		case 1:
			ObjectImpl<Function>::OnArgumentsChanged.connect(callback);
			break;
		case 2:
			ObjectImpl<Function>::OnSideEffectFreeChanged.connect(callback);
			break;
		case 3:
			ObjectImpl<Function>::OnDeprecatedChanged.connect(callback);
			break;
		default:
			throw std::runtime_error("Invalid field ID.");
	}
}

void ObjectImpl<Function>::Validate(int types, const ValidationUtils& utils)
{
	if (2 & types)
		ValidateName(Lazy<String>([this]() { return GetName(); }), utils);
	if (2 & types)
		ValidateArguments(Lazy<Array::Ptr>([this]() { return GetArguments(); }), utils);
	if (2 & types)
		ValidateSideEffectFree(Lazy<bool>([this]() { return GetSideEffectFree(); }), utils);
	if (2 & types)
		ValidateDeprecated(Lazy<bool>([this]() { return GetDeprecated(); }), utils);
}

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

void ObjectImpl<Function>::SimpleValidateArguments(const Lazy<Array::Ptr>& value, const ValidationUtils& utils)
{
}

void ObjectImpl<Function>::SimpleValidateSideEffectFree(const Lazy<bool>& value, const ValidationUtils& utils)
{
}

void ObjectImpl<Function>::SimpleValidateDeprecated(const Lazy<bool>& value, const ValidationUtils& utils)
{
}

ObjectImpl<Function>::ObjectImpl()
{
	SetName(GetDefaultName(), true);
	SetArguments(GetDefaultArguments(), true);
	SetSideEffectFree(GetDefaultSideEffectFree(), true);
	SetDeprecated(GetDefaultDeprecated(), true);
}

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

void ObjectImpl<Function>::SetField(int id, const Value& value, bool suppress_events, const Value& cookie)
{
	switch (id) {
		case 0:
			SetName(value, suppress_events, cookie);
			break;
		case 1:
			SetArguments(value, suppress_events, cookie);
			break;
		case 2:
			SetSideEffectFree(value, suppress_events, cookie);
			break;
		case 3:
			SetDeprecated(value, suppress_events, cookie);
			break;
		default:
			throw std::runtime_error("Invalid field ID.");
	}
}

Value ObjectImpl<Function>::GetField(int id) const
{
	switch (id) {
		case 0:
			return GetName();
		case 1:
			return GetArguments();
		case 2:
			return GetSideEffectFree();
		case 3:
			return GetDeprecated();
		default:
			throw std::runtime_error("Invalid field ID.");
	}
}

void ObjectImpl<Function>::ValidateField(int id, const Lazy<Value>& lvalue, const ValidationUtils& utils)
{
	switch (id) {
		case 0:
			ValidateName(lvalue, utils);
			break;
		case 1:
			ValidateArguments(lvalue, utils);
			break;
		case 2:
			ValidateSideEffectFree(lvalue, utils);
			break;
		case 3:
			ValidateDeprecated(lvalue, utils);
			break;
		default:
			throw std::runtime_error("Invalid field ID.");
	}
}

void ObjectImpl<Function>::NotifyField(int id, const Value& cookie)
{
	switch (id) {
		case 0:
			NotifyName(cookie);
			break;
		case 1:
			NotifyArguments(cookie);
			break;
		case 2:
			NotifySideEffectFree(cookie);
			break;
		case 3:
			NotifyDeprecated(cookie);
			break;
		default:
			throw std::runtime_error("Invalid field ID.");
	}
}

Object::Ptr ObjectImpl<Function>::NavigateField(int id) const
{
	throw std::runtime_error("Invalid field ID.");
}

String ObjectImpl<Function>::GetName() const
{
	return m_Name.load();
}

Array::Ptr ObjectImpl<Function>::GetArguments() const
{
	return m_Arguments.load();
}

bool ObjectImpl<Function>::GetSideEffectFree() const
{
	return m_SideEffectFree.load();
}

bool ObjectImpl<Function>::GetDeprecated() const
{
	return m_Deprecated.load();
}

void ObjectImpl<Function>::SetName(const String& value, bool suppress_events, const Value& cookie)
{
	m_Name.store(value);
	if (!suppress_events) {
		NotifyName(cookie);
	}

}

void ObjectImpl<Function>::SetArguments(const Array::Ptr& value, bool suppress_events, const Value& cookie)
{
	m_Arguments.store(value);
	if (!suppress_events) {
		NotifyArguments(cookie);
	}

}

void ObjectImpl<Function>::SetSideEffectFree(bool value, bool suppress_events, const Value& cookie)
{
	m_SideEffectFree.store(value);
	if (!suppress_events) {
		NotifySideEffectFree(cookie);
	}

}

void ObjectImpl<Function>::SetDeprecated(bool value, bool suppress_events, const Value& cookie)
{
	m_Deprecated.store(value);
	if (!suppress_events) {
		NotifyDeprecated(cookie);
	}

}

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

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

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

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

String ObjectImpl<Function>::GetDefaultName() const
{
	return String();
}

Array::Ptr ObjectImpl<Function>::GetDefaultArguments() const
{
	return Array::Ptr();
}

bool ObjectImpl<Function>::GetDefaultSideEffectFree() const
{
	return bool();
}

bool ObjectImpl<Function>::GetDefaultDeprecated() const
{
	return bool();
}


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


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


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


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

void ObjectImpl<Function>::ValidateArguments(const Lazy<Array::Ptr>& lvalue, const ValidationUtils& utils)
{
	SimpleValidateArguments(lvalue, utils);
}

void ObjectImpl<Function>::ValidateDeprecated(const Lazy<bool>& lvalue, const ValidationUtils& utils)
{
	SimpleValidateDeprecated(lvalue, utils);
}

void ObjectImpl<Function>::ValidateName(const Lazy<String>& lvalue, const ValidationUtils& utils)
{
	SimpleValidateName(lvalue, utils);
}

void ObjectImpl<Function>::ValidateSideEffectFree(const Lazy<bool>& lvalue, const ValidationUtils& utils)
{
	SimpleValidateSideEffectFree(lvalue, utils);
}

}
#pragma GCC diagnostic pop
