#ifndef _EFL_UI_FOCUS_MANAGER_EO_H_
#define _EFL_UI_FOCUS_MANAGER_EO_H_

#ifndef _EFL_UI_FOCUS_MANAGER_EO_CLASS_TYPE
#define _EFL_UI_FOCUS_MANAGER_EO_CLASS_TYPE

typedef Eo Efl_Ui_Focus_Manager;

#endif

#ifndef _EFL_UI_FOCUS_MANAGER_EO_TYPES
#define _EFL_UI_FOCUS_MANAGER_EO_TYPES

/** Structure holding the graph of relations between focussable objects.
 *
 * @since 1.20
 *
 * @ingroup Efl_Ui_Focus
 */
typedef struct _Efl_Ui_Focus_Relations
{
  Eina_List *right; /**< List of objects on the right side */
  Eina_List *left; /**< [List of objects on the left side */
  Eina_List *top; /**< [List of objects above */
  Eina_List *down; /**< [List of objects below */
  Efl_Ui_Focus_Object *next; /**< [Next object */
  Efl_Ui_Focus_Object *prev; /**< Previous object */
  Efl_Ui_Focus_Object *parent; /**< Parent object */
  Efl_Ui_Focus_Manager *redirect; /**< Redirect manager */
  Efl_Ui_Focus_Object *node; /**< The node where this is the information from */
  Eina_Bool logical; /**< @c true if this node is only logical */
  int position_in_history; /**< The position in the history stack */
} Efl_Ui_Focus_Relations;

/** Structure holding the focus object with extra information on logical end
 *
 * @since 1.21
 *
 * @ingroup Efl_Ui_Focus
 */
typedef struct _Efl_Ui_Focus_Manager_Logical_End_Detail
{
  Eina_Bool is_regular_end; /**< @c true if logical end, @c false otherwise */
  Efl_Ui_Focus_Object *element; /**< Focus object element */
} Efl_Ui_Focus_Manager_Logical_End_Detail;


#endif
/**
 * @brief Calculates the directions of Efl.Ui.Focus.Direction
 *
 * Each registered item will get a other registered object into each direction,
 * you can get those items for the currently focused item if you call request
 * move.
 *
 * @since 1.20
 *
 * @ingroup Efl_Ui_Focus_Manager
 */
#define EFL_UI_FOCUS_MANAGER_INTERFACE efl_ui_focus_manager_interface_get()

EWAPI const Efl_Class *efl_ui_focus_manager_interface_get(void);

/**
 * @brief Move the focus into the given direction.
 *
 * This call flushes all changes. This means all changes between the last flush
 * and now are computed
 *
 * @param[in] obj The object.
 * @param[in] direction The direction to move to
 *
 * @return The element which is now focused
 *
 * @since 1.20
 *
 * @ingroup Efl_Ui_Focus_Manager
 */
EOAPI Efl_Ui_Focus_Object *efl_ui_focus_manager_move(Eo *obj, Efl_Ui_Focus_Direction direction);

/**
 * @brief Return the object next in the @c direction from @c child.
 *
 * @param[in] obj The object.
 * @param[in] direction Direction to move focus
 * @param[in] child The child where to look from. Pass @c null to indicate the
 * last focused child.
 * @param[in] logical Weather you want to have a logical node as result or a
 * logical. Note, at a move call no logical node will get focus, and this is
 * passed as @c false there.
 *
 * @return Next object to focus
 *
 * @since 1.20
 *
 * @ingroup Efl_Ui_Focus_Manager
 */
EOAPI Efl_Ui_Focus_Object *efl_ui_focus_manager_request_move(Eo *obj, Efl_Ui_Focus_Direction direction, Efl_Ui_Focus_Object *child, Eina_Bool logical);

/**
 * @brief The element which is currently focused by this manager
 *
 * For the case focus is a logical child, then the item will go to the next
 * none logical element. If there is none, focus will stay where it is right
 * now.
 *
 * @param[in] obj The object.
 * @param[in] focus Focused element
 *
 * @since 1.20
 *
 * @ingroup Efl_Ui_Focus_Manager
 */
