
#ifndef BINDING_H_INCLUDED
#define BINDING_H_INCLUDED

#include <stddef.h>
#include <stdint.h>

#include "kernel.h"
#include "Joystick.h"


// The binding table is the SOURCE OF TRUTH for a slot's mapping; the
// resolved fields the hot decode path reads (mapped_x_16, mapped_buttons[],
// key_*, mouse_*, axes[].invert - see struct joydata_struct) are a COMPILED
// form, expanded from it by binding_compile(). The record layout and
// constants are in Joystick.h; see doc.Bindings for the full model
// (singular vs shareable targets, how Invert interacts with axes[].invert).

// Any bit outside this in a binding's flags is rejected
#define Joystick_Binding_Flag_Known   (Joystick_Binding_Flag_Invert)

// Serialised table header, as stored in the config store
#define Joystick_Binding_Magic    0x50414D4Au   // 'JMAP' little-endian
#define Joystick_Binding_Version  1u

typedef struct {
  uint32_t    magic;      // Joystick_Binding_Magic
  uint16_t    version;    // Joystick_Binding_Version
  uint16_t    count;      // number of valid entries following
  joystick_binding entries[1]; // [count] - flexible tail
} joystick_binding_map;


// Validate a whole incoming table against a slot's real capabilities BEFORE it
// touches live state: header sanity, per-record range checks (indexed by the
// device's actual num_axes/num_buttons), reserved/flag hygiene, and the
// singular-target overlap rule. Returns NULL if clean, else an error and the
// live mapping is left untouched. count is the number of entries in entries[].
_kernel_oserror *binding_validate(uint32_t slot, const joystick_binding *entries, uint32_t count);

// Validate one candidate binding against the slot's CURRENT table (range +
// the singular-target rule vs. what's already bound). Backs *USBJoystick_Map /
// Joystick_AddBinding. Returns NULL if it may be added.
_kernel_oserror *binding_validate_one(uint32_t slot, const joystick_binding *b);

// Expand the slot's stored binding table into the resolved fields the decode
// path reads (clears them first). Called after any table change. Never fails -
// the table was validated on the way in.
void binding_compile(uint32_t slot);

// The inverse: rebuild the binding table FROM the current resolved fields, so a
// mapping produced the old way (auto_map / config overlay) is visible through
// Joystick_ReadBindings. Does not recompile.
void binding_capture(uint32_t slot);

// Replace the slot's table wholesale: validate, copy in, compile. (Set path.)
_kernel_oserror *binding_write(uint32_t slot, const joystick_binding *entries, uint32_t count);

// Append one binding to the slot's table: validate against current, add,
// compile.
_kernel_oserror *binding_add(uint32_t slot, const joystick_binding *b);

// Drop bindings from the slot's table and recompile. If src_type < 0, clears
// the whole table; otherwise clears just entries for that one source.
void binding_clear(uint32_t slot, int32_t src_type, int32_t src_index);

// Drop just the binding(s) matching *match on source AND target (kind+index),
// and recompile. Used to remove one specific input->output binding.
void binding_remove(uint32_t slot, const joystick_binding *match);


// SWI wrappers (register calling convention) - see h.joyswis for numbers.
_kernel_oserror *swi_joystick_read_bindings(_kernel_swi_regs *r);
_kernel_oserror *swi_joystick_write_bindings(_kernel_swi_regs *r);
_kernel_oserror *swi_joystick_add_binding(_kernel_swi_regs *r);
_kernel_oserror *swi_joystick_read_default_bindings(_kernel_swi_regs *r);

// *USBJoystick_* command wrappers (string args)
_kernel_oserror *command_map(const char *args, int32_t argc);
_kernel_oserror *command_unmap(const char *args, int32_t argc);
_kernel_oserror *command_mappings(const char *args, int32_t argc);

// Shared text<->binding helpers (c.cmdbind), reused by the config store so its
// bind= lines use the exact *USBJoystick_Map grammar. parse_spec modifies the
// token buffers in place (NUL at the ':'); the formatters emit canonical tokens.
_kernel_oserror *binding_parse_spec(uint32_t slot, char *src_tok, char *tgt_tok,
                                    int invert, joystick_binding *b);
void binding_format_source(const joystick_binding *b, uint32_t slot, char *buf, size_t buflen);
void binding_format_target(const joystick_binding *b, char *buf, size_t buflen);

#endif
