#ifndef TIMEPERIOD_TI
#define TIMEPERIOD_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 "icinga/customvarobject.hpp"

#include "base/function.hpp"

namespace icinga
{

class TimePeriod;

template<>
class TypeImpl<TimePeriod> : public TypeImpl<CustomVarObject>
{
public:
	DECLARE_PTR_TYPEDEFS(TypeImpl<TimePeriod>);

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

	void Validate(int types, const ValidationUtils& utils) override;
	void SimpleValidateValidBegin(const Lazy<Value>& value, const ValidationUtils& utils);
	void SimpleValidateValidEnd(const Lazy<Value>& value, const ValidationUtils& utils);
	void SimpleValidateDisplayName(const Lazy<String>& value, const ValidationUtils& utils);
	void SimpleValidateExcludes(const Lazy<Array::Ptr>& avalue, const ValidationUtils& utils);
	void SimpleValidateIncludes(const Lazy<Array::Ptr>& avalue, const ValidationUtils& utils);
	void SimpleValidateSegments(const Lazy<Array::Ptr>& value, const ValidationUtils& utils);
	void SimpleValidateRanges(const Lazy<Dictionary::Ptr>& value, const ValidationUtils& utils);
	void SimpleValidateUpdate(const Lazy<Function::Ptr>& value, const ValidationUtils& utils);
	void SimpleValidatePreferIncludes(const Lazy<bool>& value, const ValidationUtils& utils);
	void SimpleValidateIsInside(const Lazy<bool>& value, const ValidationUtils& utils);
public:
	ObjectImpl<TimePeriod>();
public:
	~ObjectImpl<TimePeriod>() 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:
	Value GetValidBegin() const;
public:
	Value GetValidEnd() const;
public:
	String GetDisplayName() const;
public:
	Array::Ptr GetExcludes() const;
public:
	Array::Ptr GetIncludes() const;
public:
	Array::Ptr GetSegments() const;
public:
	Dictionary::Ptr GetRanges() const;
public:
	Function::Ptr GetUpdate() const;
public:
	bool GetPreferIncludes() const;
public:
	virtual bool GetIsInside() const = 0;
public:
	void SetValidBegin(const Value& value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetValidEnd(const Value& value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetDisplayName(const String& value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetExcludes(const Array::Ptr& value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetIncludes(const Array::Ptr& value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetSegments(const Array::Ptr& value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetRanges(const Dictionary::Ptr& value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetUpdate(const Function::Ptr& value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetPreferIncludes(bool value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetIsInside(bool value, bool suppress_events = false, const Value& cookie = Empty);
protected:
	void TrackExcludes(const Array::Ptr& oldValue, const Array::Ptr& newValue);
	void TrackIncludes(const Array::Ptr& oldValue, const Array::Ptr& newValue);
protected:
	void Start(bool runtimeCreated = false) override;
	void Stop(bool runtimeRemoved = false) override;
public:
	virtual void NotifyValidBegin(const Value& cookie = Empty);
public:
	virtual void NotifyValidEnd(const Value& cookie = Empty);
public:
	virtual void NotifyDisplayName(const Value& cookie = Empty);
public:
	virtual void NotifyExcludes(const Value& cookie = Empty);
public:
	virtual void NotifyIncludes(const Value& cookie = Empty);
public:
	virtual void NotifySegments(const Value& cookie = Empty);
public:
	virtual void NotifyRanges(const Value& cookie = Empty);
public:
	virtual void NotifyUpdate(const Value& cookie = Empty);
public:
	virtual void NotifyPreferIncludes(const Value& cookie = Empty);
public:
	virtual void NotifyIsInside(const Value& cookie = Empty);
private:
	inline Value GetDefaultValidBegin() const;
private:
	inline Value GetDefaultValidEnd() const;
private:
	inline String GetDefaultDisplayName() const;
private:
	inline Array::Ptr GetDefaultExcludes() const;
private:
	inline Array::Ptr GetDefaultIncludes() const;
private:
	inline Array::Ptr GetDefaultSegments() const;
private:
	inline Dictionary::Ptr GetDefaultRanges() const;
private:
	inline Function::Ptr GetDefaultUpdate() const;
private:
	inline bool GetDefaultPreferIncludes() const;
private:
	inline bool GetDefaultIsInside() const;
protected:
	virtual void ValidateValidBegin(const Lazy<Value>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateValidEnd(const Lazy<Value>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateDisplayName(const Lazy<String>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateExcludes(const Lazy<Array::Ptr>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateIncludes(const Lazy<Array::Ptr>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateSegments(const Lazy<Array::Ptr>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateRanges(const Lazy<Dictionary::Ptr>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateUpdate(const Lazy<Function::Ptr>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidatePreferIncludes(const Lazy<bool>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateIsInside(const Lazy<bool>& lvalue, const ValidationUtils& utils);
private:
	AtomicOrLocked<Value> m_ValidBegin;
	AtomicOrLocked<Value> m_ValidEnd;
	AtomicOrLocked<String> m_DisplayName;
	AtomicOrLocked<Array::Ptr> m_Excludes;
	AtomicOrLocked<Array::Ptr> m_Includes;
	AtomicOrLocked<Array::Ptr> m_Segments;
	AtomicOrLocked<Dictionary::Ptr> m_Ranges;
	AtomicOrLocked<Function::Ptr> m_Update;
	AtomicOrLocked<bool> m_PreferIncludes;
public:
	static boost::signals2::signal<void (const intrusive_ptr<TimePeriod>&, const Value&)> OnValidBeginChanged;
	static boost::signals2::signal<void (const intrusive_ptr<TimePeriod>&, const Value&)> OnValidEndChanged;
	static boost::signals2::signal<void (const intrusive_ptr<TimePeriod>&, const Value&)> OnDisplayNameChanged;
	static boost::signals2::signal<void (const intrusive_ptr<TimePeriod>&, const Value&)> OnExcludesChanged;
	static boost::signals2::signal<void (const intrusive_ptr<TimePeriod>&, const Value&, const Value&)> OnExcludesChangedWithOldValue;
	static boost::signals2::signal<void (const intrusive_ptr<TimePeriod>&, const Value&)> OnIncludesChanged;
	static boost::signals2::signal<void (const intrusive_ptr<TimePeriod>&, const Value&, const Value&)> OnIncludesChangedWithOldValue;
	static boost::signals2::signal<void (const intrusive_ptr<TimePeriod>&, const Value&)> OnSegmentsChanged;
	static boost::signals2::signal<void (const intrusive_ptr<TimePeriod>&, const Value&)> OnRangesChanged;
	static boost::signals2::signal<void (const intrusive_ptr<TimePeriod>&, const Value&, const Value&)> OnRangesChangedWithOldValue;
	static boost::signals2::signal<void (const intrusive_ptr<TimePeriod>&, const Value&)> OnUpdateChanged;
	static boost::signals2::signal<void (const intrusive_ptr<TimePeriod>&, const Value&)> OnPreferIncludesChanged;
	static boost::signals2::signal<void (const intrusive_ptr<TimePeriod>&, const Value&)> OnIsInsideChanged;
};

}
#endif /* TIMEPERIOD_TI */
