// JoeyLib new-port template ("jBlank").
//
// Copy this directory to src/<yourplatform>/, set JOEYLIB_PLATFORM_<YOURS> in
// include/joey/platform.h (mirror the JOEYLIB_PLATFORM_BLANK blocks there), and
// fill in the TODOs below. Build with -DJOEYLIB_PLATFORM_<YOURS>.
//
// HOW THE PORT MODEL WORKS
// -----------------------
// JoeyLib's public API (jlDrawPixel, jlFillRect, jlSpriteDraw, ...) is
// implemented ONCE in src/core/*.c. Each overridable operation is a jlp<Op>()
// resolved at COMPILE TIME: a portable-C default lives in src/generic/ and your
// port supplies its own version ONLY when it defines JL_HAS_<OP> in platform.h.
// There is no runtime dispatch.
//
// The payoff for a new port: you get ALL of the graphics for free. The generic
// backend (src/generic/genericDraw|Tile|Sprite|Surface.c) is a complete chunky
// 4bpp software renderer -- draw primitives, tiles, sprites, surface readers,
// allocation. A new CHUNKY port renders correctly before you write a single
// line of graphics code. You only have to implement the platform SERVICES below
// (whose generics are no-op stubs): bring up the display, blit the stage to it,
// read input, and report timing. Wire up audio whenever you like.
//
// To ACCELERATE a specific op later (e.g. a hardware blit for fillRect), add
// JL_HAS_FILL_RECT to your platform.h block and a jlpFillRect() here; the core
// will call yours instead of the generic. Nothing else changes.

#include "port.h"
#include "surfaceInternal.h"   // jlSurfaceT: ->pixels (chunky), ->scb, ->palette
#include "inputInternal.h"     // gKeyState[] etc. for jlpInputPoll


// ----- Lifecycle -----------------------------------------------------------

// Called once from jlInit after config is stored, before any surfaces exist.
// Bring up your video mode and allocate any hardware-adjacent buffers. Return
// true on success (false aborts jlInit). jlpLastError may be set on failure.
bool jlpInit(const jlConfigT *config) {
    (void)config;
    // TODO: program your display into a 320x200, 16-colors-per-scanline mode
    //       (or the closest your hardware offers) and prepare to present.
    return true;
}


// Called from jlShutdown. Undo jlpInit: restore the prior video mode and free
// whatever you allocated.
void jlpShutdown(void) {
    // TODO: restore the display.
}


// ----- Present -------------------------------------------------------------

// Copy the library-owned stage surface to the visible display. This is the one
// service every port MUST get right. The stage is chunky 4bpp:
//   src->pixels  : SURFACE_PIXELS_SIZE bytes, 2 pixels per byte (high nibble is
//                  the LEFT pixel), SURFACE_BYTES_PER_ROW per scanline.
//   src->scb[y]  : palette index 0..15 selecting which of the 16 palettes row
//                  y uses (SCB = scanline control byte).
//   src->palette[p][c] : 16 palettes x 16 colors, each a $0RGB 4-bit-channel
//                  value. Expand to your hardware's color depth.
// jlStagePresent has already walked the per-row dirty bands; for a first cut
// just blit the whole frame, then optimize to dirty rows later (see the dirty
// arrays in surfaceInternal.h).
void jlpPresent(const jlSurfaceT *src) {
    (void)src;
    // TODO: for each scanline y, look up src->scb[y] to pick the palette, then
    //       expand src->pixels nibbles -> your framebuffer pixels.
}


// ----- Input ---------------------------------------------------------------

// Set up your keyboard/joystick at the end of jlInit.
void jlpInputInit(void) {
    // TODO: install / enable your input hardware.
}


// Tear input down (from jlShutdown, before jlpShutdown).
void jlpInputShutdown(void) {
    // TODO: restore input hardware.
}


// Refresh the core-owned key-state array each frame. Write true into
// gKeyState[key] for every currently-held key (see joey/input.h for the jlKeyE
// codes); keys you can't map simply stay false. The cross-platform jlInputPoll
// and joystick code build on this.
//
// Typed characters (jlInputGetChar) are a second, independent path: pass each
// OS/firmware-translated ASCII byte (shift and layout already applied) to
// jlInputCharPush. The core filters to the documented set, so pushing every
// translated byte is fine. If your keyboard handling runs at interrupt time,
// buffer the bytes in your own volatile ring and drain it here instead --
// jlInputCharPush is not interrupt-safe (see the DOS and ST ports).
void jlpInputPoll(void) {
    // TODO: read your keyboard and set gKeyState[...] = true for held keys.
    // TODO: feed translated characters to jlInputCharPush(ch).
}


// Clear any auto-disconnect / calibration state for a joystick and arm a fresh
// center capture on the next poll. Digital-stick ports can leave this empty.
void jlpJoystickReset(jlJoystickE js) {
    (void)js;
    // TODO (analog sticks only): reset calibration for js.
}


// ----- Timing --------------------------------------------------------------

// Block until the next display vertical blank (frame pacing).
void jlpWaitVBL(void) {
    // TODO: spin/sleep until the next vblank.
}


// A monotonic 16-bit frame/refresh counter. Either edge-detect a vblank flag
// inside this call or return a counter maintained by a vblank interrupt. Used
// for animation cadence and the generic millisElapsed (frameCount*1000/frameHz).
uint16_t jlpFrameCount(void) {
    // TODO: return your running frame count.
    return 0u;
}


// Nominal display refresh rate in Hz (50 PAL, 60 NTSC, 70 VGA, ...). Reported
// only; the generic millisElapsed divides by it.
uint16_t jlpFrameHz(void) {
    // TODO: return your real refresh rate.
    return 60u;
}


// ----- Audio (optional) ----------------------------------------------------
//
// Left entirely to the no-op generics: your port links and runs SILENT until
// you wire up sound. When you do, add JL_HAS_AUDIO_<OP> to your platform.h
// block and implement the matching jlpAudio<Op>() here (see src/<port>/audio.c
// in the shipping ports for the full op set: Init/Shutdown, PlayMod/StopMod/
// IsPlayingMod, PlaySfx/PlaySfxStream/StopSfx, Tone/Voice, TickRegister,
// CriticalEnter/Exit, FrameTick).
