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

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

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

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

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

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

	switch (static_cast<int>(Utility::SDBM(name, 1))) {
		case 99:
			if (name == "crit")
				return offset + 0;
			if (name == "counter")
				return offset + 7;

			break;
		case 108:
			if (name == "label")
				return offset + 4;

			break;
		case 109:
			if (name == "min")
				return offset + 2;
			if (name == "max")
				return offset + 3;

			break;
		case 117:
			if (name == "unit")
				return offset + 5;

			break;
		case 118:
			if (name == "value")
				return offset + 6;

			break;
		case 119:
			if (name == "warn")
				return offset + 1;

			break;
	}

	return -1;
}

Field TypeImpl<PerfdataValue>::GetFieldInfo(int id) const
{
	switch (id) {
		case 0:
			return {0, "Value", "crit", "crit", nullptr, 4, 0};
		case 1:
			return {1, "Value", "warn", "warn", nullptr, 4, 0};
		case 2:
			return {2, "Value", "min", "min", nullptr, 4, 0};
		case 3:
			return {3, "Value", "max", "max", nullptr, 4, 0};
		case 4:
			return {4, "String", "label", "label", nullptr, 4, 0};
		case 5:
			return {5, "String", "unit", "unit", nullptr, 4, 0};
		case 6:
			return {6, "Number", "value", "value", nullptr, 4, 0};
		case 7:
			return {7, "Boolean", "counter", "counter", nullptr, 4, 0};
		default:
			throw std::runtime_error("Invalid field ID.");
	}
}

int TypeImpl<PerfdataValue>::GetFieldCount() const
{
	return 8;
}

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

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

void TypeImpl<PerfdataValue>::RegisterAttributeHandler(int fieldId, const Type::AttributeHandler& callback)
{
	switch (fieldId) {
		case 0:
			ObjectImpl<PerfdataValue>::OnCritChanged.connect(callback);
			break;
		case 1:
			ObjectImpl<PerfdataValue>::OnWarnChanged.connect(callback);
			break;
		case 2:
			ObjectImpl<PerfdataValue>::OnMinChanged.connect(callback);
			break;
		case 3:
			ObjectImpl<PerfdataValue>::OnMaxChanged.connect(callback);
			break;
		case 4:
			ObjectImpl<PerfdataValue>::OnLabelChanged.connect(callback);
			break;
		case 5:
			ObjectImpl<PerfdataValue>::OnUnitChanged.connect(callback);
			break;
		case 6:
			ObjectImpl<PerfdataValue>::OnValueChanged.connect(callback);
			break;
		case 7:
			ObjectImpl<PerfdataValue>::OnCounterChanged.connect(callback);
			break;
		default:
			throw std::runtime_error("Invalid field ID.");
	}
}

void ObjectImpl<PerfdataValue>::Validate(int types, const ValidationUtils& utils)
{
	if (4 & types)
		ValidateCrit(Lazy<Value>([this]() { return GetCrit(); }), utils);
	if (4 & types)
		ValidateWarn(Lazy<Value>([this]() { return GetWarn(); }), utils);
	if (4 & types)
		ValidateMin(Lazy<Value>([this]() { return GetMin(); }), utils);
	if (4 & types)
		ValidateMax(Lazy<Value>([this]() { return GetMax(); }), utils);
	if (4 & types)
		ValidateLabel(Lazy<String>([this]() { return GetLabel(); }), utils);
	if (4 & types)
		ValidateUnit(Lazy<String>([this]() { return GetUnit(); }), utils);
	if (4 & types)
		ValidateValue(Lazy<double>([this]() { return GetValue(); }), utils);
	if (4 & types)
		ValidateCounter(Lazy<bool>([this]() { return GetCounter(); }), utils);
}

void ObjectImpl<PerfdataValue>::SimpleValidateCrit(const Lazy<Value>& value, const ValidationUtils& utils)
{
	if (value().IsObjectType<Function>()) {
		Function::Ptr func = value();
		if (func->IsDeprecated())
			Log(LogWarning, "PerfdataValue") << "Attribute 'crit' for object '" << dynamic_cast<ConfigObject *>(this)->GetName() << "' of type '" << dynamic_cast<ConfigObject *>(this)->GetReflectionType()->GetName() << "' is set to a deprecated function: " << func->GetName();
	}

}

void ObjectImpl<PerfdataValue>::SimpleValidateWarn(const Lazy<Value>& value, const ValidationUtils& utils)
{
	if (value().IsObjectType<Function>()) {
		Function::Ptr func = value();
		if (func->IsDeprecated())
			Log(LogWarning, "PerfdataValue") << "Attribute 'warn' for object '" << dynamic_cast<ConfigObject *>(this)->GetName() << "' of type '" << dynamic_cast<ConfigObject *>(this)->GetReflectionType()->GetName() << "' is set to a deprecated function: " << func->GetName();
	}

}

