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

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

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

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

Type::Ptr TypeImpl<LivestatusListener>::GetBaseType() const
{
	return ConfigObject::TypeInstance;
}

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

	switch (static_cast<int>(Utility::SDBM(name, 1))) {
		case 98:
			if (name == "bind_host")
				return offset + 2;
			if (name == "bind_port")
				return offset + 3;

			break;
		case 99:
			if (name == "compat_log_path")
				return offset + 4;

			break;
		case 115:
			if (name == "socket_type")
				return offset + 0;
			if (name == "socket_path")
				return offset + 1;

			break;
	}

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

Field TypeImpl<LivestatusListener>::GetFieldInfo(int id) const
{
	int real_id = id - ConfigObject::TypeInstance->GetFieldCount();
	if (real_id < 0) { return ConfigObject::TypeInstance->GetFieldInfo(id); }
	switch (real_id) {
		case 0:
			return {0, "String", "socket_type", "socket_type", nullptr, 2, 0};
		case 1:
			return {1, "String", "socket_path", "socket_path", nullptr, 2, 0};
		case 2:
			return {2, "String", "bind_host", "bind_host", nullptr, 2, 0};
		case 3:
			return {3, "String", "bind_port", "bind_port", nullptr, 2, 0};
		case 4:
			return {4, "String", "compat_log_path", "compat_log_path", nullptr, 2, 0};
		default:
			throw std::runtime_error("Invalid field ID.");
	}
}

int TypeImpl<LivestatusListener>::GetFieldCount() const
{
	return 5 + ConfigObject::TypeInstance->GetFieldCount();
}

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

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

void TypeImpl<LivestatusListener>::RegisterAttributeHandler(int fieldId, const Type::AttributeHandler& callback)
{
	int real_id = fieldId - ConfigObject::TypeInstance->GetFieldCount(); 
	if (real_id < 0) { ConfigObject::TypeInstance->RegisterAttributeHandler(fieldId, callback); return; }
	switch (real_id) {
		case 0:
			ObjectImpl<LivestatusListener>::OnSocketTypeChanged.connect(callback);
			break;
		case 1:
			ObjectImpl<LivestatusListener>::OnSocketPathChanged.connect(callback);
			break;
		case 2:
			ObjectImpl<LivestatusListener>::OnBindHostChanged.connect(callback);
			break;
		case 3:
			ObjectImpl<LivestatusListener>::OnBindPortChanged.connect(callback);
			break;
		case 4:
			ObjectImpl<LivestatusListener>::OnCompatLogPathChanged.connect(callback);
			break;
		default:
			throw std::runtime_error("Invalid field ID.");
	}
}

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

	if (2 & types)
		ValidateSocketType(Lazy<String>([this]() { return GetSocketType(); }), utils);
	if (2 & types)
		ValidateSocketPath(Lazy<String>([this]() { return GetSocketPath(); }), utils);
	if (2 & types)
		ValidateBindHost(Lazy<String>([this]() { return GetBindHost(); }), utils);
	if (2 & types)
		ValidateBindPort(Lazy<String>([this]() { return GetBindPort(); }), utils);
	if (2 & types)
		ValidateCompatLogPath(Lazy<String>([this]() { return GetCompatLogPath(); }), utils);
}

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

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

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

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

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

ObjectImpl<LivestatusListener>::ObjectImpl()
{
	SetSocketType(GetDefaultSocketType(), true);
	SetSocketPath(GetDefaultSocketPath(), true);
	SetBindHost(GetDefaultBindHost(), true);
	SetBindPort(GetDefaultBindPort(), true);
	SetCompatLogPath(GetDefaultCompatLogPath(), true);
}

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

void ObjectImpl<LivestatusListener>::SetField(int id, const Value& value, bool suppress_events, const Value& cookie)
{
	int real_id = id - ConfigObject::TypeInstance->GetFieldCount(); 
	if (real_id < 0) { ConfigObject::SetField(id, value, suppress_events, cookie); return; }
	switch (real_id) {
		case 0:
			SetSocketType(value, suppress_events, cookie);
			break;
		case 1:
			SetSocketPath(value, suppress_events, cookie);
			break;
		case 2:
			SetBindHost(value, suppress_events, cookie);
			break;
		case 3:
			SetBindPort(value, suppress_events, cookie);
			break;
		case 4:
			SetCompatLogPath(value, suppress_events, cookie);
			break;
		default:
			throw std::runtime_error("Invalid field ID.");
	}
}

Value ObjectImpl<LivestatusListener>::GetField(int id) const
{
	int real_id = id - ConfigObject::TypeInstance->GetFieldCount(); 
	if (real_id < 0) { return ConfigObject::GetField(id); }
	switch (real_id) {
		case 0:
			return GetSocketType();
		case 1:
			return GetSocketPath();
		case 2:
			return GetBindHost();
		case 3:
			return GetBindPort();
		case 4:
			return GetCompatLogPath();
		default:
			throw std::runtime_error("Invalid field ID.");
	}
}

