/*
 * M A N D E L B R O T	C O N S T R U C T I O N   S E T
 *
 * (C) Copyright 1989 by Olaf Seibert.
 * Mandel may be freely distributed. See file 'doc/Notice' for details.
 *
 * The Display routines; initialisation and de-initialisation of
 * screen and window.
 */

#include <exec/types.h>
#include <intuition/intuition.h>
#ifdef DEBUG
#   include <stdio.h>
#   undef STATIC
#   define STATIC   /* EMPTY */
#endif
#include "mandel.h"

#define BUGHEIGHT 213	/* See later comment */
#define BUGWIDTH  640

USHORT ColorMap[MAXDEPTH];
bool ColorMapValid = FALSE;


/*
 *  Initialize the screen and the windows and the menus
 *  Return value indicates FAILURE.
 */

bool InitDisplay(borderless)
bool borderless;
{
    USHORT ViewModes = MandelNScreen.ViewModes;
    struct Screen WBScreen;
    int i;

    StopFraming();

    Saved = TRUE;   /* We can easily reconstruct this `picture' */

    if (WBWidth == 0) { /* Get Left, Top, Width, Height */
	GetScreenData(&WBScreen, (long)sizeof(WBScreen),
	    (long)WBENCHSCREEN, NULL);
	WBWidth = WBScreen.Width;
	WBHeight = WBScreen.Height;
	/* Maybe we have an interlaced WorkBench screen */
	if (WBScreen.ViewPort.Modes & LACE) WBHeight >>= 1;
	/* And maybe, if we use MWB, it isn't hires... */
	if (!(WBScreen.ViewPort.Modes & HIRES)) WBWidth <<= 1;
    }
    MandelNScreen.Width = WBWidth;
    MandelNScreen.Height = WBHeight;

    if (ViewModes & LACE) MandelNScreen.Height <<= 1;
    if (MandelNScreen.Height < MINSCREENHEIGHT)
	MandelNScreen.Height = MINSCREENHEIGHT;

    if (ViewModes & HIRES) {
	MandelNScreen.Depth = 4;

	/* Avoid a bug in MrgCop()?? if you have a PAL machine with */
	/* a screen wider than 640 taller than 213 and with 4 bitplanes */

	if (MandelNScreen.Width > BUGWIDTH && MandelNScreen.Height > BUGHEIGHT)
	    MandelNScreen.Width = BUGWIDTH;
    } else {
	MandelNScreen.Width >>= 1;
	if (ViewModes & EXTRA_HALFBRITE) {
	    MandelNScreen.Depth = 6;
	} else {
	    MandelNScreen.Depth = 5;
	}
    }

    if (MandelNScreen.Width < MINSCREENWIDTH)
	MandelNScreen.Width = MINSCREENWIDTH;

    NumColors = 1 << MandelNScreen.Depth;

    if ( !MandelScreen && !(MandelScreen = OpenScreen(&MandelNScreen)) ) {
	skipto abort;
    }

    if (ColorMapValid)
	LoadRGB4(&MandelScreen->ViewPort, ColorMap, (long) NumColors);

    MainNWindow.Screen = MandelScreen;

    if (MainNWindow.Height < MainNWindow.MinHeight) {
	/* First time we open the window */
	MainNWindow.LeftEdge = 0;
	MainNWindow.TopEdge  = MandelScreen->BarHeight;
	MainNWindow.Width    = MandelScreen->Width;
	MainNWindow.Height   = MandelScreen->Height - MainNWindow.TopEdge;
    } else {
	if (ViewModes & HIRES) {
	    MainNWindow.LeftEdge <<= 1;
	    MainNWindow.Width <<= 1;
	}
	if (ViewModes & LACE) {
	    MainNWindow.TopEdge <<= 1;
	    MainNWindow.Height <<= 1;
	}
    }

    /* Check for windows that can't be opened */

    if (MainNWindow.LeftEdge + MainNWindow.Width > MandelScreen->Width)
	MainNWindow.Width = MandelScreen->Width - MainNWindow.LeftEdge;

    if (MainNWindow.TopEdge + MainNWindow.Height > MandelScreen->Height)
	MainNWindow.Height = MandelScreen->Height - MainNWindow.TopEdge;

    if ( !MainWindow && !(MainWindow = OpenWindow(&MainNWindow)) ) {
	skipto abort;
    }

    SetMenuStrip(MainWindow, MandelMenu);
    if (borderless) {
	DoBorderless(MainWindow, &borderinfo);
    }

    InitPenTable();

    return FALSE;

abort:
    CleanupDisplay((bool) TRUE);
    return TRUE;

}

