// ============================================================================
// face_node.h — the UNIVERSAL TRANSLATOR interface.
//
// The substrate does not re-implement any OS's hardware. It TRANSLATES: it
// intercepts the small, documented set of hardware-contract vectors an OS
// already uses (console-out, keyboard, IRQ/timer) and maps them to substrate
// operations. One translator per OS dialect; ONE operator drives them all.
//
// This is universal because translation is per-INTERFACE, not per-machine. An
// OS's hardware contract is a vector table, not silicon:
//   CoCo (Color BASIC Unravelled):  RVEC3 = CONSOLE OUT, KEYBUF, IRQVEC
//   C64:                            $0326 = CHROUT,       $0277 KEYD, IRQ
//   any OS:                         its own equivalent handful of vectors
// You translate the contract, not the chip. The guest never touches metal;
// there is no metal, and no "down" from the boundary (X=0 ⇒ Ω ≡ Fix(T)).
//
//   Ω(n+1) = T(Ω(n))   ·   nothing sent, law shared
//
// This header has ZERO dialect-specific content. C64 is one proven dialect
// (see ../dialects/c64/); it is not privileged by anything in this file.
// ============================================================================
#ifndef HDGL_FACE_NODE_H
#define HDGL_FACE_NODE_H

#include <stdint.h>   // freestanding-safe per the C standard; portable

// Face lifecycle states (same ladder as the Omega graph nodes).
enum FaceState {
  FACE_INIT = 0, FACE_DISCOVERED, FACE_CONFIGURED,
  FACE_READY, FACE_EXECUTED, FACE_COMPLETED
};

// The face's TRANSLATION TABLE for one OS's hardware contract. We do NOT
// re-implement the guest's machine — we translate the small, documented set of
// hardware-contract vectors the OS already uses (its console-out vector, its
// input path, its IRQ/timer hooks) into substrate operations. One translator
// per OS dialect; the operator that calls it (face_operator.c) is universal.
struct FaceBasis {
  // realize/attach the guest and install the vector translation. Fix(project)
  void     (*init)(void* self);
  // advance the guest so it reaches its own hardware-contract vectors, where
  // the translation intercepts. The guest runs its own code; we translate its
  // hardware calls — we do not drive it. (endogenous Δ)
  int      (*step)(void* self, unsigned int quanta);
  // TRANSLATE console-out: observe what the guest emitted through its console
  // vector into a projection surface. read-only — never drives the guest.
  void     (*observe)(void* self, unsigned char* surface, int cols, int rows);
  // TRANSLATE input: deliver an event into the guest's native input contract
  // (its keyboard buffer / device vector), the authentic way.
  void     (*input)(void* self, uint8_t key);
  // TRANSLATE mouse/pointer: deliver relative motion + buttons into the
  // guest's own native pointer contract (whatever that already is for this
  // dialect — a joystick port, a real mouse register, etc; never invented).
  // buttons bit0=left,bit1=right,bit2=middle.
  void     (*mouse)(void* self, int8_t dx, int8_t dy, uint8_t buttons);
  // the guest's own program counter / identity coordinate (Δ, for the graph).
  uint32_t (*coord)(void* self);
};

// Practical, not principled: sized to fit the C64 (and many other 8-bit-era
// text modes). A dialect with a larger text surface needs this widened —
// a mechanical change, not an architectural one. See README's "Honest
// limitations" section.
//
// DEFAULT geometry (the C64-era text mode the first proven dialect used).
// A face that does not set its own cols/rows falls back to this in
// face_realize(). Unchanged, so the c64 and demo dialects are byte-for-byte
// unaffected by the Alpine widening below.
#define FACE_SURFACE_COLS 40
#define FACE_SURFACE_ROWS 25