void ObjectImpl<LivestatusListener>::ValidateField(int id, const Lazy<Value>& lvalue, const ValidationUtils& utils)
{
	int real_id = id - ConfigObject::TypeInstance->GetFieldCount(); 
	if (real_id < 0) { ConfigObject::ValidateField(id, lvalue, utils); return; }
	switch (real_id) {
		case 0:
			ValidateSocketType(lvalue, utils);
			break;
		case 1:
			ValidateSocketPath(lvalue, utils);
			break;
		case 2:
			ValidateBindHost(lvalue, utils);
			break;
		case 3:
			ValidateBindPort(lvalue, utils);
			break;
		case 4:
			ValidateCompatLogPath(lvalue, utils);
			break;
		default:
			throw std::runtime_error("Invalid field ID.");
	}
}

void ObjectImpl<LivestatusListener>::NotifyField(int id, const Value& cookie)
{
	int real_id = id - ConfigObject::TypeInstance->GetFieldCount(); 
	if (real_id < 0) { ConfigObject::NotifyField(id, cookie); return; }
	switch (real_id) {
		case 0:
			NotifySocketType(cookie);
			break;
		case 1:
			NotifySocketPath(cookie);
			break;
		case 2:
			NotifyBindHost(cookie);
			break;
		case 3:
			NotifyBindPort(cookie);
			break;
		case 4:
			NotifyCompatLogPath(cookie);
			break;
		default:
			throw std::runtime_error("Invalid field ID.");
	}
}

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

String ObjectImpl<LivestatusListener>::GetSocketType() const
{
	return m_SocketType.load();
}

String ObjectImpl<LivestatusListener>::GetSocketPath() const
{
	return m_SocketPath.load();
}

String ObjectImpl<LivestatusListener>::GetBindHost() const
{
	return m_BindHost.load();
}

String ObjectImpl<LivestatusListener>::GetBindPort() const
{
	return m_BindPort.load();
}

String ObjectImpl<LivestatusListener>::GetCompatLogPath() const
{
	return m_CompatLogPath.load();
}

void ObjectImpl<LivestatusListener>::SetSocketType(const String& value, bool suppress_events, const Value& cookie)
{
	m_SocketType.store(value);
	if (!suppress_events) {
		NotifySocketType(cookie);
	}

}

void ObjectImpl<LivestatusListener>::SetSocketPath(const String& value, bool suppress_events, const Value& cookie)
{
	m_SocketPath.store(value);
	if (!suppress_events) {
		NotifySocketPath(cookie);
	}

}

void ObjectImpl<LivestatusListener>::SetBindHost(const String& value, bool suppress_events, const Value& cookie)
{
	m_BindHost.store(value);
	if (!suppress_events) {
		NotifyBindHost(cookie);
	}

}

void ObjectImpl<LivestatusListener>::SetBindPort(const String& value, bool suppress_events, const Value& cookie)
{
	m_BindPort.store(value);
	if (!suppress_events) {
		NotifyBindPort(cookie);
	}

}

void ObjectImpl<LivestatusListener>::SetCompatLogPath(const String& value, bool suppress_events, const Value& cookie)
{
	m_CompatLogPath.store(value);
	if (!suppress_events) {
		NotifyCompatLogPath(cookie);
	}

}

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

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

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

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

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

String ObjectImpl<LivestatusListener>::GetDefaultSocketType() const
{
	 return "unix"; 
}

String ObjectImpl<LivestatusListener>::GetDefaultSocketPath() const
{
	 return Configuration::InitRunDir + "/cmd/livestatus"; 
}

String ObjectImpl<LivestatusListener>::GetDefaultBindHost() const
{
	 return "127.0.0.1"; 
}

String ObjectImpl<LivestatusListener>::GetDefaultBindPort() const
{
	 return "6558"; 
}

String ObjectImpl<LivestatusListener>::GetDefaultCompatLogPath() const
{
	 return Configuration::LogDir + "/compat"; 
}


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


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


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


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


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

void ObjectImpl<LivestatusListener>::ValidateBindHost(const Lazy<String>& lvalue, const ValidationUtils& utils)
{
	SimpleValidateBindHost(lvalue, utils);
}

void ObjectImpl<LivestatusListener>::ValidateBindPort(const Lazy<String>& lvalue, const ValidationUtils& utils)
{
	SimpleValidateBindPort(lvalue, utils);
}

void ObjectImpl<LivestatusListener>::ValidateCompatLogPath(const Lazy<String>& lvalue, const ValidationUtils& utils)
{
	SimpleValidateCompatLogPath(lvalue, utils);
}

void ObjectImpl<LivestatusListener>::ValidateSocketPath(const Lazy<String>& lvalue, const ValidationUtils& utils)
{
	SimpleValidateSocketPath(lvalue, utils);
}

void ObjectImpl<LivestatusListener>::ValidateSocketType(const Lazy<String>& lvalue, const ValidationUtils& utils)
{
	SimpleValidateSocketType(lvalue, utils);
}

}
#pragma GCC diagnostic pop
