#include "gtlayout.h"

#include <dos/dos.h>

#include <exec/execbase.h>
#include <exec/libraries.h>

#include <clib/exec_protos.h>
#include <pragmas/exec_pragmas.h>

struct GTLayoutBase
{
	struct Library		 LibNode;
	struct ExecBase		*SysBase;
	struct SignalSemaphore	 LockSemaphore;
	BPTR			 LibSegment;
};

#define SysBase		GTLayoutBase->SysBase
#define LockSemaphore	GTLayoutBase->LockSemaphore
#define LibSegment	GTLayoutBase->LibSegment

STATIC struct Library * __asm __saveds	LibInit(register __a0 BPTR Segment,register __d0 struct GTLayoutBase *GTLayoutBase,register __a6 struct ExecBase *ExecBase);
STATIC struct Library * __asm __saveds	LibOpen(register __a6 struct GTLayoutBase *GTLayoutBase);
STATIC BPTR __asm __saveds		LibExpunge(register __a6 struct GTLayoutBase *GTLayoutBase);
STATIC BPTR __asm __saveds		LibClose(register __a6 struct GTLayoutBase *GTLayoutBase);
STATIC LONG __asm __saveds		LibNull(register __a6 struct GTLayoutBase *GTLayoutBase);

STATIC APTR LibVectors[] =
{
	LibOpen,
	LibClose,
	LibExpunge,
	LibNull,

	LT_LevelWidth,
	LT_DeleteHandle,
	LT_CreateHandle,
	LT_CreateHandleTagList,
	LT_Rebuild,
	LT_HandleInput,
	LT_BeginRefresh,
	LT_EndRefresh,
	LT_GetAttributesA,
	LT_SetAttributesA,
	LT_AddA,
	LT_NewA,
	LT_EndGroup,
	LT_LayoutA,
	LT_LayoutMenusA,
	LT_Fixed2String,
	LT_String2Fixed,
	LT_FixedMult,
	LT_LabelWidth,
	LT_LabelChars,
	LT_LockWindow,
	LT_UnlockWindow,
	LT_DeleteWindowLock,
	LT_ShowWindow,
	LT_Activate,
	LT_PressButton,
	LT_GetCode,
	LT_GetIMsg,
	LT_ReplyIMsg,
	LT_BuildA,
	LT_RebuildTagList,

	(APTR)-1
};

extern UBYTE __far	LibName[],
			LibID[];

extern LONG __far	LibVersion,
			LibRevision;

struct { ULONG DataSize; APTR Table; APTR Data; struct GTLayoutBase * (*Init)(); } __aligned LibInitTab =
{
	sizeof(struct GTLayoutBase),
	LibVectors,
	NULL,
	LibInit
};

STATIC struct GTLayoutBase * __asm __saveds
LibInit(register __a0 BPTR Segment,register __d0 struct GTLayoutBase *GTLayoutBase,register __a6 struct ExecBase *ExecBase)
{
	GTLayoutBase -> LibNode . lib_Node . ln_Type	= NT_LIBRARY;
	GTLayoutBase -> LibNode . lib_Node . ln_Name	= LibName;
	GTLayoutBase -> LibNode . lib_Flags		= LIBF_CHANGED | LIBF_SUMUSED;
	GTLayoutBase -> LibNode . lib_Version		= LibVersion;
	GTLayoutBase -> LibNode . lib_Revision		= LibRevision;
	GTLayoutBase -> LibNode . lib_IdString		= (APTR)LibID;

	LibSegment	= Segment;
	SysBase		= ExecBase;

	InitSemaphore(&LockSemaphore);

#ifdef CPU_ANY
	if(SysBase -> LibNode . lib_Version < 37)
#else
	if(SysBase -> LibNode . lib_Version < 37 || !(SysBase -> AttnFlags & AFF_68020))
#endif	/* CPU_ANY */
		return(NULL);
	else
		return(GTLayoutBase);
}

STATIC struct Library * __asm __saveds
LibOpen(register __a6 struct GTLayoutBase *GTLayoutBase)
{
	GTLayoutBase -> LibNode . lib_Flags &= ~LIBF_DELEXP;

	GTLayoutBase -> LibNode . lib_OpenCnt++;

	if(GTLayoutBase -> LibNode . lib_OpenCnt == 1)
	{
		ObtainSemaphore(&LockSemaphore);

		if(LT_Init())
			ReleaseSemaphore(&LockSemaphore);
		else
		{
			LT_Exit();

			ReleaseSemaphore(&LockSemaphore);

			GTLayoutBase -> LibNode . lib_OpenCnt--;

			return(NULL);
		}
	}

	return(GTLayoutBase);
}

STATIC BPTR __asm __saveds
LibExpunge(register __a6 struct GTLayoutBase *GTLayoutBase)
{
	if(!GTLayoutBase -> LibNode . lib_OpenCnt && LibSegment)
	{
		BPTR TempSegment = LibSegment;

		Remove((struct Node *)GTLayoutBase);

		FreeMem((BYTE *)GTLayoutBase - GTLayoutBase -> LibNode . lib_NegSize,GTLayoutBase -> LibNode . lib_NegSize + GTLayoutBase -> LibNode . lib_PosSize);

		return(TempSegment);
	}
	else
	{
		GTLayoutBase -> LibNode . lib_Flags |= LIBF_DELEXP;

		return(NULL);
	}
}

STATIC BPTR __asm __saveds
LibClose(register __a6 struct GTLayoutBase *GTLayoutBase)
{
	if(GTLayoutBase -> LibNode . lib_OpenCnt > 0)
		GTLayoutBase -> LibNode . lib_OpenCnt--;

	if(!GTLayoutBase -> LibNode . lib_OpenCnt)
	{
		ObtainSemaphore(&LockSemaphore);

		LT_Exit();

		ReleaseSemaphore(&LockSemaphore);

		if(GTLayoutBase -> LibNode . lib_Flags & LIBF_DELEXP)
			return(LibExpunge(GTLayoutBase));
	}

	return(NULL);
}

STATIC LONG __asm __saveds
LibNull(register __a6 struct GTLayoutBase *GTLayoutBase)
{
	return(NULL);
}
