// Replaces built-in behavior of console.uselect()
// for RIP/RIPScrip terminals on Synchronet v3.21+
// Set SCFG->System->Loadable Modules->Select Item to "uselect_rip"
// with access requirements set to RIP
// This script was initially generated by Claude AI.

"use strict";

require("sbbsdefs.js", "K_NOCRLF");
require("rip_lib.js", "RIPWindow");
require("rip_lightbar_menu.js", "RIPLightbarMenu");

if (!console.term_supports(USER_RIP))
{
    console.print("\x01n\x01y\x01hYour terminal doesn't support RIP\x01n\r\n");
    console.pause();
    exit(-1);
}

js.on_exit('console.attributes = ' + console.attributes);
js.on_exit('bbs.sys_status = ' + bbs.sys_status);

bbs.sys_status |= SS_MOFF;

var dflt = Number(argv[0]);
var items = console.uselect_items;
var header = format(bbs.text(bbs.text.SelectItemHdr), console.uselect_title);

// Send a batch of RIP commands to the client.
// Uses \r (CR) before ! instead of \r\n (CRLF) to avoid advancing the text
// cursor to a new line, which would scroll the text window. The \r returns
// to column 0 so ! is recognized as the start of a RIP command line.
// Always parks the text cursor at (0,0) after each batch to prevent cursor
// drift from the trailing \r\n that terminates the RIP line.
function sendRIP(cmds)
{
	//console.write("\r!" + cmds + RIPGotoXYNumeric(0, 0) + "\r\n");
	console.write("\r!" + cmds + "\r\n");
}

// Displays a RIP header at the top of the screen
function RIPHdr(pText, pRIPFont, pFontSize, pTextColorNum, pInnerBorderColorNum, pOuterEdgeColorNum, pBkgColorNum)
{
	var fontNum = (typeof(pRIPFont) === "number" && pRIPFont >= RIP_FONT_DEFAULT && pRIPFont <= RIP_FONT_BOLD ? pRIPFont : RIP_FONT_TRIPLEX);
	var fontSize = (typeof(pFontSize) === "number" ? pFontSize : 5);
	var textColorNum = (typeof(pTextColorNum) === "number" ? pTextColorNum : 1);
	var innerBorderColorNum = (typeof(pInnerBorderColorNum) === "number" ? pInnerBorderColorNum : 15);
	var outerEdgeColorNum = (typeof(pOuterEdgeColorNum) === "number" ? pOuterEdgeColorNum : 8);
	var bkgColorNum = (typeof(pBkgColorNum) === "number" ? pBkgColorNum : 7);

	var btnFlags = RIP_BTN_STYLE_CHISEL_EFFECT|RIP_BTN_STYLE_DROPSHADOW_LBL|RIP_BTN_STYLE_BEVEL|RIP_BTN_STYLE_SUNKEN;

	var rip = RIPKillMouseFields();
	rip += RIPFontStyleNumeric(fontNum, 0, fontSize, 0);
	rip += RIPWriteMode(0);
	rip += RIPButtonStyleNumeric(640, 40, 2, btnFlags, 5, textColorNum, 0, innerBorderColorNum,
								 outerEdgeColorNum, bkgColorNum, 1, 0, 0, 0, 0);
	rip += RIPButtonNumeric(0, 0, 640, 60, 0, 0, 0, [pText], "");
	return rip;
}

// --- Initial screen setup ---
// Avoid RIPResetWindows() — it calls reinit_screen() in SyncTerm, which tears
// down and recreates the entire terminal emulator instance (cterm_end/cterm_init,
// vmem realloc, pixel buffer save/restore). Every RIPWindow command also triggers
// reinit_screen() due to a bug in the early-return check (compares font size
// INDEX against pixel WIDTH, so it never matches). By not changing the text
// window font at all, we avoid all reinit_screen() calls and eliminate the
// post-exit input delay. RIP graphical commands use pixel coordinates (640x350)
// independent of the text window font, so the menu renders identically.
sendRIP(RIPKillMouseFields()
        + RIPFillStyleNumeric(1, RIP_COLOR_BLACK)
        + RIPBarNumeric(0, 0, 639, 349)
        + RIPNoMore());

// Draw the header at the top of the screen.
// Strip Ctrl-A codes from the header text since they don't display well with RIP.
var cleanHeader = strip_ctrl(header);
var hdrRIP = RIPHdr(cleanHeader, RIP_FONT_TRIPLEX, 5, RIP_COLOR_BLUE);
sendRIP(hdrRIP);

// --- Create the lightbar menu ---
var MENU_X = 15;
var MENU_Y = 64;
var MENU_WIDTH = 611;   // 625 - 15 + 1
var MENU_HEIGHT = 286;  // 350 - 64
var menu = new RIPLightbarMenu(MENU_X, MENU_Y, MENU_WIDTH, MENU_HEIGHT, true);

// Add items with hotkey prefixes
for (var i = 0; i < items.length; ++i)
{
	var text, hotkey;
	if (items.length <= 15)
	{
		text = format("%X %s", i + 1, items[i].name);
		hotkey = format("%X", i + 1);
	}
	else if (items.length <= 26)
	{
		text = format("%c %s", ascii('A') + i, items[i].name);
		hotkey = String.fromCharCode(ascii('A') + i);
	}
	else
	{
		text = items[i].name;
		hotkey = null;
	}
	menu.Add(text, items[i].num, hotkey);
}

// Get the user's selection
var retval = menu.GetVal(dflt);
if (retval === null)
	retval = -1;

// --- Exit cleanup ---
// No RIPWindow command on exit. Since we never changed the text window font
// on startup (avoided RIPResetWindows), the calling shell's font is still
// intact and no restoration is needed. This avoids triggering SyncTerm's
// reinit_screen() which is the primary cause of the post-exit input delay.

// console.write() (rputs) sends raw bytes through Synchronet's output path which
// updates internal terminal tracking state (column, row, lastcrcol) via
// parse_output(), but rputs only saves/restores lncntr — not the rest.
// Reset all tracking state to prevent stale values from affecting the calling
// shell (e.g., a non-zero lastcrcol would cause lncntr to accumulate on every
// newline, potentially triggering an unwanted "more?" pause).
console.line_counter = 0;
console.last_line_length = 0;
console.current_column = 0;

exit(retval);