EOAPI void efl_ui_focus_manager_focus_set(Eo *obj, Efl_Ui_Focus_Object *focus) EINA_ARG_NONNULL(2);

/**
 * @brief The element which is currently focused by this manager
 *
 * For the case focus is a logical child, then the item will go to the next
 * none logical element. If there is none, focus will stay where it is right
 * now.
 *
 * @param[in] obj The object.
 *
 * @return Focused element
 *
 * @since 1.20
 *
 * @ingroup Efl_Ui_Focus_Manager
 */
EOAPI Efl_Ui_Focus_Object *efl_ui_focus_manager_focus_get(const Eo *obj);

/**
 * @brief Add a another manager to serve the move requests.
 *
 * If this value is set, all move requests are redirected to this manager
 * object. Set it to @c null once nothing should be redirected anymore.
 *
 * @param[in] obj The object.
 * @param[in] redirect The redirect manager.
 *
 * @since 1.20
 *
 * @ingroup Efl_Ui_Focus_Manager
 */
EOAPI void efl_ui_focus_manager_redirect_set(Eo *obj, Efl_Ui_Focus_Manager *redirect);

/**
 * @brief Add a another manager to serve the move requests.
 *
 * If this value is set, all move requests are redirected to this manager
 * object. Set it to @c null once nothing should be redirected anymore.
 *
 * @param[in] obj The object.
 *
 * @return The redirect manager.
 *
 * @since 1.20
 *
 * @ingroup Efl_Ui_Focus_Manager
 */
EOAPI Efl_Ui_Focus_Manager *efl_ui_focus_manager_redirect_get(const Eo *obj);

/**
 * @brief The list of elements which are at the border of the graph.
 *
 * This means one of the relations right,left or down,up are not set. This call
 * flushes all changes. See @ref efl_ui_focus_manager_move
 *
 * @param[in] obj The object.
 *
 * @return An iterator over the border objects.
 *
 * @since 1.20
 *
 * @ingroup Efl_Ui_Focus_Manager
 */
EOAPI Eina_Iterator *efl_ui_focus_manager_border_elements_get(const Eo *obj);

/**
 * @brief Root node for all logical subtrees.
 *
 * This property can only be set once.
 *
 * @param[in] obj The object.
 * @param[in] root Will be registered into this manager object.
 *
 * @return If @c true, this is the root node
 *
 * @since 1.20
 *
 * @ingroup Efl_Ui_Focus_Manager
 */
EOAPI Eina_Bool efl_ui_focus_manager_root_set(Eo *obj, Efl_Ui_Focus_Object *root) EINA_ARG_NONNULL(2);

/**
 * @brief Root node for all logical subtrees.
 *
 * This property can only be set once.
 *
 * @param[in] obj The object.
 *
 * @return Will be registered into this manager object.
 *
 * @since 1.20
 *
 * @ingroup Efl_Ui_Focus_Manager
 */
EOAPI Efl_Ui_Focus_Object *efl_ui_focus_manager_root_get(const Eo *obj);

/**
 * @brief Returns a widget that can receive focus
 *
 * The returned widget is in a child of the passed param. Its garanteed that
 * child will not be prepared once again, so you can call this function out of
 * a prepare call.
 *
 * @param[in] obj The object.
 * @param[in] child Parent for returned child
 *
 * @return Child of passed parameter
 *
 * @since 1.20
 *
 * @ingroup Efl_Ui_Focus_Manager
 */
EOAPI Efl_Ui_Focus_Object *efl_ui_focus_manager_request_subchild(Eo *obj, Efl_Ui_Focus_Object *child);

/**
 * @brief This will fetch the data from a registered node.
 *
 * Be aware this function will trigger all dirty nodes to be computed
 *
 * @param[in] obj The object.
 * @param[in] child The child object to inspect.
 *
 * @return The list of relations starting from @c child.
 *
 * @since 1.20
 *
 * @ingroup Efl_Ui_Focus_Manager
 */
