#ifndef CONFIGOBJECT_TI
#define CONFIGOBJECT_TI

#include "base/object.hpp"
#include "base/type.hpp"
#include "base/value.hpp"
#include "base/array.hpp"
#include "base/atomic.hpp"
#include "base/dictionary.hpp"
#include <boost/signals2.hpp>

#include "base/debuginfo.hpp"

#include "base/configtype.hpp"

namespace icinga
{


enum HAMode
{
	HARunOnce,
	HARunEverywhere
};

class NameComposer
{
public:
	virtual ~NameComposer();

	virtual String MakeName(const String& shortName, const Object::Ptr& context) const = 0;
	virtual Dictionary::Ptr ParseName(const String& name) const = 0;
};

class ConfigObjectBase;

template<>
struct TypeHelper<ConfigObjectBase, false>
{
	static ObjectFactory GetFactory()
	{
		return nullptr;
	}
};

template<>
class TypeImpl<ConfigObjectBase> : public Type
{
public:
	DECLARE_PTR_TYPEDEFS(TypeImpl<ConfigObjectBase>);

	TypeImpl();
	~TypeImpl() override;

	String GetName() const override;
	int GetAttributes() const override;
	Type::Ptr GetBaseType() const override;
	int GetFieldId(const String& name) const override;
	Field GetFieldInfo(int id) const override;
	int GetFieldCount() const override;
	ObjectFactory GetFactory() const override;
	int GetActivationPriority() const override;
public:
	void RegisterAttributeHandler(int fieldId, const Type::AttributeHandler& callback) override;
};


template<>
class ObjectImpl<ConfigObjectBase> : public Object
{
public:
	DECLARE_PTR_TYPEDEFS(ObjectImpl<ConfigObjectBase>);

	void Validate(int types, const ValidationUtils& utils) override;
public:
	ObjectImpl<ConfigObjectBase>();
public:
	~ObjectImpl<ConfigObjectBase>() override;
};


class ConfigObjectBase : public ObjectImpl<ConfigObjectBase>
{
public:
	inline DebugInfo GetDebugInfo() const
	{
		return m_DebugInfo;
	}

	void SetDebugInfo(const DebugInfo& di)
	{
		m_DebugInfo = di;
	}

	inline virtual void Start(bool /* runtimeCreated */)
	{ }

	inline virtual void Stop(bool /* runtimeRemoved */)
	{ }

private:
	DebugInfo m_DebugInfo;
};


class ConfigObject;

template<>
struct TypeHelper<ConfigObject, false>
{
	static ObjectFactory GetFactory()
	{
		return nullptr;
	}
};

template<>
class TypeImpl<ConfigObject> : public TypeImpl<ConfigObjectBase>, public ConfigType
{
public:
	DECLARE_PTR_TYPEDEFS(TypeImpl<ConfigObject>);

	TypeImpl();
	~TypeImpl() override;

	String GetName() const override;
	int GetAttributes() const override;
	Type::Ptr GetBaseType() const override;
	int GetFieldId(const String& name) const override;
	Field GetFieldInfo(int id) const override;
	int GetFieldCount() const override;
	ObjectFactory GetFactory() const override;
	int GetActivationPriority() const override;
public:
	void RegisterAttributeHandler(int fieldId, const Type::AttributeHandler& callback) override;
};


template<>
class ObjectImpl<ConfigObject> : public ConfigObjectBase
{
public:
	DECLARE_PTR_TYPEDEFS(ObjectImpl<ConfigObject>);

