#ifndef _EFL_OBJECT_EO_H_
#define _EFL_OBJECT_EO_H_

#ifndef _EFL_OBJECT_EO_CLASS_TYPE
#define _EFL_OBJECT_EO_CLASS_TYPE

typedef Eo Efl_Object;

#endif

#ifndef _EFL_OBJECT_EO_TYPES
#define _EFL_OBJECT_EO_TYPES

/** This struct holds the description of a specific event.
 *
 * @ingroup Efl
 */
typedef struct _Efl_Event_Description
{
  const char *name; /**< name of the event. */
  Eina_Bool unfreezable; /**< @c true if the event cannot be frozen. */
  Eina_Bool legacy_is; /**< Internal use: @c true if a legacy event. */
  Eina_Bool restart; /**< @c true if when the event is triggered again from a
                      * callback it'll start from where it was */
} Efl_Event_Description;

/**
 * @brief A parameter passed in event callbacks holding extra event parameters.
 *
 * This is the full event information passed to callbacks in C.
 *
 * @ingroup Efl
 */
typedef struct _Efl_Event
{
  Efl_Object *object; /**< The object the callback was called on. */
  const Efl_Event_Description *desc; /**< The event description. */
  void *info; /**< Extra event information passed by the event caller */
} Efl_Event;


#endif
/** Abstract Efl object class
 *
 * @ingroup Efl_Object
 */
#define EFL_OBJECT_CLASS efl_object_class_get()

EWAPI const Efl_Class *efl_object_class_get(void);

/**
 * @brief The parent of an object.
 *
 * Parents keep references to their children. In order to delete objects which
 * have parents you need to set parent to NULL or use efl_del(). This will both
 * delete & unref the object).
 *
 * The Eo parent is conceptually user set. That means that a parent should not
 * be changed behind the scenes in an unexpected way.
 *
 * For example: If you have a widget that has a box internally and when you
 * 'swallow' a widget and the swallowed object ends up in the box, the parent
 * should be the widget, not the box.
 *
 * @param[in] obj The object.
 * @param[in] parent The new parent
 *
 * @ingroup Efl_Object
 */
EOAPI void efl_parent_set(Eo *obj, Efl_Object *parent);

/**
 * @brief The parent of an object.
 *
 * Parents keep references to their children. In order to delete objects which
 * have parents you need to set parent to NULL or use efl_del(). This will both
 * delete & unref the object).
 *
 * The Eo parent is conceptually user set. That means that a parent should not
 * be changed behind the scenes in an unexpected way.
 *
 * For example: If you have a widget that has a box internally and when you
 * 'swallow' a widget and the swallowed object ends up in the box, the parent
 * should be the widget, not the box.
 *
 * @param[in] obj The object.
 *
 * @return The new parent
 *
 * @ingroup Efl_Object
 */
EOAPI Efl_Object *efl_parent_get(const Eo *obj);

/**
 * @brief The name of the object.
 *
 * Every object can have a string name. Names may not contain the following
 * characters: / ? * [ ] ! \ : Using any of these in a name will result in
 * undefined behavior later on. An empty string is considered the same as a
 * NULL string or no string for the name.
 *
 * @param[in] obj The object.
 * @param[in] name The name
 *
 * @ingroup Efl_Object
 */
EOAPI void efl_name_set(Eo *obj, const char *name);

/**
 * @brief The name of the object.
 *
 * Every object can have a string name. Names may not contain the following
 * characters: / ? * [ ] ! \ : Using any of these in a name will result in
 * undefined behavior later on. An empty string is considered the same as a
 * NULL string or no string for the name.
 *
 * @param[in] obj The object.
 *
 * @return The name
 *
 * @ingroup Efl_Object
 */
EOAPI const char *efl_name_get(const Eo *obj);

/**
 * @brief A human readable comment for the object
 *
 * Every object can have a string comment. This is intended for developers and
 * debugging. An empty string is considered the same as a NULL string or no
 * string for the comment.
 *
 * @param[in] obj The object.
 * @param[in] comment The comment
 *
 * @ingroup Efl_Object
 */
