#pragma once

#include "..\munga\style.h"

//########################################################################
//############################ MFDSplitView ##############################
//########################################################################
//
// One desktop window showing a single cockpit display, used by SVGA16's
// split mode (L4MFDSPLIT=1). The pod hardware packed the five monochrome
// MFDs into the color channels of two video outputs and mounted the map
// display rotated; on a desktop each display gets its own window instead.
//
// Each window also carries its display's physical button bank, exactly
// as mounted in the pod (geometry per vRIO's CockpitLayout):
//   - MFDs: a 4x2 cluster - 4 red buttons above the glass, 4 below,
//     RIO addresses descending from the cluster anchor (top-left = hi).
//   - The map ("secondary screen"): 6 amber buttons down each side -
//     Secondary 0x10-0x15 on the left, Screen 0x18-0x1D on the right
//     (the remaining column addresses are Tesla relays, not buttons).
// Buttons light from the lamp state the game commands (via PadRIO) and
// press/release RIO units with the mouse.
//
// SVGA16 fills Pixels() (32bpp top-down, sourceWidth x sourceHeight as
// passed - already swapped by the caller for the rotated map) and calls
// Repaint(). Closing a view window just hides it.
//
class MFDSplitView
{
public:
	enum ButtonStyle
	{
		NoButtons = 0,
		MFDStrips,			// 4 above + 4 below, addresses descend from anchorA
		SideColumns			// 6 per side; anchorA = left base, anchorB = right base
	};

	// With a parent, the view is created as a chrome-less child window
	// inside the single cockpit window (x/y in parent client coords);
	// without one it is its own draggable desktop window.
	MFDSplitView(
		const char *title,
		int source_width,
		int source_height,
		int display_width,
		int display_height,
		int x,
		int y,
		ButtonStyle button_style = NoButtons,
		int anchorA = 0,
		int anchorB = 0,
		void *parent = 0
	);

	int
		ClientWidth() const
			{ return clientWidth; }
	int
		ClientHeight() const
			{ return clientHeight; }

	// Move the pane (child mode: parent client coords). Panes overlap
	// the viewscreen like the pod's bezels, so exact placement happens
	// after construction from the measured client sizes.
	void
		SetPosition(int x, int y);

	// Re-scale the glass (cockpit resized): the source buffer is
	// unchanged, only the destination size and the button geometry
	// derived from it.
	void
		Resize(int display_width, int display_height);

	// Take the pane off screen. Used for the Winners Circle, which wants
	// the whole viewscreen: the panes overlap it like the pod's bezels,
	// so hiding them uncovers the full canvas underneath.
	void
		Hide();

	// caption and HWND, for the sticky-placement file
	const char *
		Title() const
			{ return paneTitle; }
	void *
		Window()
			{ return window; }

	~MFDSplitView();

	Logical
		TestInstance() const;

	unsigned long *
		Pixels()
			{ return pixels; }

	void
		Repaint();

	// Window-procedure callbacks (public for the registered WndProc)
	void
		Paint();
	void
		MouseDown(int x, int y);
	void
		MouseUp();

protected:
	void
		LayoutButtons(
			ButtonStyle button_style,
			int anchorA,
			int anchorB,
			int display_width,
			int display_height,
			int *client_width,
			int *client_height
		);

	struct ScreenButton
	{
		int	unit;
		int	x, y, w, h;
		int	amber;			// 0 = red family, 1 = amber family
	};

	enum { maxButtons = 20 };

	void
		*window;			// HWND
	void
		*blitHeader;		// BITMAPINFOHEADER for StretchDIBits
	unsigned long
		*pixels;
	int
		sourceWidth,
		sourceHeight;

	int
		displayX, displayY,
		displayW, displayH;
	int
		clientWidth, clientHeight;

	ScreenButton
		buttons[maxButtons];
	int
		buttonCount;
	int
		pressedIndex;

	// kept so the bank can be rebuilt when the cockpit re-scales
	ButtonStyle
		buttonStyle;
	int
		buttonAnchorA,
		buttonAnchorB;

	// the window caption, and the key this pane is saved under
	const char
		*paneTitle;
	// True for a pane of its own on the desktop (the exploded view); the
	// composited cockpit's panes are chrome-less children and cannot be
	// dragged, so there is nothing to remember for them.
	Logical
		ownWindow;
};

//########################################################################
// Sticky window placement.
//
// The game window and, in the exploded view, each display pane are all
// draggable, but their placement is recomputed on every launch - so
// putting a window somewhere useful never survived the menu-race-menu
// loop. RP412MFDLAYOUT remembers it, in mfd_layout.cfg beside
// bindings.txt:
//
//   off / 0 / unset   computed placement only, no file (default)
//   load / restore    restore saved placement at startup, never write
//   save / adjust     restore, then rewrite on each finished drag and
//                     on teardown - the round trip
//
// One "<title>=x,y,w,h" line per window, plus an optional ",noframe"
// that takes that window's title bar and border off - for a cockpit that
// fills a monitor edge to edge without -fit's all-or-nothing, or an
// exploded pane photographed without chrome. A bare window has nothing
// to drag by, so place it first and add the flag after; Save carries the
// flag back out, since it is an instruction rather than something
// measured off the window. Windows are always built framed, so deleting
// the flag is all it takes to get the frame back.
//
// Whether the size comes back depends on the window, which is why
// Register takes it as a flag:
//
//   display panes  position only. A pane's size follows its content and
//                  its button banks, so an old size from a different
//                  build must not distort it. The plasma glass registers
//                  the same way - its size is L4PLASMASCALE's business.
//   the game window  position and size. Nothing derives that size - -res
//                  only decides how sharp the scene is, and the cockpit
//                  fits itself to whatever client area it is given - so
//                  a window sized to suit a monitor should come back
//                  that way, and half-restoring it would be the strange
//                  behaviour. RPL4.CPP registers it before the console
//                  screen, so the saved placement is there from the
//                  first frame rather than arriving when a race starts.
//
// A placement that lands on none of the monitors currently plugged in is
// ignored rather than applied - restoring the game window off screen
// would leave nothing to drag back.
//
// Lives here because the display panes were the first to need it; the
// game window joined later rather than grow a second copy of the same
// file format.
//
// Ported from BT411's BT_GLASS_LAYOUT.
//########################################################################

// Take part in the saved layout. title is the key in the file and must
// outlive the window (the callers pass string literals).
void
	RPWindowLayout_Register(void *window, const char *title, Logical with_size);
void
	RPWindowLayout_Forget(void *window);

// Apply the saved placement over the computed one. Call once everything
// has been built and placed.
void
	RPWindowLayout_Load();

// Write every registered window's placement. No-op unless mode is save.
void
	RPWindowLayout_Save();
