#ifndef _EFL_LOOP_EO_H_
#define _EFL_LOOP_EO_H_

#ifndef _EFL_LOOP_EO_CLASS_TYPE
#define _EFL_LOOP_EO_CLASS_TYPE

typedef Eo Efl_Loop;

#endif

#ifndef _EFL_LOOP_EO_TYPES
#define _EFL_LOOP_EO_TYPES

/** EFL loop arguments data structure
 *
 * @ingroup Efl
 */
typedef struct _Efl_Loop_Arguments
{
  const Eina_Array *argv; /**< Array with loop arguments */
  Eina_Bool initialization; /**< Set to @c true when the program should
                             * initialize its internal state. This happen once
                             * per process instance. */
} Efl_Loop_Arguments;


#endif
/**
 * @brief The Efl Main Loop
 *
 * The Efl main loop provides a clean and tiny event loop library with many
 * modules to do lots of convenient things for a programmer, saving time and
 * effort. It's lean and designed to work on anything from embedded systems all
 * the way up to large and powerful multi-cpu workstations. The main loop has a
 * number of primitives you can use.  It serializes these and allows for
 * greater responsiveness without the need for threads (or any other
 * concurrency). However you can provide these if you need to.
 *
 * @ingroup Efl_Loop
 */
#define EFL_LOOP_CLASS efl_loop_class_get()

EWAPI const Efl_Class *efl_loop_class_get(void);

/** Runs a single iteration of the main loop to process everything on the
 * queue.
 *
 * @ingroup Efl_Loop
 */
EOAPI void efl_loop_iterate(Eo *obj);

/**
 * @brief Runs a single iteration of the main loop to process everything on the
 * queue with block/non-blocking status.
 *
 * @param[in] obj The object.
 * @param[in] may_block A flag if the main loop has a possibility of blocking.
 *
 * @return Return from single iteration run
 *
 * @ingroup Efl_Loop
 */
EOAPI int efl_loop_iterate_may_block(Eo *obj, int may_block);

/**
 * @brief Runs the application main loop.
 *
 * @param[in] obj The object.
 *
 * @return Value set by quit()
 *
 * @ingroup Efl_Loop
 */
EOAPI Eina_Value *efl_loop_begin(Eo *obj);

/**
 * @brief Quits the main loop once all the events currently on the queue have
 * been processed.
 *
 * @param[in] obj The object.
 * @param[in] exit_code Returned value by begin()
 *
 * @ingroup Efl_Loop
 */
EOAPI void efl_loop_quit(Eo *obj, Eina_Value exit_code);

/**
 * @brief A future promise that will be resolved from a clean main loop context
 * as soon as possible.
 *
 * This has higher priority, for low priority use @ref efl_loop_idle
 *
 * @param[in] obj The object.
 *
 * @return The future handle.
 *
 * @ingroup Efl_Loop
 */
EOAPI Eina_Future *efl_loop_job(Eo *obj);

/**
 * @brief Slow down the loop execution by forcing sleep for a small period of
 * time every time the loop iterates/loops.
 *
 * @param[in] obj The object.
 * @param[in] amount Time to sleep for each "loop iteration"
 *
 * @ingroup Efl_Loop
 */
EOAPI void efl_loop_throttle_set(Eo *obj, double amount);

/**
 * @brief Slow down the loop execution by forcing sleep for a small period of
 * time every time the loop iterates/loops.
 *
 * @param[in] obj The object.
 *
 * @return Time to sleep for each "loop iteration"
 *
 * @ingroup Efl_Loop
 */
EOAPI double efl_loop_throttle_get(const Eo *obj);

/**
 * @brief The time point when the loop was logically woken.
 *
 * @param[in] obj The object.
 * @param[in] timepoint Time in seconds since process specific start point
 *
 * @ingroup Efl_Loop
 */
EOAPI void efl_loop_time_set(Eo *obj, double timepoint);

/**
 * @brief The time point when the loop was logically woken.
 *
 * @param[in] obj The object.
 *
 * @return Time in seconds since process specific start point
 *
 * @ingroup Efl_Loop
 */
EOAPI double efl_loop_time_get(const Eo *obj);

/**
 * @brief A future promise that will be resolved from a clean main loop context
 * as soon as the main loop is idle.
 *
 * This is a low priority version of @ref efl_loop_job
 *
 * @param[in] obj The object.
 *
 * @return The future handle.
 *
 * @ingroup Efl_Loop
 */
EOAPI Eina_Future *efl_loop_idle(Eo *obj);

/**
 * @brief A future promise that will be resolved from a clean main loop context
 * after @c time seconds.
 *
 * @param[in] obj The object.
 * @param[in] time The time from now in second that the main loop will wait
 * before triggering it.
 *
 * @return The future handle.
 *
 * @ingroup Efl_Loop
 */