EOAPI void efl_comment_set(Eo *obj, const char *comment);

/**
 * @brief A human readable comment for the object
 *
 * Every object can have a string comment. This is intended for developers and
 * debugging. An empty string is considered the same as a NULL string or no
 * string for the comment.
 *
 * @param[in] obj The object.
 *
 * @return The comment
 *
 * @ingroup Efl_Object
 */
EOAPI const char *efl_comment_get(const Eo *obj);

/**
 * @brief Build a read-only name for this object used for debugging.
 *
 * Multiple calls using efl_super() can be chained in order to build the entire
 * debug name, from parent to child classes. In C the usual way to build the
 * string is as follows:
 *
 * efl_debug_name_override(efl_super(obj, MY_CLASS), sb);
 * eina_strbuf_append_printf(sb, "new_information");
 *
 * Usually more debug information should be added to @c sb after calling the
 * super function.
 *
 * @param[in] obj The object.
 * @param[in] sb A string buffer, must not be @c null.
 *
 * @since 1.21
 *
 * @ingroup Efl_Object
 */
EOAPI void efl_debug_name_override(Eo *obj, Eina_Strbuf *sb);

/**
 * @brief Return freeze events of object.
 *
 * Return event freeze count.
 *
 * @return The event freeze count of the object
 *
 * @ingroup Efl_Object
 */
EOAPI int efl_event_global_freeze_count_get(const Eo *obj);

/**
 * @brief Return freeze events of object.
 *
 * Return event freeze count.
 *
 * @param[in] obj The object.
 *
 * @return The event freeze count of the object
 *
 * @ingroup Efl_Object
 */
EOAPI int efl_event_freeze_count_get(const Eo *obj);

/**
 * @brief True if the object is already finalized, otherwise false.
 *
 * @param[in] obj The object.
 *
 * @return @c true if the object is finalized, @c false otherwise
 *
 * @ingroup Efl_Object
 */
EOAPI Eina_Bool efl_finalized_get(const Eo *obj);

/**
 * @brief True if the object is already invalidated, otherwise false.
 *
 * @param[in] obj The object.
 *
 * @return @c true if the object is invalidated, @c false otherwise
 *
 * @ingroup Efl_Object
 */
EOAPI Eina_Bool efl_invalidated_get(const Eo *obj);

/**
 * @brief Searches upwards in the object tree for a provider which knows the
 * given class/interface.
 *
 * The object from the provider will then be returned. The base implementation
 * calls the provider_find function on the object parent, and returns its
 * result. If no parent is present NULL is returned. Each implementation has to
 * support this function by overriding it and returning itself if the interface
 * matches the parameter. If this is not done the class cannot be found up in
 * the object tree.
 *
 * @param[in] obj The object.
 * @param[in] klass The class identifier to search for
 *
 * @return Object from the provider list
 *
 * @ingroup Efl_Object
 */
EOAPI Efl_Object *efl_provider_find(const Eo *obj, const Efl_Object *klass);

/**
 * @brief Call the object's constructor.
 *
 * Should not be used with #eo_do. Only use it with #eo_do_super.
 *
 * @param[in] obj The object.
 *
 * @return The new object created, can be NULL if aborting
 *
 * @ingroup Efl_Object
 */
EOAPI Efl_Object *efl_constructor(Eo *obj);

/**
 * @brief Call the object's destructor.
 *
 * Should not be used with #efl_do. Only use it with #efl_do_super. Will be
 * triggered once #invalidate and #noref have been triggered.
 * @param[in] obj The object.
 *
 * @ingroup Efl_Object
 */
EOAPI void efl_destructor(Eo *obj);

/**
 * @brief Called at the end of efl_add. Should not be called, just overridden.
 *
 * @param[in] obj The object.
 *
 * @return The new object created, can be NULL if aborting
 *
 * @ingroup Efl_Object
 */
