/*
 *	Windows.c - Copyright © 1991 by S.R. & P.C.
 *
 *	Created:	27 Feb 1991  09:35:12
 *	Modified:	21 Jul 1991  17:19:13
 *
 *	Make>> make
 */

#include "Global.h"
#include "proto/Windows.h"
#include "proto/File.h"
#include "proto/Draw.h"
#include "proto/Menus.h"
#include "proto/String.h"


#define XPOS_COL1	0
#define XPOS_COL2	282


extern struct Screen *Screen;
extern struct MsgPort *MainPort;
extern struct MinList WindowList;
extern struct BrowserWindow *CurrentWin;
extern struct Config Config;
extern struct Menu Menu1;
extern char *ReqTitle;
extern char *Copyright;
extern BOOL CustomScreen;
extern short SelectNum;
extern long SelectBytes, SelectBlocks;


static long IDCMPFlags = GADGETDOWN|GADGETUP|MOUSEBUTTONS|MENUPICK|RAWKEY|NEWSIZE|CLOSEWINDOW|ACTIVEWINDOW|DISKINSERTED|DISKREMOVED;

static struct NewScreen NewBrowserScreen = {
	0,0,			/* screen XY origin relative to View */
	640,256,		/* screen width and height */
	2,				/* screen depth (number of bitplanes) */
	0,1,			/* detail and block pens */
	HIRES,			/* display modes for this screen */
	CUSTOMSCREEN,	/* screen type */
	NULL,			/* pointer to default screen font */
	NULL,			/* screen title */
	NULL,			/* first in list of custom screen gadgets */
	NULL			/* pointer to custom BitMap structure */
};


struct NewWindow NewBrowserWindow = {
	0,0,			/* window XY origin relative to TopLeft of screen */
	280,57,			/* window width and height */
	0,1,			/* detail and block pens */
	NULL,			/* IDCMP flags */
	WINDOWSIZING|WINDOWDRAG|WINDOWDEPTH|SMART_REFRESH|NOCAREREFRESH|ACTIVATE,	/* other window flags */
	NULL,			/* first gadget in gadget list */
	NULL,			/* custom CHECKMARK imagery */
	NULL,			/* window title */
	NULL,			/* custom screen pointer */
	NULL,			/* custom bitmap */
	110,57,			/* minimum width and height */
	-1,-1,			/* maximum width and height */
	WBENCHSCREEN	/* destination screen type */
};


static short PointerMatrix[36] = {
	0, 0, 4294967168, 4294967168, 16640, 0,
	25344, 8704, 30464, 13824, 32512, 15872, 23808, 7168, 23808, 7168, 18688,
	2048, 23808, 7168, 21760, 5120, 30464, 13824, 25344, 8704, 27392, 10752,
	32512, 15872, 4294967168, 4294967168, 0, 0, 0, 0
};


#define WAIT_XOFFSET	-1L
#define WAIT_YOFFSET	 0L
#define WAIT_SIZE		72L


static void SafeCloseWindow(struct Window *win)
{
	register struct IntuiMessage *msg, *succ;
	register struct MsgPort	*mp = win->UserPort;

	Forbid();
	msg = (struct IntuiMessage *)mp->mp_MsgList.lh_Head;
	while (succ=(struct IntuiMessage *)msg->ExecMessage.mn_Node.ln_Succ) {
		if (msg->IDCMPWindow == win) {
			Remove((struct Node *)msg);
			ReplyMsg((struct Message *)msg);
		}
		msg = succ;
	}
	win->UserPort = NULL;
	ModifyIDCMP(win, 0);
	Permit();
	CloseWindow(win);
}


void SetWaitPointer(BOOL on)
{
	static short *ChipPointerMatrix = NULL;
	static short NestCnt = 0;
	register struct IntuiMessage *msg, *succ;
	struct BrowserWindow *Win, *Next;

	if (on == TRUE) {
		NestCnt++;
		if (NestCnt > 1)
			return;
	}
	else if (on == FALSE) {
		NestCnt--;
		if (NestCnt >= 1)
			return;
		/* remove some pending messages to avoid careless mistakes */
		Forbid();
		msg = (struct IntuiMessage *)MainPort->mp_MsgList.lh_Head;
		while (succ=(struct IntuiMessage *)msg->ExecMessage.mn_Node.ln_Succ) {
			switch(msg->Class) {
			case MOUSEBUTTONS:
			case MENUPICK:
			case RAWKEY:
				Remove((struct Node *)msg);
				ReplyMsg((struct Message *)msg);
				break;
			}
			msg = succ;
		}
		Permit();
	}
	if (!ChipPointerMatrix) {
		ChipPointerMatrix = ArpAllocMem(WAIT_SIZE, MEMF_PUBLIC|MEMF_CHIP);
		CopyMem(PointerMatrix, ChipPointerMatrix, WAIT_SIZE);
	}
	Win = (struct BrowserWindow *)WindowList.mlh_Head;
	while(Next = (struct BrowserWindow *)Win->bw_Node.mln_Succ) {
		if (on == TRUE)
			SetPointer(Win->bw_Window, ChipPointerMatrix, 16L, 16L, WAIT_XOFFSET, WAIT_YOFFSET);
		else
			ClearPointer(Win->bw_Window);
		Win = Next;
	}
}