void ObjectImpl<PerfdataValue>::SimpleValidateMin(const Lazy<Value>& value, const ValidationUtils& utils)
{
	if (value().IsObjectType<Function>()) {
		Function::Ptr func = value();
		if (func->IsDeprecated())
			Log(LogWarning, "PerfdataValue") << "Attribute 'min' for object '" << dynamic_cast<ConfigObject *>(this)->GetName() << "' of type '" << dynamic_cast<ConfigObject *>(this)->GetReflectionType()->GetName() << "' is set to a deprecated function: " << func->GetName();
	}

}

void ObjectImpl<PerfdataValue>::SimpleValidateMax(const Lazy<Value>& value, const ValidationUtils& utils)
{
	if (value().IsObjectType<Function>()) {
		Function::Ptr func = value();
		if (func->IsDeprecated())
			Log(LogWarning, "PerfdataValue") << "Attribute 'max' for object '" << dynamic_cast<ConfigObject *>(this)->GetName() << "' of type '" << dynamic_cast<ConfigObject *>(this)->GetReflectionType()->GetName() << "' is set to a deprecated function: " << func->GetName();
	}

}

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

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

void ObjectImpl<PerfdataValue>::SimpleValidateValue(const Lazy<double>& value, const ValidationUtils& utils)
{
}

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

ObjectImpl<PerfdataValue>::ObjectImpl()
{
	SetCrit(GetDefaultCrit(), true);
	SetWarn(GetDefaultWarn(), true);
	SetMin(GetDefaultMin(), true);
	SetMax(GetDefaultMax(), true);
	SetLabel(GetDefaultLabel(), true);
	SetUnit(GetDefaultUnit(), true);
	SetValue(GetDefaultValue(), true);
	SetCounter(GetDefaultCounter(), true);
}

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

void ObjectImpl<PerfdataValue>::SetField(int id, const Value& value, bool suppress_events, const Value& cookie)
{
	switch (id) {
		case 0:
			SetCrit(value, suppress_events, cookie);
			break;
		case 1:
			SetWarn(value, suppress_events, cookie);
			break;
		case 2:
			SetMin(value, suppress_events, cookie);
			break;
		case 3:
			SetMax(value, suppress_events, cookie);
			break;
		case 4:
			SetLabel(value, suppress_events, cookie);
			break;
		case 5:
			SetUnit(value, suppress_events, cookie);
			break;
		case 6:
			SetValue(value, suppress_events, cookie);
			break;
		case 7:
			SetCounter(value, suppress_events, cookie);
			break;
		default:
			throw std::runtime_error("Invalid field ID.");
	}
}

Value ObjectImpl<PerfdataValue>::GetField(int id) const
{
	switch (id) {
		case 0:
			return GetCrit();
		case 1:
			return GetWarn();
		case 2:
			return GetMin();
		case 3:
			return GetMax();
		case 4:
			return GetLabel();
		case 5:
			return GetUnit();
		case 6:
			return GetValue();
		case 7:
			return GetCounter();
		default:
			throw std::runtime_error("Invalid field ID.");
	}
}

void ObjectImpl<PerfdataValue>::ValidateField(int id, const Lazy<Value>& lvalue, const ValidationUtils& utils)
{
	switch (id) {
		case 0:
			ValidateCrit(lvalue, utils);
			break;
		case 1:
			ValidateWarn(lvalue, utils);
			break;
		case 2:
			ValidateMin(lvalue, utils);
			break;
		case 3:
			ValidateMax(lvalue, utils);
			break;
		case 4:
			ValidateLabel(lvalue, utils);
			break;
		case 5:
			ValidateUnit(lvalue, utils);
			break;
		case 6:
			ValidateValue(lvalue, utils);
			break;
		case 7:
			ValidateCounter(lvalue, utils);
			break;
		default:
			throw std::runtime_error("Invalid field ID.");
	}
}

void ObjectImpl<PerfdataValue>::NotifyField(int id, const Value& cookie)
{
	switch (id) {
		case 0:
			NotifyCrit(cookie);
			break;
		case 1:
			NotifyWarn(cookie);
			break;
		case 2:
			NotifyMin(cookie);
			break;
		case 3:
			NotifyMax(cookie);
			break;
		case 4:
			NotifyLabel(cookie);
			break;
		case 5:
			NotifyUnit(cookie);
			break;
		case 6:
			NotifyValue(cookie);
			break;
		case 7:
			NotifyCounter(cookie);
			break;
		default:
			throw std::runtime_error("Invalid field ID.");
	}
}

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

Value ObjectImpl<PerfdataValue>::GetCrit() const
{
	return m_Crit.load();
}

Value ObjectImpl<PerfdataValue>::GetWarn() const
{
	return m_Warn.load();
}

Value ObjectImpl<PerfdataValue>::GetMin() const
{
	return m_Min.load();
}