EOAPI Efl_Object *efl_finalize(Eo *obj);

/** Called when parent reference is lost/set to @c NULL and switch the state of
 * the object to invalidate.
 *
 * @ingroup Efl_Object
 */
EOAPI void efl_invalidate(Eo *obj);

/**
 * @brief Triggered when no reference are keeping the object alive.
 *
 * The parent can be the last one keeping an object alive and so @c noref can
 * happen before @c invalidate as it is only impacted by the ref/unref of the
 * object.
 * @param[in] obj The object.
 *
 * @ingroup Efl_Object
 */
EOAPI void efl_noref(Eo *obj);

/**
 * @brief Find a child object with the given name and return it.
 *
 * The search string can be a glob (shell style, using *). It can also specify
 * class name in the format of "class:name" where ":" separates class and name.
 * Both class and name can be globs. If the class is specified but the name is
 * empty like "class:" then the search will match any object of that class.
 *
 * @param[in] obj The object.
 * @param[in] search The name search string
 *
 * @return The first object found
 *
 * @ingroup Efl_Object
 */
EOAPI Efl_Object *efl_name_find(const Eo *obj, const char *search);

/**
 * @brief Thaw events of object.
 *
 * Allows event callbacks to be called for an object.
 * @param[in] obj The object.
 *
 * @ingroup Efl_Object
 */
EOAPI void efl_event_thaw(Eo *obj);

/**
 * @brief Freeze events of object.
 *
 * Prevents event callbacks from being called for an object.
 * @param[in] obj The object.
 *
 * @ingroup Efl_Object
 */
EOAPI void efl_event_freeze(Eo *obj);

/**
 * @brief Thaw events of object.
 *
 * Allows event callbacks be called for an object.
 *
 * @ingroup Efl_Object
 */
EOAPI void efl_event_global_thaw(const Eo *obj);

/**
 * @brief Freeze events of object.
 *
 * Prevents event callbacks from being called for an object.
 *
 * @ingroup Efl_Object
 */
EOAPI void efl_event_global_freeze(const Eo *obj);

/**
 * @brief Stop the current callback call.
 *
 * This stops the current callback call. Any other callbacks for the current
 * event will not be called. This is useful when you want to filter out events.
 * Just add higher priority events and call this under certain conditions to
 * block a certain event.
 * @param[in] obj The object.
 *
 * @ingroup Efl_Object
 */
EOAPI void efl_event_callback_stop(Eo *obj);

/**
 * @brief Add an event callback forwarder for an event and an object.
 *
 * @param[in] obj The object.
 * @param[in] desc The description of the event to listen to
 * @param[in] new_obj The object to emit events from
 *
 * @ingroup Efl_Object
 */
EOAPI void efl_event_callback_forwarder_add(Eo *obj, const Efl_Event_Description *desc, Efl_Object *new_obj);

/**
 * @brief Remove an event callback forwarder for an event and an object.
 *
 * @param[in] obj The object.
 * @param[in] desc The description of the event to listen to
 * @param[in] new_obj The object to emit events from
 *
 * @ingroup Efl_Object
 */
EOAPI void efl_event_callback_forwarder_del(Eo *obj, const Efl_Event_Description *desc, Efl_Object *new_obj);

/**
 * @brief Get an iterator on all childrens
 *
 * @param[in] obj The object.
 *
 * @return Children iterator
 *
 * @ingroup Efl_Object
 */
EOAPI Eina_Iterator *efl_children_iterator_new(Eo *obj) EINA_WARN_UNUSED_RESULT;

/**
 * @brief Make an object a composite object of another.
 *
 * The class of comp_obj must be part of the extensions of the class of the
 * parent. It isn't possible to attach more then 1 composite of the same class.
 * This function also sets the parent of comp_obj to parent.
 *
 * See @ref efl_composite_detach, @ref efl_composite_part_is.
 *
 * @param[in] obj The object.
 * @param[in] comp_obj the object that will be used to composite the parent.
 *
 * @return @c true if successful. @c false otherwise.
 *
 * @ingroup Efl_Object
 */