// CAPACITY of the projection surface array (FaceNode.surface). This is the
// mechanical widening the README's "Honest limitations" sanctions: the array
// must hold the WIDEST dialect's text mode, so a dialect with a bigger console
// (the Alpine face is 80x25) fits without truncation. Each face still projects
// only its OWN cols*rows; a smaller dialect simply uses the first cols*rows
// cells and leaves the rest blank. Nothing here privileges any one geometry.
#define FACE_SURFACE_MAX_COLS 80
#define FACE_SURFACE_MAX_ROWS 25
#define FACE_SURFACE_SIZE (FACE_SURFACE_MAX_COLS*FACE_SURFACE_MAX_ROWS)

#define FACE_SETTLE_WINDOW   64   // == VECTOR_DIM (analogcontainer1/vector_container.h)
#define FACE_CHECKPOINT_RING 4
#define PHI_LATTICE_SLOTS    128  // substrate/phi_lattice.asm -- the real substrate

// Onion-shell checkpoint: three layered φ-hashes (core/dna/combined), using
// face_phi_hash as the hash primitive — this project's own hardened-vector
// hash (Security Guard/engine.txt lineage), not SHA-256. Reversible,
// observation-only.
struct FaceCheckpoint {
  uint64_t op_id;
  uint64_t shell_core;      // hash of the raw observed surface
  uint64_t shell_dna;       // hash of the DNA-encoded genome string
  uint64_t shell_combined;  // hash of (core, dna) combined
};

// A face = a mathematical boundary + its basis + its projection surface.
struct FaceNode {
  const char*      name;
  uint64_t         id;             // phi_hash(name) — context_id
  enum FaceState   state;
  struct FaceBasis basis;          // the projected hardware
  void*            self;           // the face's private machine (behind the wall)
  int              cols, rows;     // projection surface geometry
  unsigned char    surface[FACE_SURFACE_SIZE]; // the observed screen (moiré target)
  int              active;
  char             genome[9];       // Fix(project) as DNA — {A,C,G,T}, 8 symbols
  int              settle_lock;     // set from the REAL phi-lattice consensus (substrate/)
  uint32_t         lattice[PHI_LATTICE_SLOTS]; // the actual substrate: Router64's own phi-lattice
  uint64_t         lattice_tick;    // driven by the observed surface (Δ), never invented
  struct FaceCheckpoint checkpoints[FACE_CHECKPOINT_RING];
  uint32_t         checkpoint_count; // total created (ring wraps mod FACE_CHECKPOINT_RING)
};

// ── the universal operator (the "bootloader") ── see face_operator.c
// realize(): bind the guest to the projection and bring the face to READY.
void face_realize(struct FaceNode* f);
// tick(): observe → settle → project. Called each substrate iteration.
void face_tick(struct FaceNode* f);
// low-latency variants: step a small batch, observe separately (poll input between)
void face_tick_steps(struct FaceNode* f, unsigned int quanta);
void face_tick_observe(struct FaceNode* f);
// key(): deliver an input event to the face's guest (authentic path).
void face_key(struct FaceNode* f, uint8_t key);
// mouse(): deliver a relative-motion + button event to the face's guest
// (authentic path -- same translation-table shape as face_key).
void face_mouse(struct FaceNode* f, int8_t dx, int8_t dy, uint8_t buttons);

// settle(): the REAL substrate. Folds the observed surface into the
// lattice's tick, runs one phi-lattice recursion (substrate/phi_lattice.asm,
// the same asm Router64 boots with), and reads consensus into settle_lock.
// Checkpoints on the UNLOCK->LOCK edge. Called every tick, any face.
void face_settle(struct FaceNode* f);
// checkpoint(): onion-shell layered φ-hash snapshot into the ring buffer.
void face_checkpoint(struct FaceNode* f);
// genome(): the face's Fix-point identity, dna_encode'd into f->genome.
void face_genome(struct FaceNode* f);

// phi-hash used for context_id (φ-fold, no stored constants).
uint64_t face_phi_hash(const char* name);

#endif
