#ifndef ZONE_TI
#define ZONE_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/configobject.hpp"

namespace icinga
{

class Zone;

template<>
class TypeImpl<Zone> : public TypeImpl<ConfigObject>
{
public:
	DECLARE_PTR_TYPEDEFS(TypeImpl<Zone>);

	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<Zone> : public ConfigObject
{
public:
	DECLARE_PTR_TYPEDEFS(ObjectImpl<Zone>);

	void Validate(int types, const ValidationUtils& utils) override;
	void SimpleValidateParentRaw(const Lazy<String>& value, const ValidationUtils& utils);
	void SimpleValidateEndpointsRaw(const Lazy<Array::Ptr>& avalue, const ValidationUtils& utils);
	void SimpleValidateAllParents(const Lazy<Array::Ptr>& avalue, const ValidationUtils& utils);
	void SimpleValidateGlobal(const Lazy<bool>& value, const ValidationUtils& utils);
public:
	ObjectImpl<Zone>();
public:
	~ObjectImpl<Zone>() 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 GetParentRaw() const;
public:
	Array::Ptr GetEndpointsRaw() const;
public:
	virtual Array::Ptr GetAllParents() const = 0;
public:
	bool GetGlobal() const;
public:
	void SetParentRaw(const String& value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetEndpointsRaw(const Array::Ptr& value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetAllParents(const Array::Ptr& value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetGlobal(bool value, bool suppress_events = false, const Value& cookie = Empty);
protected:
	void TrackParentRaw(const String& oldValue, const String& newValue);
	void TrackEndpointsRaw(const Array::Ptr& oldValue, const Array::Ptr& newValue);
public:
	Object::Ptr NavigateParentRaw() const;
protected:
	void Start(bool runtimeCreated = false) override;
	void Stop(bool runtimeRemoved = false) override;
public:
	virtual void NotifyParentRaw(const Value& cookie = Empty);
public:
	virtual void NotifyEndpointsRaw(const Value& cookie = Empty);
public:
	virtual void NotifyAllParents(const Value& cookie = Empty);
public:
	virtual void NotifyGlobal(const Value& cookie = Empty);
private:
	inline String GetDefaultParentRaw() const;
private:
	inline Array::Ptr GetDefaultEndpointsRaw() const;
private:
	inline Array::Ptr GetDefaultAllParents() const;
private:
	inline bool GetDefaultGlobal() const;
protected:
	virtual void ValidateParentRaw(const Lazy<String>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateEndpointsRaw(const Lazy<Array::Ptr>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateAllParents(const Lazy<Array::Ptr>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateGlobal(const Lazy<bool>& lvalue, const ValidationUtils& utils);
private:
	AtomicOrLocked<String> m_ParentRaw;
	AtomicOrLocked<Array::Ptr> m_EndpointsRaw;
	AtomicOrLocked<bool> m_Global;
public:
	static boost::signals2::signal<void (const intrusive_ptr<Zone>&, const Value&)> OnParentRawChanged;
	static boost::signals2::signal<void (const intrusive_ptr<Zone>&, const Value&)> OnEndpointsRawChanged;
	static boost::signals2::signal<void (const intrusive_ptr<Zone>&, const Value&)> OnAllParentsChanged;
	static boost::signals2::signal<void (const intrusive_ptr<Zone>&, const Value&)> OnGlobalChanged;
};

}
#endif /* ZONE_TI */
