#ifndef CONFIG_H_INCLUDED
#define CONFIG_H_INCLUDED

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

#include "kernel.h"

// The settings load/save subsystem: a per-device binding table persisted to a
// text config file, keyed by a device fingerprint. See doc.Config for the file
// format, location, fingerprinting tiers and boot-time loading.


// Longest fingerprint string, including the terminating NUL:
//   "vvvv:pppp:serial=" (17) + serial (up to USB_MAX_STRING_LEN, 128) + NUL
#define CONFIG_FINGERPRINT_MAX 160


// Config-store location. The directory name is deliberately a single point
// of change (see doc.Config, "The USBJoystick vs Joysticks dir name") - if
// a shared cross-module convention is ever agreed, only this changes.
// Reads go through the Choices: path (which searches Choices$Path); writes go
// to <Choices$Write>.<dir>.
#define CONFIG_DIR       "USBJoystick"
#define CONFIG_LEAFNAME  "Devices"
#define CONFIG_READ_PATH "Choices:" CONFIG_DIR "." CONFIG_LEAFNAME

// Config-file format version, written in the header ("Format:N") and checked
// on read. The reader ignores any file whose version isn't this (falling back
// to auto-mapping) and the writer replaces an older-version file rather than
// merging into it, so bumping this cleanly retires incompatible files.
#define CONFIG_FORMAT_VERSION 2


// Produce the config-store key for a device slot into buf (buflen bytes,
// must be at least CONFIG_FINGERPRINT_MAX):
//   Tier 1 (device has a real USB serial):  "vvvv:pppp:serial=<serial>"
//   Tier 2 (no serial):                     "vvvv:pppp"
// vvvv/pppp are lower-case 4-hex-digit vendor/product ids. Any character
// in the serial that would break a [section] header line (<= ' ', or one
// of []; =) is replaced with '_' - see doc.Config, "Device fingerprint".
//
// Returns NULL on success, or an error if the slot is out of range, not
// an active joystick, or buf is too small.
_kernel_oserror *config_fingerprint(uint32_t slot, char *buf, size_t buflen);


// Consult the config store for one slot: if its fingerprint section exists,
// replace the slot's binding table with the saved bindings (and stick number).
// A missing file, a wrong-version file, or a missing/empty section all leave
// the slot on its auto-mapping - none is an error. Best-effort: a malformed
// value is logged and skipped, never fatal to a device attach. Safe to call
// repeatedly. See doc.Config.
void config_apply(uint32_t slot);


// Save slot's current binding table to the config store: read the existing
// file (if any, and of the current format), replace this device's fingerprint
// section with a fresh one while preserving every other section and [global],
// and write the whole file to <Choices$Write>.<dir>.<leaf>. Returns an error
// if Choices$Write isn't set or the write fails.
_kernel_oserror *config_save_mapping(uint32_t slot);

// Drop slot's saved section from the config store (so it reverts to the
// default, auto-generated mapping), then re-run auto_map() live so the change
// shows immediately.
_kernel_oserror *config_revert_to_default_map(uint32_t slot);

// Re-read the config store and apply it to every currently-attached slot. The
// boot-time hook and JoySetup's refresh both call this (Joystick_ReloadConfig).
// To clear a saved mapping use config_revert_to_default_map.
void config_reload_all(void);

// Persist the module-wide [global] settings (the Emulate + Control gates)
// without touching any device's own section - see h.joyswis
// (Joystick_SaveSettings). Independent of config_save_mapping.
_kernel_oserror *config_save_global(void);


// SWI wrappers (register calling convention) - see h.joyswis for numbers.
_kernel_oserror *swi_joystick_save_mapping(_kernel_swi_regs *r);
_kernel_oserror *swi_joystick_revert_to_default_map(_kernel_swi_regs *r);
_kernel_oserror *swi_joystick_reload_config(_kernel_swi_regs *r);
_kernel_oserror *swi_joystick_save_global(_kernel_swi_regs *r);

// *USBJoystick_* command wrappers (string args)
_kernel_oserror *command_save_mapping(const char *args, int32_t argc);
_kernel_oserror *command_revert_to_default_map(const char *args, int32_t argc);
_kernel_oserror *command_reload_config(const char *args, int32_t argc);
_kernel_oserror *command_save_settings(const char *args, int32_t argc);

// *USBJoystick_Fingerprint <slot> - print the config-store fingerprint key for
// one slot (a diagnostic aid).
_kernel_oserror *command_fingerprint(const char *args, int32_t argc);


#endif
