// Surface type and allocation.
//
// All surfaces are 320x200 16-color images. In-memory storage is
// target-native: chunky 4bpp packed (two pixels per byte, high nibble
// is the left pixel) on IIgs and DOS; native planar (4 separate
// bitplanes on Amiga, word-interleaved planes on Atari ST) on the
// 68k ports. Public API entry points speak in color indices (0..15)
// regardless, so game code does not see the storage format.
//
// Each surface carries its own 200-entry SCB (scanline control byte)
// table and a 16-by-16 $0RGB palette set. See docs/DESIGN.md section 6.

#ifndef JOEYLIB_SURFACE_H
#define JOEYLIB_SURFACE_H

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

// ----- Fixed surface dimensions (library contract) -----

#define SURFACE_WIDTH               320
#define SURFACE_HEIGHT              200
#define SURFACE_BYTES_PER_ROW       160
#define SURFACE_PIXELS_SIZE         (SURFACE_BYTES_PER_ROW * SURFACE_HEIGHT)

#define SURFACE_PALETTE_COUNT       16
#define SURFACE_COLORS_PER_PALETTE  16
#define SURFACE_PALETTE_ENTRIES     (SURFACE_PALETTE_COUNT * SURFACE_COLORS_PER_PALETTE)

// ----- Opaque public type -----

typedef struct jlSurfaceT jlSurfaceT;

// Allocate a new offscreen surface. Returns NULL on failure (jlLastError
// describes the reason).
jlSurfaceT *jlSurfaceCreate(void);

// Release an offscreen surface previously returned by jlSurfaceCreate.
// Passing NULL is a no-op. Passing the stage is a no-op.
void jlSurfaceDestroy(jlSurfaceT *s);

// The library-owned stage: the back-buffer surface that jlStagePresent
// flips to the display. Always valid between jlInit and jlShutdown.
// On IIgs the stage's pixel buffer is pinned to bank $01 SHR space with
// shadow inhibited so writes are full-speed (2.8 MHz) and isolated from
// the displayed framebuffer until the next jlStagePresent.
jlSurfaceT *jlStageGet(void);

// Copy pixels, SCBs, and palettes from src into dst. Both must be valid
// surfaces.
void jlSurfaceCopy(jlSurfaceT *dst, const jlSurfaceT *src);

// Copy a pixel rectangle from src into dst at the SAME position (no
// repositioning, so planar ports never shift bits). The rect is
// clipped to the surface, then widened OUTWARD to the 16-pixel group
// grid ON EVERY PORT -- the copied window is x rounded down and
// x + w rounded up to multiples of 16 (same window rule as
// jlSpriteSaveUnder), so up to 15 extra pixels on each side are
// copied. Two consequences the caller owns: a snapped erase can
// clobber on-screen content up to 15 px outside the requested rect,
// and it silently invalidates any live jlSpriteBackupT whose
// recorded window it touches. Copies pixels only: SCBs and palettes
// are untouched. The intended use is restoring background
// rectangles from a pristine copy of the scene (the clean-buffer
// pattern) instead of per-sprite save/restore -- erase ALL windows,
// then redraw ALL sprites; do not mix with backup-restore in the
// same region.
void jlSurfaceCopyRect(jlSurfaceT *dst, const jlSurfaceT *src, int16_t x, int16_t y, uint16_t w, uint16_t h);

// Persist a surface to disk in target-native form: 32000 bytes of
// pixels followed by 200 bytes of SCB followed by 512 bytes of $0RGB
// palette table (16 palettes x 16 colors, native uint16_t). Returns
// false if the file can't be opened or the write fails. The same
// platform that wrote the file must read it -- no endianness
// conversion is performed.
bool jlSurfaceSaveFile(const jlSurfaceT *src, const char *path);

// Read a surface from disk, overwriting dst. Returns false if the
// file is missing, the wrong size, or the read fails. dst keeps its
// identity (no reallocation).
bool jlSurfaceLoadFile(jlSurfaceT *dst, const char *path);

// 32-bit content hash of the surface. NOT FNV-1a: a two-stream 16-bit
// multiplicative hash -- per input byte b, lo = lo * 31 + b and
// hi = hi * 251 + b (mod 2^16), seeded lo = 0xACE1 / hi = 0x1357, and
// combined as (hi << 16) | lo. The hashed domain, in order:
//   1. the packed chunky pixel byte stream (32000 bytes, two 4-bit
//      pixels per byte, high nibble = left pixel, row-major),
//   2. the 200 SCB bytes,
//   3. the 256 palette uint16 entries, each folded high byte then
//      low byte.
// SURFACE_HASH_MIX_BYTE in src/core/surfaceInternal.h is the single
// source of truth for the per-byte mix; a port override (the planar
// Amiga/ST readers) must reuse it byte-for-byte and feed the identical
// byte sequence, so the same logical pixels produce the same hash on
// every port regardless of internal storage format. Used by the UBER
// validation harness to pixel-compare ports against an IIgs golden
// reference.
uint32_t jlSurfaceHash(const jlSurfaceT *s);

#endif