EOAPI Eina_Bool efl_composite_attach(Eo *obj, Efl_Object *comp_obj);

/**
 * @brief Detach a composite object from another object.
 *
 * This functions also sets the parent of comp_obj to @c null.
 *
 * See @ref efl_composite_attach, @ref efl_composite_part_is.
 *
 * @param[in] obj The object.
 * @param[in] comp_obj The object that will be removed from the parent.
 *
 * @return @c true if successful. @c false otherwise.
 *
 * @ingroup Efl_Object
 */
EOAPI Eina_Bool efl_composite_detach(Eo *obj, Efl_Object *comp_obj);

/**
 * @brief Check if an object is part of a composite object.
 *
 * See @ref efl_composite_attach, @ref efl_composite_part_is.
 *
 * @param[in] obj The object.
 *
 * @return @c true if it is. @c false otherwise.
 *
 * @ingroup Efl_Object
 */
EOAPI Eina_Bool efl_composite_part_is(Eo *obj);

/**
 * @brief Allow an object to be deleted by unref even if it has a parent.
 *
 * This simply hides the error message warning that an object being destroyed
 * still has a parent. This property is false by default.
 *
 * In a normal object use case, when ownership of an object is given to a
 * caller, said ownership should be released with efl_unref(). If the object
 * has a parent, this will print error messages, as @c efl_unref() is stealing
 * the ref from the parent.
 *
 * @warning Use this function very carefully, unless you're absolutely sure of
 * what you are doing.
 *
 * @param[in] obj The object.
 * @param[in] allow Whether to allow @c efl_unref() to zero even if
 * @ref efl_parent_get is not @c null.
 *
 * @ingroup Efl_Object
 */
EOAPI void efl_allow_parent_unref_set(Eo *obj, Eina_Bool allow);

/**
 * @brief Allow an object to be deleted by unref even if it has a parent.
 *
 * This simply hides the error message warning that an object being destroyed
 * still has a parent. This property is false by default.
 *
 * In a normal object use case, when ownership of an object is given to a
 * caller, said ownership should be released with efl_unref(). If the object
 * has a parent, this will print error messages, as @c efl_unref() is stealing
 * the ref from the parent.
 *
 * @warning Use this function very carefully, unless you're absolutely sure of
 * what you are doing.
 *
 * @param[in] obj The object.
 *
 * @return Whether to allow @c efl_unref() to zero even if @ref efl_parent_get
 * is not @c null.
 *
 * @ingroup Efl_Object
 */
EOAPI Eina_Bool efl_allow_parent_unref_get(const Eo *obj);

EWAPI extern const Efl_Event_Description _EFL_EVENT_DEL;

/** Object is being deleted.
 *
 * @ingroup Efl_Object
 */
#define EFL_EVENT_DEL (&(_EFL_EVENT_DEL))

EWAPI extern const Efl_Event_Description _EFL_EVENT_INVALIDATE;

/** Object is being invalidated and loosing its parent.
 *
 * @ingroup Efl_Object
 */
#define EFL_EVENT_INVALIDATE (&(_EFL_EVENT_INVALIDATE))

EWAPI extern const Efl_Event_Description _EFL_EVENT_NOREF;

/** Object has lost its last reference, only parent relationship is keeping it
 * alive.
 *
 * @ingroup Efl_Object
 */
#define EFL_EVENT_NOREF (&(_EFL_EVENT_NOREF))

EWAPI extern const Efl_Event_Description _EFL_EVENT_DESTRUCT;

/** Object has been fully destroyed. It can not be used beyond this point. This
 * event should only serve to clean up any dangling pointer.
 *
 * @ingroup Efl_Object
 */
#define EFL_EVENT_DESTRUCT (&(_EFL_EVENT_DESTRUCT))

#endif