struct BrowserWindow *FindWindow(struct Window *W)
{
	struct BrowserWindow *Win;

	Win = (struct BrowserWindow *)WindowList.mlh_Head;
	while(Win && Win->bw_Window != W) {
		Win = (struct BrowserWindow *)Win->bw_Node.mln_Succ;
	}
	return Win;
}


struct BrowserWindow *FindDir(BPTR DirLock)
{
	struct BrowserWindow *Win;

	if (!DirLock)
		return NULL;
	Win = (struct BrowserWindow *)WindowList.mlh_Head->mln_Succ;	/* Skip main window */
	while(Win->bw_Node.mln_Succ) {
		if (!CompareLock(DirLock, Win->bw_DirLock)) {
			return Win;
		}
		Win = (struct BrowserWindow *)Win->bw_Node.mln_Succ;
	}
	return NULL;
}


static void FreeWindowMem(struct BrowserWindow *Win)
{
	struct ScrollEntry *S;
	short n;

	if (Win->bw_Type == BW_MAIN) {
		if ((n = Win->bw_NumEntries) > 0) {
			if (Win->bw_EntryArray) {
				if (Win->bw_EntryArray[0]) {
					if (Win->bw_EntryArray[0]->se_Print)
						FreeMem(Win->bw_EntryArray[0]->se_Print, n*(Win->bw_PrintStringLen+1));
					FreeMem(Win->bw_EntryArray[0], n*sizeof(struct ScrollEntry));
				}
				FreeMem(Win->bw_EntryArray, n<<2);
			}
			SelectNum -= Win->bw_SelectNum;
		}
	}
	else {
		FreePrintStrings(Win);
		while(S = (struct ScrollEntry *)RemTail((struct List *)&Win->bw_EntryList)) {
			/* if entry was selected, sub infos from global selected infos */
			if (S->se_State & STATE_SELECTED) {
				SelectBytes -= S->se_FileInfo.fi_Size;
				SelectBlocks -= S->se_FileInfo.fi_NumBlocks;
				SelectNum--;
			}
			CleanFileInfo(&S->se_FileInfo);
			FreeMem(S, sizeof(struct ScrollEntry));
		}
		while(S = (struct ScrollEntry *)RemTail((struct List *)&Win->bw_NewEntryList)) {
			CleanFileInfo(&S->se_FileInfo);
			FreeMem(S, sizeof(struct ScrollEntry));
		}
		if (Win->bw_NumEntries > 0)
			FreeMem(Win->bw_EntryArray, Win->bw_NumEntries<<2);
	}
	Win->bw_EntryArray = NULL;
}


void ResetWindow(struct BrowserWindow *Win)
{
	FreeWindowMem(Win);
	Win->bw_Flags = 0;
	Win->bw_NumCol = 1;			/* Prevent Zero divide in refresh */
	Win->bw_ColWidth = 1;		/* Prevent Zero divide in refresh */
	Win->bw_ShownEntries = 0;
	Win->bw_NumEntries = 0;
	Win->bw_NumNewEntries = 0;
	Win->bw_NumDeleted = 0;
	Win->bw_NumDirs = 0;
	Win->bw_NumFiles = 0;
	Win->bw_NumBytes = 0;
	Win->bw_NumBlocks = 0;
	Win->bw_SelectBytes = 0;
	Win->bw_SelectBlocks = 0;
	Win->bw_SelectNum = 0;
	Win->bw_MaxFilenameLen = 0;
	Win->bw_BottomText[0] = '\0';
	NewMinList(&Win->bw_EntryList);
	NewMinList(&Win->bw_NewEntryList);
	RefreshWindow(Win);
}


void CloseBrowserWindow(struct BrowserWindow *Win)
{
	if (Win->bw_Window) {
		ClearMenuStrip(Win->bw_Window);
		SafeCloseWindow(Win->bw_Window);
	}
	FreeWindowMem(Win);
	Remove((struct Node *)Win);				/* Unlink window from list */
	if (Win->bw_Type == BW_DIR) {
		FreeStr((char *)Win->bw_Window->Title);
		UnLock(Win->bw_DirLock);
		UnLock(Win->bw_RootLock);
	}
	FreeMem(Win, sizeof(struct BrowserWindow));
	/* make the main window the current one until next ACTIVATE msg */
	CurrentWin = (struct BrowserWindow *)WindowList.mlh_Head;
}


struct BrowserWindow *OpenBrowserWindow(struct BrowserWindow *Parent, BPTR DirLock, BPTR RootLock, short Position)
{
	struct BrowserWindow *Win, *BW;
	struct Screen *wb;
	struct Window *W;
	char *Title;
	char buf[REQ_DSIZE];
	short x,y,y1=0,y2=0;