EOAPI Eina_Future *efl_loop_timeout(Eo *obj, double time);

/**
 * @brief Will register a manager of a specific class to be answered by
 * eo.provider_find.
 *
 * @param[in] obj The object.
 * @param[in] klass The class provided by the registered provider.
 * @param[in] provider The provider for the newly registered class that has to
 * provide that said Efl.Class.
 *
 * @return @c true if successfully register, @c false otherwise.
 *
 * @ingroup Efl_Loop
 */
EOAPI Eina_Bool efl_loop_register(Eo *obj, const Efl_Class *klass, const Efl_Object *provider);

/**
 * @brief Will unregister a manager of a specific class that was previously
 * registered and answered by eo.provider_find.
 *
 * @param[in] obj The object.
 * @param[in] klass The class provided by the provider to unregister for.
 * @param[in] provider The provider for the registered class to unregister.
 *
 * @return @c true if successfully unregistered, @c false otherwise.
 *
 * @ingroup Efl_Loop
 */
EOAPI Eina_Bool efl_loop_unregister(Eo *obj, const Efl_Class *klass, const Efl_Object *provider);

/**
 * @brief Get a message handler object that is created by and owned by the
 * Efl.Loop object, so you can listen to this message type by listening to
 * message events on the handler as well as send objects as events.
 *
 * @param[in] loop The loop to get the object from.
 * @param[in] klass The class of the message object.
 *
 * @return The message handler to use.
 *
 * @ingroup Efl_Loop
 */
EOAPI Efl_Loop_Message_Handler *efl_loop_message_handler_get(const Eo *obj, Efl_Loop *loop, const Efl_Class *klass);

EWAPI extern const Efl_Event_Description _EFL_LOOP_EVENT_IDLE_ENTER;

/** Event occurs once the main loop enters the idle state.
 *
 * @ingroup Efl_Loop
 */
#define EFL_LOOP_EVENT_IDLE_ENTER (&(_EFL_LOOP_EVENT_IDLE_ENTER))

EWAPI extern const Efl_Event_Description _EFL_LOOP_EVENT_IDLE_EXIT;

/** Event occurs once the main loop exits the idle state.
 *
 * @ingroup Efl_Loop
 */
#define EFL_LOOP_EVENT_IDLE_EXIT (&(_EFL_LOOP_EVENT_IDLE_EXIT))

EWAPI extern const Efl_Event_Description _EFL_LOOP_EVENT_IDLE;

/** Event occurs once the main loop is idle. If you keep listening on this
 * event it may increase the burden on your CPU.
 *
 * @ingroup Efl_Loop
 */
#define EFL_LOOP_EVENT_IDLE (&(_EFL_LOOP_EVENT_IDLE))

EWAPI extern const Efl_Event_Description _EFL_LOOP_EVENT_ARGUMENTS;

/** Event happens when args are provided to the loop by args_add().
 * @return Efl_Loop_Arguments
 *
 * @ingroup Efl_Loop
 */
#define EFL_LOOP_EVENT_ARGUMENTS (&(_EFL_LOOP_EVENT_ARGUMENTS))

EWAPI extern const Efl_Event_Description _EFL_LOOP_EVENT_POLL_HIGH;

/** Event occurs multiple times per second. The exact tick is undefined and can
 * be adjusted system wide.
 *
 * @ingroup Efl_Loop
 */
#define EFL_LOOP_EVENT_POLL_HIGH (&(_EFL_LOOP_EVENT_POLL_HIGH))

EWAPI extern const Efl_Event_Description _EFL_LOOP_EVENT_POLL_MEDIUM;

/** Event occurs multiple times per minute. The exact tick is undefined and can
 * be adjusted system wide.
 *
 * @ingroup Efl_Loop
 */
#define EFL_LOOP_EVENT_POLL_MEDIUM (&(_EFL_LOOP_EVENT_POLL_MEDIUM))

EWAPI extern const Efl_Event_Description _EFL_LOOP_EVENT_POLL_LOW;

/** Event occurs multiple times every 15 minutes. The exact tick is undefined
 * and can be adjusted system wide.
 *
 * @ingroup Efl_Loop
 */
#define EFL_LOOP_EVENT_POLL_LOW (&(_EFL_LOOP_EVENT_POLL_LOW))

EWAPI extern const Efl_Event_Description _EFL_LOOP_EVENT_QUIT;

/** Event occurs when the loop was requested to quit externally e.g. by a
 * ctrl+c signal or a request from a parent loop/thread to have the child exit.
 *
 * @ingroup Efl_Loop
 */
#define EFL_LOOP_EVENT_QUIT (&(_EFL_LOOP_EVENT_QUIT))

#endif