EOAPI Efl_Ui_Focus_Relations *efl_ui_focus_manager_fetch(Eo *obj, Efl_Ui_Focus_Object *child);

/**
 * @brief Return the last logical object.
 *
 * The returned object is the last object that would be returned if you start
 * at the root and move the direction into next.
 *
 * @param[in] obj The object.
 *
 * @return Last object
 *
 * @since 1.20
 *
 * @ingroup Efl_Ui_Focus_Manager
 */
EOAPI Efl_Ui_Focus_Manager_Logical_End_Detail efl_ui_focus_manager_logical_end(Eo *obj);

/**
 * @brief Reset the history stack of this manager object. This means the most
 * upper element will be unfocused, all other elements will be removed from the
 * remembered before.
 *
 * To not break the assertion that there should be always a focused element,
 * you should focus a other element immidiatly after calling that.
 *
 * @param[in] obj The object.
 *
 * @since 1.20
 *
 * @ingroup Efl_Ui_Focus_Manager
 */
EOAPI void efl_ui_focus_manager_reset_history(Eo *obj);

/**
 * @brief Removes the most upper history element, and move focus on.
 *
 * If there is a element that was focused before, it will be taken. Otherwise,
 * the best fitting element from the registered elements will be focused.
 *
 * @param[in] obj The object.
 *
 * @since 1.20
 *
 * @ingroup Efl_Ui_Focus_Manager
 */
EOAPI void efl_ui_focus_manager_pop_history_stack(Eo *obj);

/**
 * @brief Called when this manager is set as redirect
 *
 * @param[in] obj The object.
 * @param[in] direction The direction in which this should be setup
 * @param[in] entry The object that caused this manager to be redirect
 *
 * @since 1.20
 *
 * @ingroup Efl_Ui_Focus_Manager
 */
EOAPI void efl_ui_focus_manager_setup_on_first_touch(Eo *obj, Efl_Ui_Focus_Direction direction, Efl_Ui_Focus_Object *entry);

EWAPI extern const Efl_Event_Description _EFL_UI_FOCUS_MANAGER_EVENT_REDIRECT_CHANGED;

/** Emitted when the redirect object has changed, the old manager is passed as
 * event info
 * @return Efl_Ui_Focus_Manager *
 *
 * @since 1.20
 *
 * @ingroup Efl_Ui_Focus_Manager
 */
#define EFL_UI_FOCUS_MANAGER_EVENT_REDIRECT_CHANGED (&(_EFL_UI_FOCUS_MANAGER_EVENT_REDIRECT_CHANGED))

EWAPI extern const Efl_Event_Description _EFL_UI_FOCUS_MANAGER_EVENT_FLUSH_PRE;

/** Emitted once the graph calculationg will be performed
 *
 * @since 1.20
 *
 * @ingroup Efl_Ui_Focus_Manager
 */
#define EFL_UI_FOCUS_MANAGER_EVENT_FLUSH_PRE (&(_EFL_UI_FOCUS_MANAGER_EVENT_FLUSH_PRE))

EWAPI extern const Efl_Event_Description _EFL_UI_FOCUS_MANAGER_EVENT_COORDS_DIRTY;

/** Emitted once the graph is dirty, this means there are potential changes in
 * border_elements you want to know about
 *
 * @since 1.20
 *
 * @ingroup Efl_Ui_Focus_Manager
 */
#define EFL_UI_FOCUS_MANAGER_EVENT_COORDS_DIRTY (&(_EFL_UI_FOCUS_MANAGER_EVENT_COORDS_DIRTY))

EWAPI extern const Efl_Event_Description _EFL_UI_FOCUS_MANAGER_EVENT_FOCUSED;

/** Emitted if the manager has focused an object, the passed focus object is
 * the last focused object
 * @return Efl_Ui_Focus_Object *
 *
 * @since 1.20
 *
 * @ingroup Efl_Ui_Focus_Manager
 */
#define EFL_UI_FOCUS_MANAGER_EVENT_FOCUSED (&(_EFL_UI_FOCUS_MANAGER_EVENT_FOCUSED))

#endif