Value ObjectImpl<PerfdataValue>::GetMax() const
{
	return m_Max.load();
}

String ObjectImpl<PerfdataValue>::GetLabel() const
{
	return m_Label.load();
}

String ObjectImpl<PerfdataValue>::GetUnit() const
{
	return m_Unit.load();
}

double ObjectImpl<PerfdataValue>::GetValue() const
{
	return m_Value.load();
}

bool ObjectImpl<PerfdataValue>::GetCounter() const
{
	return m_Counter.load();
}

void ObjectImpl<PerfdataValue>::SetCrit(const Value& value, bool suppress_events, const Value& cookie)
{
	m_Crit.store(value);
	if (!suppress_events) {
		NotifyCrit(cookie);
	}

}

void ObjectImpl<PerfdataValue>::SetWarn(const Value& value, bool suppress_events, const Value& cookie)
{
	m_Warn.store(value);
	if (!suppress_events) {
		NotifyWarn(cookie);
	}

}

void ObjectImpl<PerfdataValue>::SetMin(const Value& value, bool suppress_events, const Value& cookie)
{
	m_Min.store(value);
	if (!suppress_events) {
		NotifyMin(cookie);
	}

}

void ObjectImpl<PerfdataValue>::SetMax(const Value& value, bool suppress_events, const Value& cookie)
{
	m_Max.store(value);
	if (!suppress_events) {
		NotifyMax(cookie);
	}

}

void ObjectImpl<PerfdataValue>::SetLabel(const String& value, bool suppress_events, const Value& cookie)
{
	m_Label.store(value);
	if (!suppress_events) {
		NotifyLabel(cookie);
	}

}

void ObjectImpl<PerfdataValue>::SetUnit(const String& value, bool suppress_events, const Value& cookie)
{
	m_Unit.store(value);
	if (!suppress_events) {
		NotifyUnit(cookie);
	}

}

void ObjectImpl<PerfdataValue>::SetValue(double value, bool suppress_events, const Value& cookie)
{
	m_Value.store(value);
	if (!suppress_events) {
		NotifyValue(cookie);
	}

}

void ObjectImpl<PerfdataValue>::SetCounter(bool value, bool suppress_events, const Value& cookie)
{
	m_Counter.store(value);
	if (!suppress_events) {
		NotifyCounter(cookie);
	}

}

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

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

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

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

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

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

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

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

Value ObjectImpl<PerfdataValue>::GetDefaultCrit() const
{
	return Value();
}

Value ObjectImpl<PerfdataValue>::GetDefaultWarn() const
{
	return Value();
}

Value ObjectImpl<PerfdataValue>::GetDefaultMin() const
{
	return Value();
}

Value ObjectImpl<PerfdataValue>::GetDefaultMax() const
{
	return Value();
}

String ObjectImpl<PerfdataValue>::GetDefaultLabel() const
{
	return String();
}

String ObjectImpl<PerfdataValue>::GetDefaultUnit() const
{
	return String();
}

double ObjectImpl<PerfdataValue>::GetDefaultValue() const
{
	return double();
}

bool ObjectImpl<PerfdataValue>::GetDefaultCounter() const
{
	return bool();
}


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


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


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


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


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


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


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


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

void ObjectImpl<PerfdataValue>::ValidateCounter(const Lazy<bool>& lvalue, const ValidationUtils& utils)
{
	SimpleValidateCounter(lvalue, utils);
}

void ObjectImpl<PerfdataValue>::ValidateCrit(const Lazy<Value>& lvalue, const ValidationUtils& utils)
{
	SimpleValidateCrit(lvalue, utils);
}

void ObjectImpl<PerfdataValue>::ValidateLabel(const Lazy<String>& lvalue, const ValidationUtils& utils)
{
	SimpleValidateLabel(lvalue, utils);
}

void ObjectImpl<PerfdataValue>::ValidateMax(const Lazy<Value>& lvalue, const ValidationUtils& utils)
{
	SimpleValidateMax(lvalue, utils);
}

void ObjectImpl<PerfdataValue>::ValidateMin(const Lazy<Value>& lvalue, const ValidationUtils& utils)
{
	SimpleValidateMin(lvalue, utils);
}

void ObjectImpl<PerfdataValue>::ValidateUnit(const Lazy<String>& lvalue, const ValidationUtils& utils)
{
	SimpleValidateUnit(lvalue, utils);
}

void ObjectImpl<PerfdataValue>::ValidateValue(const Lazy<double>& lvalue, const ValidationUtils& utils)
{
	SimpleValidateValue(lvalue, utils);
}

void ObjectImpl<PerfdataValue>::ValidateWarn(const Lazy<Value>& lvalue, const ValidationUtils& utils)
{
	SimpleValidateWarn(lvalue, utils);
}

}
#pragma GCC diagnostic pop
