/* --- Copyright University of Sussex 1997. All rights reserved. ----------
 * File:			C.win32/extern/src/base.c
 * Purpose:			An experimental base window for Poplog with simple Ved
 * Author:			Robert John Duncan, Jul 14 1994 (see revisions)
 */

#include "popcore.h"
#include "popwin.h"

const TCHAR POP_BASE_CLASS_NAME[] = TEXT("PopBase");

static LOGFONT base_font = {
	0,				/* height -- set on window creation */
	0,				/* width -- defaults to match the height */
	0,				/* escapement -- none */
	0,				/* orientation -- none */
	0,				/* weight -- default */
	FALSE,			/* italic -- no */
	FALSE,			/* underline -- no */
	FALSE,			/* strikeout -- no */
	ANSI_CHARSET,
	OUT_DEFAULT_PRECIS,
	CLIP_DEFAULT_PRECIS,
	DEFAULT_QUALITY,
	FIXED_PITCH|FF_MODERN,
	{TEXT("Courier New")},
};

static void post_message_to_owner(
		HWND	hwnd,
		UINT	msg,
		WPARAM	wParam,
		LPARAM	lParam)
	/*	Send a message to the thread which created this window: the thread
		ID is saved in the window structure
	*/
{
	DWORD owner = GetWindowLong(hwnd, 4);
	if (!PostThreadMessage(owner, msg, wParam, lParam))
	{
		TCHAR text[128];
		DWORD error = GetLastError();
		wsprintf(
			text,
			TEXT("Your base window has just failed to get a message to Poplog.")
			TEXT("The message ID was %d and the error code was %d."),
			msg, error);
		MessageBox(hwnd, text, TEXT("Poplog Error"), MB_ICONSTOP|MB_OK);
	}
}

static int confirm_exit(HWND hwnd) {
	static TCHAR text[] =
		TEXT("Files have changed.\n")
		TEXT("Do you want to save the changes?");
	static TCHAR caption[] =
		TEXT("Poplog Exit");
	switch (MessageBox(hwnd, text, caption, MB_ICONEXCLAMATION|MB_SETFOREGROUND|
											MB_YESNOCANCEL)) {
	case IDYES:
		return 0;
	case IDNO:
		return 1;
	case IDCANCEL:
	default:
		return 2;
	}
}

