// Keyboard, mouse, and joystick input polling.
//
// Call jlInputPoll() once per frame (typically right before
// drawing) to refresh keyboard, mouse, and joystick state. After
// polling, the joeyKey* predicates return the current state of every
// key:
//
//   jlKeyDown(k)     -- is key k held down right now
//   jlKeyPressed(k)  -- rising edge since the previous poll
//   jlKeyReleased(k) -- falling edge since the previous poll
//
// Typed-character input (text entry) is a separate path:
//
//   jlInputGetChar() -- pop the next typed character, or -1
//
// The key predicates are the right shape for games (is the fire key
// held?); the character queue is the right shape for text fields
// (which character did the user type, with shift and the machine's
// keyboard layout already applied). Both are refreshed by the same
// jlInputPoll() and coexist freely.
//
// The mouse predicates return the pointer state:
//
//   jlMouseX/Y()                -- pointer position in surface
//                                    coords (0..SURFACE_WIDTH-1,
//                                    0..SURFACE_HEIGHT-1)
//   jlMouseDown(b)              -- is button b held right now
//   jlMousePressed(b)           -- rising edge since last poll
//   jlMouseReleased(b)          -- falling edge since last poll
//
// The joystick predicates return per-stick state:
//
//   jlJoystickConnected(js)     -- true if the platform reports a
//                                    stick on this port
//   jlJoystickX/Y(js)           -- axis values, signed -127..+127.
//                                    Digital sticks snap to the
//                                    extremes; analog sticks return
//                                    the raw centered value.
//   jlJoyDown(js, b)            -- is button b held on stick js
//   jlJoyPressed(js, b)         -- rising edge since last poll
//   jlJoyReleased(js, b)        -- falling edge since last poll
//
// Edge predicates are one-shot: they return true only in the
// frame the transition occurred and false thereafter.

#ifndef JOEYLIB_INPUT_H
#define JOEYLIB_INPUT_H

#include "platform.h"
#include "types.h"

typedef enum {
    KEY_NONE = 0,

    KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H, KEY_I,
    KEY_J, KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R,
    KEY_S, KEY_T, KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z,

    KEY_0, KEY_1, KEY_2, KEY_3, KEY_4,
    KEY_5, KEY_6, KEY_7, KEY_8, KEY_9,

    KEY_SPACE, KEY_ESCAPE, KEY_RETURN, KEY_TAB, KEY_BACKSPACE,

    KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT,

    KEY_LSHIFT, KEY_RSHIFT, KEY_LCTRL, KEY_LALT,

    KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5,
    KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10,

    KEY_COUNT
} jlKeyE;

typedef enum {
    MOUSE_BUTTON_NONE   = 0,
    MOUSE_BUTTON_LEFT,
    MOUSE_BUTTON_RIGHT,
    MOUSE_BUTTON_MIDDLE,

    MOUSE_BUTTON_COUNT
} jlMouseButtonE;

typedef enum {
    JOYSTICK_0 = 0,
    JOYSTICK_1,

    JOYSTICK_COUNT
} jlJoystickE;

typedef enum {
    JOY_BUTTON_0 = 0,
    JOY_BUTTON_1,

    JOY_BUTTON_COUNT
} jlJoyButtonE;

#define JOYSTICK_AXIS_MAX   127
#define JOYSTICK_AXIS_MIN   (-127)

// Control characters delivered through jlInputGetChar alongside
// printable ASCII. Everything else below 0x20, plus 0x7F, is
// filtered out of the queue.
#define JL_CHAR_BACKSPACE   0x08
#define JL_CHAR_TAB         0x09
#define JL_CHAR_RETURN      0x0D
#define JL_CHAR_ESCAPE      0x1B

// Typed-character queue capacity (ring buffer; one slot stays empty,
// so JL_CHAR_QUEUE_SIZE - 1 characters can be pending). Must be a
// power of two.
#define JL_CHAR_QUEUE_SIZE  32

void jlInputPoll(void);

// Pop the next typed character as a 7-bit code, or -1 if the queue
// is empty. Codes: printable ASCII 0x20..0x7E, plus JL_CHAR_BACKSPACE,
// JL_CHAR_TAB, JL_CHAR_RETURN, JL_CHAR_ESCAPE. Shift, caps lock, and
// the keyboard layout are already applied by the backend, so
// punctuation and shifted symbols arrive correctly on every port.
// (The layout is the machine's own on IIgs/Amiga/ST/X68000; the DOS
// port translates with a fixed US layout -- see docs/input.md.)
//
// The queue is refilled by jlInputPoll() -- no extra bring-up is
// needed. It holds JL_CHAR_QUEUE_SIZE - 1 characters; when full,
// further characters are dropped (drop-newest) until the app pops.
// OS auto-repeat may deliver repeated characters on ports whose
// keyboard services repeat (the caller manages repeat policy).
// 7-bit ASCII only; no Unicode / IME. Arrow keys are not characters
// and stay on the predicate API (jlKeyDown(KEY_UP) etc.).
// jlWaitForAnyKey empties the queue when it returns -- its dismissing
// keystroke is consumed by the wait, not delivered as text.
//
// Returns int (not a stdint type) deliberately: getchar()-style
// "byte or -1" is the interface contract consumers expect.
int jlInputGetChar(void);

// Block until the user presses any key. Internally polls via
// jlInputPoll, so per-port jlpInputPoll machinery (including
// audio-friendly IRQ-driven samplers) keeps working while the
// wait loop runs.
void jlWaitForAnyKey(void);

bool jlKeyDown(jlKeyE key);
bool jlKeyPressed(jlKeyE key);
bool jlKeyReleased(jlKeyE key);

// True when the platform confirmed an attached mouse at init (DOS: the INT 33h driver reset;
// Amiga/ST/IIgs/X68000: the OS mouse is always wired).
bool    jlMousePresent(void);
int16_t jlMouseX(void);
int16_t jlMouseY(void);
bool    jlMouseDown(jlMouseButtonE button);
bool    jlMousePressed(jlMouseButtonE button);
bool    jlMouseReleased(jlMouseButtonE button);

bool   jlJoystickConnected(jlJoystickE js);
int8_t jlJoystickX(jlJoystickE js);
int8_t jlJoystickY(jlJoystickE js);
bool   jlJoyDown(jlJoystickE js, jlJoyButtonE button);
bool   jlJoyPressed(jlJoystickE js, jlJoyButtonE button);
bool   jlJoyReleased(jlJoystickE js, jlJoyButtonE button);

// Re-enable joystick polling and recalibrate the resting (center)
// position. The IIgs port auto-disables polling after a short window
// of detecting no stick (saves ~3 ms/frame of busy-wait). It does NOT
// auto-re-probe -- the application must call this function to resume
// polling after plugging a stick in.
//
// The next poll after this call captures the stick's CURRENT raw
// position as the new center -- so the user must hold the stick
// centered when calling. Subsequent polls report position relative
// to that center; raw readings within `deadZone` units of the center
// clamp to 0 (use 0 to disable the dead zone).
//
// On platforms with truly digital sticks (Amiga / ST / DOS) the
// recalibration is a no-op -- those ports already report -1 / 0 / +1
// directly -- and `deadZone` is ignored. The function still clears
// any auto-disconnect state so polling resumes.
void jlJoystickReset(jlJoystickE js, uint8_t deadZone);

#endif
