#include <pragma/exec_lib.h>
#include <pragma/dos_lib.h>
#include <pragma/utility_lib.h>
#include <pragma/miami_lib.h>
#include <exec/libraries.h>
#include <exec/memory.h>
#include <exec/execbase.h>
#include "tcpautostart.h"

static struct Library *SocketBase		= NULL;
static struct Library *SocketBase2	= NULL;
static struct Library *UtilityBase	= NULL;
static struct Library *MiamiBase		= NULL;

char	*progver	= "$VER: TCPAutoStart 0.1 (05.02.00) @ 2000 by Thorsten Gehler\r\n";

char 	*lib_id  = "$VER: bsdsocket.library 4.1 (05.02.00)\r\n";
char 	*lib_name= "bsdsocket.library";

#define LIB_VER 4;
#define LIB_REV 1;

static BOOL	waitconnect		= FALSE;
static BOOL online			= FALSE;
static BOOL libadded			= FALSE;
static UWORD timeoutcounter;

BPTR debug_fh;

/*** PROTOTYPES ***/


struct Library * __saveds ASM nslib_LibOpen(register __a6 struct Library *MyBase);
SEGLISTPTR __saveds ASM nslib_LibClose( register __a6 struct Library *MyBase);
SEGLISTPTR __saveds ASM nslib_LibExpunge( register __a6 struct Library *MyBase);
ULONG ASM nslib_LibExtfunc(void);
void InsertFunction(APTR base, ULONG Offset, APTR func);
void CreateSocketLibrary();
void CreateSocketLibrary();
void RemoveSocketLibrary(struct Library *lib);
void debug(const char *string, ...);



void main()
{
	LONG	error					= 0;
	if (!(SocketBase2 = OpenLibrary(lib_name, 0)))
	{
		if ((UtilityBase = OpenLibrary("utility.library", 37)))
		{
			struct ExecBase * execbase = (struct ExecBase *)OpenLibrary("exec.library",0);
			CreateSocketLibrary();
			if (SocketBase)
			{
				struct Library * founded;
				struct Node *currentlib;
				struct List *liblist = &execbase->LibList;
				while(TRUE)
				{
					if (MiamiBase)
					{
						if (MiamiIsOnline("mi0"))
							online = TRUE;
						else
							online = FALSE;
					}
					if (waitconnect)
					{
						if (!MiamiBase)
							MiamiBase = OpenLibrary("miami.library",0);
						if (online)
							waitconnect = FALSE;
						else
						{
							Forbid();
							if (timeoutcounter == 0)
							{
								CloseLibrary(MiamiBase);
								MiamiBase	= 0;
							}
							Permit();
						}
						timeoutcounter--;
					}
					else
					{
						if (!online)
						{
							Forbid();
							if (MiamiBase)
							{
								CloseLibrary(MiamiBase);
								MiamiBase	= 0;
							}
							if (!libadded)
							{
								founded = NULL;
								currentlib = liblist->lh_Head;
								while (!founded && currentlib->ln_Succ)
								{
									if (!strcmp(currentlib->ln_Name, lib_name))
										founded = (struct Library *)currentlib;
									currentlib = currentlib->ln_Succ;
								}
								if (!founded)
								{
									AddLibrary(SocketBase);
									libadded = TRUE;
								}
							}
							Permit();
						}
					}
					Delay(50);
				}
			}
			else
				error = 20;
			CloseLibrary(UtilityBase);
		}
		else
			error = 20;
	}
	else
	{
		printf("bsdsocket.library already opened\n");
		CloseLibrary(SocketBase2);
		error = 20;
	}
	printf("exit\n");
	exit(error);
}




struct Library * __saveds ASM nslib_LibOpen(register __a6 struct Library *MyBase)
{
	Forbid();
	if (!waitconnect && !online)
	{
		Remove((Node *)SocketBase);
		libadded			= FALSE;
		waitconnect		= TRUE;
		timeoutcounter	= 120;
		Permit();
		Execute("run >NIL: miami:miami",0,0);
		
		while (waitconnect && !online)
			Delay(50);
	}
	else
		Permit();
	SocketBase2 = OpenLibrary("bsdsocket.library",0);
	return(SocketBase2);
}








SEGLISTPTR __saveds ASM nslib_LibClose( register __a6 struct Library *MyBase)
{
	SocketBase->lib_OpenCnt--;
	return(NULL);
}




SEGLISTPTR __saveds ASM nslib_LibExpunge( register __a6 struct Library *MyBase)
{
	if (SocketBase->lib_OpenCnt)
		return NULL;

	// bye bye my nice library 

	Remove((Node *)SocketBase);
	libadded = FALSE;
	FreeMem(((char *)SocketBase)-SocketBase->lib_NegSize, SocketBase->lib_NegSize + SocketBase->lib_PosSize);
	return(NULL);
}



ULONG ASM nslib_LibExtfunc(void)
{
	return(NULL);
}



void InsertFunction(APTR base, ULONG Offset, APTR func)
{
	char  *address			= ((char *)base)-Offset;
	char  **func_address  = (char **)(address + 2);
	address[0]=0x4e;
	address[1]=0xf9;
	*func_address = (char *)func;
}



void CreateSocketLibrary()
{
	char *base;
	ULONG negsize = 1000;
	ULONG possize = sizeof(Library) + strlen(lib_name) + strlen(lib_id) + 2;
	
	if ((base = AllocMem(negsize+possize, MEMF_ANY | MEMF_CLEAR)))
	{
		SocketBase = (Library *)(base+negsize);

		InsertFunction(SocketBase,	6,	 nslib_LibOpen);
		InsertFunction(SocketBase,	12, nslib_LibClose);				// -12
		InsertFunction(SocketBase,	18, nslib_LibExpunge);			// -18
		InsertFunction(SocketBase,	24, nslib_LibExtfunc);			// -24
		InsertFunction(SocketBase,	30, nslib_LibExtfunc);			// -30

		SocketBase->lib_Node.ln_Type	= NT_LIBRARY;
		SocketBase->lib_Node.ln_Name	= lib_name;
		SocketBase->lib_pad				= 0;
		SocketBase->lib_NegSize			= negsize;
		SocketBase->lib_PosSize			= possize;
		SocketBase->lib_Flags			= LIBF_CHANGED;
		SocketBase->lib_Version			= LIB_VER;
		SocketBase->lib_Revision		= LIB_REV;
		SocketBase->lib_IdString		= lib_id;

		AddLibrary(SocketBase);
		libadded = TRUE;
	}
	return;
}



void RemoveSocketLibrary(struct Library *lib)
{
	Remove((Node *)SocketBase);
	libadded = FALSE;
//	FreeMem(((char *)SocketBase)-SocketBase->lib_NegSize, SocketBase->lib_NegSize + SocketBase->lib_PosSize);
}









void debug(const char *string, ...)
{
	if (!debug_fh)
	{
		if ((debug_fh = Open("developer:.debug", MODE_READWRITE)))
			SetFileSize(debug_fh, 0, OFFSET_BEGINNING);
	}
	if (debug_fh)
	{
		char *buffer;
		if ((buffer = AllocVec(10000, MEMF_PUBLIC | MEMF_CLEAR)))
		{
			vsprintf(buffer, string, unsigned int(&string + 1));
			Seek(debug_fh, 0, OFFSET_END);
			FPuts(debug_fh, buffer);
			FreeVec(buffer);
		}
	}
}