bool CleanupDisplay(everything)
bool everything;
{
    bool wasborderless;
    int i;

    StopDrawing();
    StopFraming();

    CloseColorWindow((BOOL) FALSE);

    wasborderless = (MainWindow != NULL) &&
	((MainWindow->Flags & BORDERLESS) != 0);

    if (MainWindow) {
	/* Save window appearance for later, in low-res non-lace pixels */
	MainNWindow.LeftEdge = MainWindow->LeftEdge;
	MainNWindow.TopEdge  = MainWindow->TopEdge;
	MainNWindow.Width    = MainWindow->Width;
	MainNWindow.Height   = MainWindow->Height;

	ClearMenuStrip(MainWindow);     /* Remove menu strip */
	CloseWindow(MainWindow);        /* Finally close it */
	MainWindow = NULL;
    }

    /* Save the colors we may have established with great care */

    if (MandelScreen) {
	for (i=0; i < NumColors; i++) {
	    ColorMap[i] = GetRGB4(MandelScreen->ViewPort.ColorMap, i);
	}
	ColorMapValid = TRUE;

	if (MandelScreen->ViewPort.Modes & HIRES) {
	    MainNWindow.LeftEdge >>= 1;
	    MainNWindow.Width >>= 1;
	}
	if (MandelScreen->ViewPort.Modes & LACE) {
	    MainNWindow.TopEdge >>= 1;
	    MainNWindow.Height >>= 1;
	}

	/* Close the screen only if `everything' must be cleaned up */

	if (everything) {
	    CloseScreen(MandelScreen);
	    MandelScreen = NULL;
	}
    }

    return wasborderless;
}

bool ReInitDisplay()
{
    bool WasBorderless;

    WasBorderless = CleanupDisplay((bool) TRUE);
    if (InitDisplay(WasBorderless)) { /* Trouble */
	MandelNScreen.ViewModes &= ~(HIRES | LACE | EXTRA_HALFBRITE);
	WBWidth = 0;	/* Re-use Workbench screen size */
	if (InitDisplay((bool) FALSE))
	    MyExit("Can't re-init display - Maybe low on memory");
	SelectMenu(MENU(OPTMENU, OPTRES, ORHI), (bool)FALSE);
	SelectMenu(MENU(OPTMENU, OPTRES, ORILC), (bool)FALSE);
	SelectMenu(MENU(OPTMENU, OPTRES, ORBCK), (bool)FALSE);
	SelectMenu(MENU(OPTMENU, OPTRES, OREHB), (bool)FALSE);

	return TRUE;
    }

    return FALSE;
}

bool DoBorderless(window, borderinfo)
struct Window *window;
struct BorderInfo *borderinfo;
{
    /* Make window borderless */

/* register struct Layer_Info *LayerInfo = &window->WScreen->LayerInfo; */
#define LayerInfo   NULL	    /* Since V1.2 */
    register struct Layer *Layer = window->RPort->Layer;
    register long movex;
    register long movey;
    register long sizex;
    register long sizey;
    bool Success = FALSE;

    if (window->Flags & BORDERLESS) return TRUE;

    LockLayer(LayerInfo, Layer);

    window->Flags |= BORDERLESS;

    movex = -window->BorderLeft;
    movey = -window->BorderTop;
    sizex = window->BorderRight - movex;
    sizey = window->BorderBottom - movey;

    window->BorderLeft =
    window->BorderTop =
    window->BorderRight =
    window->BorderBottom = 0;

    window->GZZWidth += sizex;
    window->GZZHeight += sizey;

    if ( MoveLayer(LayerInfo, Layer, movex, movey) ) {
	Success = SizeLayer(LayerInfo, Layer, sizex, sizey);
	if (!Success) {
	    sizex = sizey = 0;
	}
    } else {
	movex = movey = sizex = sizey = 0;
    }
    UnlockLayer(Layer);

    borderinfo->MoveX = movex;
    borderinfo->MoveY = movey;
    borderinfo->SizeX = sizex;
    borderinfo->SizeY = sizey;

    /* Done making borderless */

    if (Success) {
	return Success;
    } else {	/* Try to clean up the mess */
	UndoBorderless(window, borderinfo);
	return FALSE;
    }
#undef LayerInfo
}

void UndoBorderless(window, borderinfo)
struct Window *window;
struct BorderInfo *borderinfo;
{
    /* ``Another fine mess you got me into!'' (Oliver Hardy) */

/*  register struct Layer_Info *LayerInfo = &window->WScreen->LayerInfo; */
#define LayerInfo   NULL	    /* Since V1.2 */
    register struct Layer *Layer = window->RPort->Layer;
    register long movex = borderinfo->MoveX;
    register long movey = borderinfo->MoveY;
    register long sizex = borderinfo->SizeX;
    register long sizey = borderinfo->SizeY;
    bool Success = FALSE;

    if (!(window->Flags & BORDERLESS))  return;

    LockLayer(LayerInfo, Layer);
    SizeLayer(LayerInfo, Layer, -sizex, -sizey);
    MoveLayer(LayerInfo, Layer, -movex, -movey);

    window->GZZWidth -= sizex;
    window->GZZHeight -= sizey;

    window->BorderLeft = -movex;
    window->BorderTop = -movey;
    window->BorderRight = sizex + movex;
    window->BorderBottom = sizey + movey;

    window->Flags &= ~BORDERLESS;

    RefreshWindowFrame(window);

    UnlockLayer(Layer);

    /* Done Undoing Borderless */
#undef LayerInfo
}