	if (!(Win = AllocMem(sizeof(struct BrowserWindow), MEMF_PUBLIC|MEMF_CLEAR)))
		return NULL;
	if (!Parent) {				/* This is main window */
		wb = Screen = OpenWorkBench();
		if (Config.Screen == BROWSER_CUSTOM) {
			NewBrowserScreen.Width = wb->Width;
			NewBrowserScreen.Height = wb->Height;
			NewBrowserScreen.ViewModes = wb->ViewPort.Modes;
			if (Screen = OpenScreen(&NewBrowserScreen)) {
				NewBrowserWindow.Screen = Screen;
				NewBrowserWindow.Type = CUSTOMSCREEN;
				CustomScreen = TRUE;
			}
			else {
				SimpleRequest(ReqTitle, "Couldn't open screen!");
				Screen = wb;
			}
		}
		NewBrowserWindow.LeftEdge = Screen->Width-NewBrowserWindow.Width;
		NewBrowserWindow.TopEdge = Screen->Height-NewBrowserWindow.Height;
		Title = "BrowserII";
		Win->bw_Type = BW_MAIN;
		Win->bw_Sort = Config.Sort;
		Win->bw_EntryInfoFlags = Config.EntryInfoFlags;
		Win->bw_FiltersInfo = Config.DefaultFilters;
	}
	else {
		/* if dir already opened, bring window to front, and activate it */
		if (BW = FindDir(DirLock)) {
			WindowToFront(BW->bw_Window);
			ActivateWindow(BW->bw_Window);
			FreeMem(Win, sizeof(struct BrowserWindow));
			return NULL;
		}
		Win->bw_DirLock = DirLock;
		Win->bw_RootLock = RootLock;
		PathName(Win->bw_DirLock, buf, REQ_DSIZE-1);
		Title = CopyStr(buf);
		NewBrowserWindow.Flags |= WINDOWCLOSE;

		/* Copy default flags from parent window */
		Win->bw_FiltersInfo = Parent->bw_FiltersInfo;
		Win->bw_Sort = Parent->bw_Sort;
		Win->bw_EntryInfoFlags = Parent->bw_EntryInfoFlags;

		/* Compute window TopLeft corner */
		switch(Position) {
		case POS_NEWDEV:
			BW = (struct BrowserWindow *)WindowList.mlh_Head->mln_Succ; /* Skip main window */
			while(BW->bw_Node.mln_Succ) {
				if (BW->bw_Window->LeftEdge == XPOS_COL1)
					y1 = MAX(y1, BW->bw_Window->TopEdge);
				else if (BW->bw_Window->LeftEdge == XPOS_COL2)
					y2 = MAX(y2, BW->bw_Window->TopEdge);
				BW = (struct BrowserWindow *)BW->bw_Node.mln_Succ;
			}
			if (y1>y2) {
				x = XPOS_COL2;
				y = y2+11;
			}
			else {
				x = XPOS_COL1;
				y = y1+11;
			}
			break;
		case POS_SUBDIR:
			x = Parent->bw_Window->LeftEdge;
			y = Parent->bw_Window->TopEdge+11;
			break;
		case POS_PARENTDIR:
			x = Parent->bw_Window->LeftEdge;
			y = Parent->bw_Window->TopEdge-11;
			break;
		}
		if (y < 0)
			y = 0;
		else if (y + NewBrowserWindow.Height > Screen->Height)
			y = Screen->Height-NewBrowserWindow.Height;
		NewBrowserWindow.LeftEdge = x;
		NewBrowserWindow.TopEdge = y;
	}
	NewBrowserWindow.Title = (UBYTE *)Title;
	NewBrowserWindow.FirstGadget = NULL;
	Win->bw_ScrollStruct.LineSpacing = 9;
	Win->bw_ScrollStruct.RedrawAll = RedrawAll;
	Win->bw_ScrollStruct.ScrollAndDraw = ScrollAndDraw;
	Win->bw_ScrollStruct.PropGadget = &Win->bw_Prop.Gadget;
	LinkPropGadget(&Win->bw_Prop, &NewBrowserWindow, 16, -19, GADGHCOMP|GRELRIGHT|GRELHEIGHT, -15, 10);
	Win->bw_Prop.Info.Flags = AUTOKNOB|FREEVERT;
	AddTail((struct List *)&WindowList, (struct Node *)Win);
	if (!(W = Win->bw_Window = OpenWindow(&NewBrowserWindow))) {
		CloseBrowserWindow(Win);
		return NULL;
	}
	W->BorderBottom = 9;
	W->UserPort = MainPort;
	ModifyIDCMP(W, IDCMPFlags);
	IDCMPFlags &= ~(DISKINSERTED|DISKREMOVED); /* Make only main window receive these */
	SetWindowTitles(W, Title, Copyright);
	SetMenuStrip(W, &Menu1);
	SetMenus(Win);
	NewMinList(&Win->bw_EntryList);
	NewMinList(&Win->bw_NewEntryList);
	CurrentWin = Win;
	return Win;
}