static LRESULT CALLBACK BaseWindowProc(
		HWND	hwnd,
		UINT	msg,
		WPARAM	wParam,
		LPARAM	lParam)
{
	POP_BASE_WINDOW_DATA *pb;

	/* extract per-window data */
	pb = (POP_BASE_WINDOW_DATA*)GetWindowLong(hwnd, 0);

	switch (msg)
	{
		case WM_CREATE:
		{
			CREATESTRUCT *cs = (CREATESTRUCT*)lParam;
			HDC hdc;
			HFONT old_font;
			TEXTMETRIC tm;
			int x, y, cx, cy, hres, vres;

			/* make space for the window data */
			pb = (POP_BASE_WINDOW_DATA*)pop_alloc(sizeof(POP_BASE_WINDOW_DATA));
			if (pb == NULL)
				return -1;
			SetWindowLong(hwnd, 0, (LONG)pb);

			/* save window handle and owner thread ID from CREATESTRUCT */
			pb->self = hwnd;
			SetWindowLong(hwnd, 4, *(DWORD*)cs->lpCreateParams);

			/* get initial size of frame and client area */
			GetWindowRect(hwnd, &pb->frame);
			GetClientRect(hwnd, &pb->client);

			/* select a font for the window: 10-point, fixed width */
			hdc = GetDC(hwnd);
			base_font.lfHeight = -((10*GetDeviceCaps(hdc, LOGPIXELSY))/72);
			pb->font = CreateFontIndirect(&base_font);
			if (pb->font == NULL)
				pb->font = (HFONT)GetStockObject(SYSTEM_FIXED_FONT);

			/* get character size */
			old_font = (HFONT)SelectObject(hdc, (HGDIOBJ)pb->font);
			GetTextMetrics(hdc, &tm);
			SelectObject(hdc, (HGDIOBJ)old_font);
			pb->charw = tm.tmAveCharWidth;
			pb->charh = tm.tmHeight;

			/* recompute size for a 24 x 80 display with a 2-pixel border
			   around the editing area */
			cx = pb->frame.right - pb->frame.left - pb->client.right + 4
					+ 80*pb->charw;
			cy = pb->frame.bottom - pb->frame.top - pb->client.bottom + 4
					+ 24*pb->charh;

			/* try to ensure the whole editing area is visible */
			hres = GetDeviceCaps(hdc, HORZRES);
			vres = GetDeviceCaps(hdc, VERTRES);
			x = pb->frame.left;
			if (x + cx > hres)
			{
				x = hres - cx;
				if (x < 0) x = 0;
			}
			y = pb->frame.top;
			if (y + cy > vres)
			{
				y = vres - cy;
				if (y < 0) y = 0;
			}

			/* reposition the window */
			ReleaseDC(hwnd, hdc);
			if (!MoveWindow(hwnd, x, y, cx, cy, FALSE))
				return -1;

			/* create the child edit window */
			pb->child = CreateWindow(
				POP_EDIT_CLASS_NAME,		/* name of local class */
				NULL,						/* name of window -- none */
				WS_CHILD|WS_VISIBLE,		/* window style */
				pb->client.left + 2,		/* X coord */
				pb->client.top + 2,			/* Y coord */
				pb->client.right - 4,		/* width */
				pb->client.bottom - 4,		/* height */
				hwnd,						/* parent window */
				NULL,						/* menu */
				GetModuleHandle(NULL),		/* application instance */
				NULL						/* additional information */
			);
			if (pb->child == NULL)
				return -1;

			/* set the editor font */
			SendMessage(pb->child, WM_SETFONT, (WPARAM)pb->font, 0);

			break;
		}

		case WM_DESTROY:
			/* free window data */
			pb = (POP_BASE_WINDOW_DATA*)SetWindowLong(hwnd, 0, 0);
			if (pb != NULL)
			{
				DeleteObject(pb->font);
				pop_free(pb);
			}
			/* terminate the program */
			PostQuitMessage(0);
			break;

		case WM_SETFOCUS:
			/* pass focus to the edit area */
			SetFocus(pb->child);
			break;

		case WM_WINDOWPOSCHANGING:
		{
			/* size or position changing: truncate size so as not to clip
			   characters in the edit area */
			WINDOWPOS *wp = (WINDOWPOS*)lParam;
			int extra_x, extra_y;
			extra_x = pb->frame.right - pb->frame.left - pb->client.right + 4;
			wp->cx = extra_x + pb->charw*((wp->cx - extra_x) / pb->charw);
			extra_y = pb->frame.bottom - pb->frame.top - pb->client.bottom + 4;
			wp->cy = extra_y + pb->charh*((wp->cy - extra_y) / pb->charh);
			break;
		}

		case WM_SIZE:
			if (wParam != SIZE_MINIMIZED)
			{
				/* reset frame and client window sizes */
				GetWindowRect(hwnd, &pb->frame);
				GetClientRect(hwnd, &pb->client);
				/* adjust editor window to new size */
				if (pb->child != NULL)
					if (MoveWindow(
							pb->child,
							pb->client.left + 2,  pb->client.top + 2,
							pb->client.right - 4, pb->client.bottom - 4,
							FALSE)) {
						/* tell Poplog */
						int nrows = (pb->client.bottom-4) / pb->charh;
						int ncols = (pb->client.right-4) / pb->charw;
						post_message_to_owner(
							hwnd, POPM_EDIT_SIZE,
							MAKEWPARAM(nrows, ncols), 0);
					}
			}
			break;

		case WM_CLOSE:
			/* forward to Poplog */
			post_message_to_owner(hwnd, POPM_CLOSE, wParam, lParam);
			break;

		/*	this is meant to catch and discard the activating mouse-press in
			the client window, but the WM_MOUSEACTIVATE message gets sent for
			every mouse press; surely some mistake?
		case WM_MOUSEACTIVATE:
			return LOWORD(lParam) == HTCLIENT ? MA_ACTIVATEANDEAT : MA_ACTIVATE;
			break;
		*/

		/* Messages from Poplog */

		case POPM_CONFIRM_EXIT:
			return confirm_exit(hwnd);

		/* Messages from the edit window */

		case POPM_EDIT_CHAR:
		case POPM_EDIT_FUNCTION:
		case POPM_EDIT_MOUSE:
			/* redirect to owner thread */
			post_message_to_owner(hwnd, msg, wParam, lParam);
			break;

		case POPM_EDIT_INTERRUPT:
			/*	interrupt key (Ctrl+Break) pressed, same as Ctrl+C typed at
				the console */
			pop_signal(POP_SIG_INT);
			break;

		default:
			/* default processing */
			return DefWindowProc(hwnd, msg, wParam, lParam);
	}

	return 0;
}

ATOM popwin_init_base_window_class(void)
{
	WNDCLASS bwc = {
		CS_HREDRAW|CS_VREDRAW,			/* style */
		BaseWindowProc,					/* window procedure */
		0,								/* extra bytes for the class */
		2*sizeof(LONG),					/* extra bytes per window */
		GetModuleHandle(NULL),			/* application instance */
		LoadIcon(NULL, IDI_APPLICATION),/* icon */
		LoadCursor(NULL, IDC_ARROW),	/* cursor */
		(HBRUSH)(COLOR_WINDOW+1),		/* background colour */
		NULL,							/* no menu (yet) */
		POP_BASE_CLASS_NAME,			/* class name */
	};
	HMODULE hPoplog = GetModuleHandle(TEXT("Poplog"));
	if (hPoplog != NULL) {
		/* use special icon */
		HICON hPoplogIcon = LoadIcon(hPoplog, TEXT("PoplogIcon"));
		if (hPoplogIcon != NULL)
			bwc.hIcon = hPoplogIcon;
	}
	return RegisterClass(&bwc);
}

/* --- Revision History ---------------------------------------------------
--- Robert Duncan, Jan 29 1997
		Corrections for UNICODE compilation
--- Robert Duncan, Mar 29 1996
		Interrupt passed on via pop_signal
--- Robert Duncan, Mar 21 1996
		Changed to use Poplog icon when available
--- Robert John Duncan, Feb  7 1996
		Took out use of hot-key for interrupt: now received as a message
		from the editor window.
		Added confirm-exit dialog.
--- Robert John Duncan, Jan  8 1996
		Changed to pass on mouse events from the edit window
 */