	void Validate(int types, const ValidationUtils& utils) override;
	void SimpleValidateShortName(const Lazy<String>& value, const ValidationUtils& utils);
	void SimpleValidateIcingadbIdentifier(const Lazy<String>& value, const ValidationUtils& utils);
	void SimpleValidatePackage(const Lazy<String>& value, const ValidationUtils& utils);
	void SimpleValidateZoneName(const Lazy<String>& value, const ValidationUtils& utils);
	void SimpleValidateName(const Lazy<String>& value, const ValidationUtils& utils);
	void SimpleValidateVersion(const Lazy<double>& value, const ValidationUtils& utils);
	void SimpleValidateTemplates(const Lazy<Array::Ptr>& value, const ValidationUtils& utils);
	void SimpleValidateOriginalAttributes(const Lazy<Dictionary::Ptr>& value, const ValidationUtils& utils);
	void SimpleValidateExtensions(const Lazy<Dictionary::Ptr>& value, const ValidationUtils& utils);
	void SimpleValidateSourceLocation(const Lazy<Dictionary::Ptr>& value, const ValidationUtils& utils);
	void SimpleValidateHAMode(const Lazy<HAMode>& value, const ValidationUtils& utils);
	void SimpleValidatePaused(const Lazy<bool>& value, const ValidationUtils& utils);
	void SimpleValidateStartCalled(const Lazy<bool>& value, const ValidationUtils& utils);
	void SimpleValidateStopCalled(const Lazy<bool>& value, const ValidationUtils& utils);
	void SimpleValidatePauseCalled(const Lazy<bool>& value, const ValidationUtils& utils);
	void SimpleValidateResumeCalled(const Lazy<bool>& value, const ValidationUtils& utils);
	void SimpleValidateActive(const Lazy<bool>& value, const ValidationUtils& utils);
	void SimpleValidateStateLoaded(const Lazy<bool>& value, const ValidationUtils& utils);
public:
	ObjectImpl<ConfigObject>();
public:
	~ObjectImpl<ConfigObject>() override;
public:
	void SetField(int id, const Value& value, bool suppress_events = false, const Value& cookie = Empty) override;
public:
	Value GetField(int id) const override;
public:
	void ValidateField(int id, const Lazy<Value>& lvalue, const ValidationUtils& utils) override;
public:
	void NotifyField(int id, const Value& cookie = Empty) override;
public:
	Object::Ptr NavigateField(int id) const override;
public:
	String GetShortName() const;
public:
	String GetIcingadbIdentifier() const;
public:
	String GetPackage() const;
public:
	String GetZoneName() const;
public:
	String GetName() const;
public:
	double GetVersion() const;
protected:
	Array::Ptr GetTemplates() const;
public:
	Dictionary::Ptr GetOriginalAttributes() const;
protected:
	Dictionary::Ptr GetExtensions() const;
public:
	virtual Dictionary::Ptr GetSourceLocation() const = 0;
public:
	HAMode GetHAMode() const;
protected:
	bool GetPaused() const;
protected:
	bool GetStartCalled() const;
protected:
	bool GetStopCalled() const;
protected:
	bool GetPauseCalled() const;
protected:
	bool GetResumeCalled() const;
protected:
	bool GetActive() const;
protected:
	bool GetStateLoaded() const;
public:
	void SetShortName(const String& value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetIcingadbIdentifier(const String& value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetPackage(const String& value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetZoneName(const String& value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetName(const String& value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetVersion(double value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetTemplates(const Array::Ptr& value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetOriginalAttributes(const Dictionary::Ptr& value, bool suppress_events = false, const Value& cookie = Empty);
protected:
	void SetExtensions(const Dictionary::Ptr& value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetSourceLocation(const Dictionary::Ptr& value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetHAMode(const HAMode& value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetPaused(bool value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetStartCalled(bool value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetStopCalled(bool value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetPauseCalled(bool value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetResumeCalled(bool value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetActive(bool value, bool suppress_events = false, const Value& cookie = Empty);
protected:
	void SetStateLoaded(bool value, bool suppress_events = false, const Value& cookie = Empty);
protected:
	void TrackZoneName(const String& oldValue, const String& newValue);
protected:
	void Start(bool runtimeCreated = false) override;
	void Stop(bool runtimeRemoved = false) override;
public:
	virtual void NotifyShortName(const Value& cookie = Empty);
public:
	virtual void NotifyIcingadbIdentifier(const Value& cookie = Empty);
public:
	virtual void NotifyPackage(const Value& cookie = Empty);
public:
	virtual void NotifyZoneName(const Value& cookie = Empty);
public:
	virtual void NotifyName(const Value& cookie = Empty);
public:
	virtual void NotifyVersion(const Value& cookie = Empty);
public:
	virtual void NotifyTemplates(const Value& cookie = Empty);
public:
	virtual void NotifyOriginalAttributes(const Value& cookie = Empty);
protected:
	virtual void NotifyExtensions(const Value& cookie = Empty);
public:
	virtual void NotifySourceLocation(const Value& cookie = Empty);
public:
	virtual void NotifyHAMode(const Value& cookie = Empty);
public:
	virtual void NotifyPaused(const Value& cookie = Empty);
public:
	virtual void NotifyStartCalled(const Value& cookie = Empty);
public:
	virtual void NotifyStopCalled(const Value& cookie = Empty);
public:
	virtual void NotifyPauseCalled(const Value& cookie = Empty);
public:
	virtual void NotifyResumeCalled(const Value& cookie = Empty);
public:
	virtual void NotifyActive(const Value& cookie = Empty);
protected:
	virtual void NotifyStateLoaded(const Value& cookie = Empty);
private:
	inline String GetDefaultShortName() const;
private:
	inline String GetDefaultIcingadbIdentifier() const;
private:
	inline String GetDefaultPackage() const;
private:
	inline String GetDefaultZoneName() const;
private:
	inline String GetDefaultName() const;
private:
	inline double GetDefaultVersion() const;
private:
	inline Array::Ptr GetDefaultTemplates() const;
private:
	inline Dictionary::Ptr GetDefaultOriginalAttributes() const;
private:
	inline Dictionary::Ptr GetDefaultExtensions() const;
private:
	inline Dictionary::Ptr GetDefaultSourceLocation() const;
private:
	inline HAMode GetDefaultHAMode() const;
private:
	inline bool GetDefaultPaused() const;
private:
	inline bool GetDefaultStartCalled() const;
private:
	inline bool GetDefaultStopCalled() const;
private:
	inline bool GetDefaultPauseCalled() const;
private:
	inline bool GetDefaultResumeCalled() const;
private:
	inline bool GetDefaultActive() const;
private:
	inline bool GetDefaultStateLoaded() const;
protected:
	virtual void ValidateShortName(const Lazy<String>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateIcingadbIdentifier(const Lazy<String>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidatePackage(const Lazy<String>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateZoneName(const Lazy<String>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateName(const Lazy<String>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateVersion(const Lazy<double>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateTemplates(const Lazy<Array::Ptr>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateOriginalAttributes(const Lazy<Dictionary::Ptr>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateExtensions(const Lazy<Dictionary::Ptr>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateSourceLocation(const Lazy<Dictionary::Ptr>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateHAMode(const Lazy<HAMode>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidatePaused(const Lazy<bool>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateStartCalled(const Lazy<bool>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateStopCalled(const Lazy<bool>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidatePauseCalled(const Lazy<bool>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateResumeCalled(const Lazy<bool>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateActive(const Lazy<bool>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateStateLoaded(const Lazy<bool>& lvalue, const ValidationUtils& utils);
private:
	AtomicOrLocked<String> m_ShortName;
	AtomicOrLocked<String> m_IcingadbIdentifier;
	AtomicOrLocked<String> m_Package;
	AtomicOrLocked<String> m_ZoneName;
	AtomicOrLocked<String> m_Name;
	AtomicOrLocked<double> m_Version;
	AtomicOrLocked<Array::Ptr> m_Templates;
	AtomicOrLocked<Dictionary::Ptr> m_OriginalAttributes;
	AtomicOrLocked<Dictionary::Ptr> m_Extensions;
	AtomicOrLocked<HAMode> m_HAMode;
	AtomicOrLocked<bool> m_Paused;
	AtomicOrLocked<bool> m_StartCalled;
	AtomicOrLocked<bool> m_StopCalled;
	AtomicOrLocked<bool> m_PauseCalled;
	AtomicOrLocked<bool> m_ResumeCalled;
	AtomicOrLocked<bool> m_Active;
	AtomicOrLocked<bool> m_StateLoaded;
public:
	static boost::signals2::signal<void (const intrusive_ptr<ConfigObject>&, const Value&)> OnShortNameChanged;
	static boost::signals2::signal<void (const intrusive_ptr<ConfigObject>&, const Value&)> OnIcingadbIdentifierChanged;
	static boost::signals2::signal<void (const intrusive_ptr<ConfigObject>&, const Value&)> OnPackageChanged;
	static boost::signals2::signal<void (const intrusive_ptr<ConfigObject>&, const Value&)> OnZoneNameChanged;
	static boost::signals2::signal<void (const intrusive_ptr<ConfigObject>&, const Value&)> OnNameChanged;
	static boost::signals2::signal<void (const intrusive_ptr<ConfigObject>&, const Value&)> OnVersionChanged;
	static boost::signals2::signal<void (const intrusive_ptr<ConfigObject>&, const Value&)> OnTemplatesChanged;
	static boost::signals2::signal<void (const intrusive_ptr<ConfigObject>&, const Value&)> OnOriginalAttributesChanged;
	static boost::signals2::signal<void (const intrusive_ptr<ConfigObject>&, const Value&)> OnExtensionsChanged;
	static boost::signals2::signal<void (const intrusive_ptr<ConfigObject>&, const Value&)> OnSourceLocationChanged;
	static boost::signals2::signal<void (const intrusive_ptr<ConfigObject>&, const Value&)> OnHAModeChanged;
	static boost::signals2::signal<void (const intrusive_ptr<ConfigObject>&, const Value&)> OnPausedChanged;
	static boost::signals2::signal<void (const intrusive_ptr<ConfigObject>&, const Value&)> OnStartCalledChanged;
	static boost::signals2::signal<void (const intrusive_ptr<ConfigObject>&, const Value&)> OnStopCalledChanged;
	static boost::signals2::signal<void (const intrusive_ptr<ConfigObject>&, const Value&)> OnPauseCalledChanged;
	static boost::signals2::signal<void (const intrusive_ptr<ConfigObject>&, const Value&)> OnResumeCalledChanged;
	static boost::signals2::signal<void (const intrusive_ptr<ConfigObject>&, const Value&)> OnActiveChanged;
	static boost::signals2::signal<void (const intrusive_ptr<ConfigObject>&, const Value&)> OnStateLoadedChanged;
	friend class ConfigItem;
	friend class ConfigType;
};

}
#endif /* CONFIGOBJECT_TI */
