#ifndef SERVICE_TI
#define SERVICE_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/checkable.hpp"

#include "icinga/host.hpp"

#include "icinga/icingaapplication.hpp"

#include "icinga/customvarobject.hpp"

namespace icinga
{


class ServiceNameComposer : public NameComposer
{
public:
	virtual String MakeName(const String& shortName, const Object::Ptr& context) const override;
	virtual Dictionary::Ptr ParseName(const String& name) const override;
};

class Service;

template<>
class TypeImpl<Service> : public TypeImpl<Checkable>, public ServiceNameComposer
{
public:
	DECLARE_PTR_TYPEDEFS(TypeImpl<Service>);

	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;
	const std::unordered_set<Type*>& GetLoadDependencies() const override;
	int GetActivationPriority() const override;
public:
	void RegisterAttributeHandler(int fieldId, const Type::AttributeHandler& callback) override;
};


template<>
class ObjectImpl<Service> : public Checkable
{
public:
	DECLARE_PTR_TYPEDEFS(ObjectImpl<Service>);

	void Validate(int types, const ValidationUtils& utils) override;
	void SimpleValidateDisplayName(const Lazy<String>& value, const ValidationUtils& utils);
	void SimpleValidateHostName(const Lazy<String>& value, const ValidationUtils& utils);
	void SimpleValidateGroups(const Lazy<Array::Ptr>& avalue, const ValidationUtils& utils);
	void SimpleValidateHost(const Lazy<Host::Ptr>& value, const ValidationUtils& utils);
	void SimpleValidateState(const Lazy<ServiceState>& value, const ValidationUtils& utils);
	void SimpleValidateLastState(const Lazy<ServiceState>& value, const ValidationUtils& utils);
	void SimpleValidateLastHardState(const Lazy<ServiceState>& value, const ValidationUtils& utils);
	void SimpleValidateLastStateOK(const Lazy<Timestamp>& value, const ValidationUtils& utils);
	void SimpleValidateLastStateWarning(const Lazy<Timestamp>& value, const ValidationUtils& utils);
	void SimpleValidateLastStateCritical(const Lazy<Timestamp>& value, const ValidationUtils& utils);
	void SimpleValidateLastStateUnknown(const Lazy<Timestamp>& value, const ValidationUtils& utils);
public:
	ObjectImpl<Service>();
public:
	~ObjectImpl<Service>() 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 GetDisplayName() const;
public:
	String GetHostName() const;
public:
	Array::Ptr GetGroups() const;
public:
	virtual Host::Ptr GetHost() const = 0;
public:
	ServiceState GetState() const;
public:
	ServiceState GetLastState() const;
public:
	ServiceState GetLastHardState() const;
public:
	Timestamp GetLastStateOK() const;
public:
	Timestamp GetLastStateWarning() const;
public:
	Timestamp GetLastStateCritical() const;
public:
	Timestamp GetLastStateUnknown() const;
public:
	void SetDisplayName(const String& value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetHostName(const String& value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetGroups(const Array::Ptr& value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetHost(const Host::Ptr& value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetState(const ServiceState& value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetLastState(const ServiceState& value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetLastHardState(const ServiceState& value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetLastStateOK(const Timestamp& value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetLastStateWarning(const Timestamp& value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetLastStateCritical(const Timestamp& value, bool suppress_events = false, const Value& cookie = Empty);
public:
	void SetLastStateUnknown(const Timestamp& value, bool suppress_events = false, const Value& cookie = Empty);
protected:
	void TrackHostName(const String& oldValue, const String& newValue);
	void TrackGroups(const Array::Ptr& oldValue, const Array::Ptr& newValue);
public:
	Object::Ptr NavigateHost() const;
protected:
	void Start(bool runtimeCreated = false) override;
	void Stop(bool runtimeRemoved = false) override;
public:
	virtual void NotifyDisplayName(const Value& cookie = Empty);
public:
	virtual void NotifyHostName(const Value& cookie = Empty);
public:
	virtual void NotifyGroups(const Value& cookie = Empty);
public:
	virtual void NotifyHost(const Value& cookie = Empty);
public:
	virtual void NotifyState(const Value& cookie = Empty);
public:
	virtual void NotifyLastState(const Value& cookie = Empty);
public:
	virtual void NotifyLastHardState(const Value& cookie = Empty);
public:
	virtual void NotifyLastStateOK(const Value& cookie = Empty);
public:
	virtual void NotifyLastStateWarning(const Value& cookie = Empty);
public:
	virtual void NotifyLastStateCritical(const Value& cookie = Empty);
public:
	virtual void NotifyLastStateUnknown(const Value& cookie = Empty);
private:
	inline String GetDefaultDisplayName() const;
private:
	inline String GetDefaultHostName() const;
private:
	inline Array::Ptr GetDefaultGroups() const;
private:
	inline Host::Ptr GetDefaultHost() const;
private:
	inline ServiceState GetDefaultState() const;
private:
	inline ServiceState GetDefaultLastState() const;
private:
	inline ServiceState GetDefaultLastHardState() const;
private:
	inline Timestamp GetDefaultLastStateOK() const;
private:
	inline Timestamp GetDefaultLastStateWarning() const;
private:
	inline Timestamp GetDefaultLastStateCritical() const;
private:
	inline Timestamp GetDefaultLastStateUnknown() const;
protected:
	virtual void ValidateDisplayName(const Lazy<String>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateHostName(const Lazy<String>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateGroups(const Lazy<Array::Ptr>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateHost(const Lazy<Host::Ptr>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateState(const Lazy<ServiceState>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateLastState(const Lazy<ServiceState>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateLastHardState(const Lazy<ServiceState>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateLastStateOK(const Lazy<Timestamp>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateLastStateWarning(const Lazy<Timestamp>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateLastStateCritical(const Lazy<Timestamp>& lvalue, const ValidationUtils& utils);
protected:
	virtual void ValidateLastStateUnknown(const Lazy<Timestamp>& lvalue, const ValidationUtils& utils);
private:
	AtomicOrLocked<String> m_DisplayName;
	AtomicOrLocked<String> m_HostName;
	AtomicOrLocked<Array::Ptr> m_Groups;
	AtomicOrLocked<Timestamp> m_LastStateOK;
	AtomicOrLocked<Timestamp> m_LastStateWarning;
	AtomicOrLocked<Timestamp> m_LastStateCritical;
	AtomicOrLocked<Timestamp> m_LastStateUnknown;
public:
	static boost::signals2::signal<void (const intrusive_ptr<Service>&, const Value&)> OnDisplayNameChanged;
	static boost::signals2::signal<void (const intrusive_ptr<Service>&, const Value&)> OnHostNameChanged;
	static boost::signals2::signal<void (const intrusive_ptr<Service>&, const Value&)> OnGroupsChanged;
	static boost::signals2::signal<void (const intrusive_ptr<Service>&, const Value&, const Value&)> OnGroupsChangedWithOldValue;
	static boost::signals2::signal<void (const intrusive_ptr<Service>&, const Value&)> OnHostChanged;
	static boost::signals2::signal<void (const intrusive_ptr<Service>&, const Value&)> OnStateChanged;
	static boost::signals2::signal<void (const intrusive_ptr<Service>&, const Value&)> OnLastStateChanged;
	static boost::signals2::signal<void (const intrusive_ptr<Service>&, const Value&)> OnLastHardStateChanged;
	static boost::signals2::signal<void (const intrusive_ptr<Service>&, const Value&)> OnLastStateOKChanged;
	static boost::signals2::signal<void (const intrusive_ptr<Service>&, const Value&)> OnLastStateWarningChanged;
	static boost::signals2::signal<void (const intrusive_ptr<Service>&, const Value&)> OnLastStateCriticalChanged;
	static boost::signals2::signal<void (const intrusive_ptr<Service>&, const Value&)> OnLastStateUnknownChanged;
	friend class ServiceNameComposer;
};

}
#endif /* SERVICE_TI */
