/**
 * @file input.h
 * @brief Declares the input backend: where GET and GETKEY read from.
 *
 * Same reasoning as graphics.h and audio.h. The libakgl implementation is
 * akgl_controller_poll_key(), which drains a keystroke ring the library fills
 * from SDL events the *host* pumps -- so the interpreter answers "is there a key
 * waiting" without owning the event loop, which is what goal 3 requires.
 *
 * One thing an embedding host should know: that ring is process-global and the
 * host's own control maps read the same events. An interpreter sitting in a
 * GET loop drains keystrokes the game will then never see. A host that cares
 * either withholds the input backend or supplies a filtered one of its own.
 */

#ifndef _AKBASIC_INPUT_H_
#define _AKBASIC_INPUT_H_

#include <akerror.h>

#include <akbasic/types.h>

/**
 * @brief Where the console input verbs read.
 */
typedef struct akbasic_InputBackend
{
    void *self;

    /**
     * Take the next buffered keystroke without waiting for one.
     *
     * An empty buffer is success with `*available` false, never an error: GET on
     * an empty buffer yields the empty string, which is ordinary BASIC and
     * happens on most iterations of any GET loop.
     */
    akerr_ErrorContext AKERR_NOIGNORE *(*poll_key)(struct akbasic_InputBackend *self, int *keycode, bool *available);
    /** Discard everything buffered. */
    akerr_ErrorContext AKERR_NOIGNORE *(*flush_keys)(struct akbasic_InputBackend *self);
} akbasic_InputBackend;

/**
 * @brief The console input verbs' state, which lives on the runtime.
 *
 * `waiting` is what makes GETKEY work without blocking. On a C128, GETKEY sits
 * on the keyboard until somebody types; section 1.6 forbids that, so instead the
 * verb sets this and akbasic_runtime_step() declines to advance the program
 * until a key turns up. A host keeps its frame rate, a bounded
 * akbasic_runtime_run() still returns, and the program still does not move past
 * the GETKEY -- which is the part the program author cares about.
 */
typedef struct
{
    bool waiting;		/* a GETKEY is holding the program			*/
    char variable[64];		/* the variable it will assign the key to		*/
    bool numeric;		/* true when that variable takes a code, not a letter	*/
} akbasic_InputState;

/* --- Internal API: exposed for the step loop and the tests. --- */

struct akbasic_Runtime;

/**
 * @brief Answer whether a GETKEY is still holding, assigning the key if one came.
 *
 * Called from akbasic_runtime_step() before it executes anything. While
 * `*blocked` comes back true the step does nothing at all, so the program stays
 * exactly where the GETKEY left it.
 *
 * Taking the input device away while a GETKEY is holding releases the hold
 * rather than wedging the script forever -- a host is allowed to change its mind
 * about what it lends out.
 *
 * @param obj Object to initialize, inspect, or modify.
 * @param blocked Output destination populated by the function; true while a GETKEY is unsatisfied.
 * @return `NULL` on success, otherwise an error context owned by the caller.
 * @throws AKERR_NULLPOINTER When either argument is NULL.
 * @throws AKBASIC_ERR_UNDEFINED When the variable the GETKEY named has gone out of scope.
 */
akerr_ErrorContext AKERR_NOIGNORE *akbasic_input_service(struct akbasic_Runtime *obj, bool *blocked);

#endif // _AKBASIC_INPUT_H_
