/**************************************************/
/*  (c) 1994 by S Leuker, all rights reserved.    */
/*  This source code may be used as a basis for   */
/*  a server managing distributred objects.       */
/*  It is part of nettalkd, the server managing   */
/*  NetTalk clients.                              */
/**************************************************/

#import "NetTalkServer.h"
#import <remote/NXConnection.h>
#include <stdio.h>
#import <machkit/NXPort.h>


@implementation NetTalkServer


- init
{
	[super init];

	clientList = [[List alloc] init];
	channelList = [[List alloc] init];
	connection = [NXConnection registerRoot:self withName:NETTALK];
	[connection registerForInvalidationNotification:self];
	[NXPort worryAboutPortInvalidation];
	
	return self;
}


- run
{
	[connection run];
	return self;
}


- setTimeOut:(float)aTime
{
	timeOut = aTime;
	return self;
}


- (float) timeOut
{
	return timeOut;
}


/*****************************************************************/
/*  Methods from the NTKPserver protocol                         */
/*****************************************************************/


- (id)
		clientList
{
	return clientList;
}


- (id<NTKPserver>)
		addClient:(in id<NTKPclient>)aClient
{
	id connectionToClient;
	
	connectionToClient = [(NXProxy*)aClient connectionForProxy];
	[connectionToClient registerForInvalidationNotification:self];
	[(NXProxy*)aClient setProtocolForProxy:@protocol(NTKPclient)];
	
	[clientList addObjectIfAbsent:aClient];
	[clientList makeObjectsPerform:@selector(newClientNamed:) 
		with:(void*)[aClient uniqueName]];
	[[clientList objectAt:0] setServerStarter:YES];
	return self;
}


- (id<NTKPserver>)
		removeClient:(in id<NTKPclient>)aClient
{
	int    i = 0;
	char  *uName;
	
	if ([clientList indexOf:aClient] == NX_NOT_IN_LIST)
		return nil;
NX_DURING
	uName = (char *)[aClient uniqueName];
NX_HANDLER
	uName = "UNKNOWN@UNKNOWN";
NX_ENDHANDLER

	[clientList removeObject:aClient];
	if (aClient == serverStarter)
	{
		serverStarter = [clientList objectAt:0];
		[serverStarter setServerStarter:YES];
	}
	while (i < [clientList count])
	{
		[(id<NTKPclient>)[clientList objectAt:i++]
			client:uName wantsToDisconnectForCode:"*"];
	}
	return self;
}


- (id<NTKPclient>)
		findClientNamed:(const char *)uName
{
	id   client = nil;
	int  i = 0;
	while (i < [clientList count])
	{
NX_DURING
		if (strcmp([[clientList objectAt:i] uniqueName], uName) == 0)
		{
			client = [clientList objectAt:i];
			i = [clientList count];
		}
		i++;
NX_HANDLER
		[self removeClient:[clientList objectAt:i]];
NX_ENDHANDLER
	}
	return client;
}


- (oneway void) connect:(in id<NTKPclient>)me
		to:(in const char *)uName
		via:(in id)aServerText
		withCode:(in const char *)aCode
		topicIs:(in const char *)aTopic;
{
	[[self findClientNamed:uName]
		client:[me uniqueName]
		sendsVia:aServerText
		forCode:aCode
		topicIs:aTopic];
}


- (oneway void)
		disconnect:(in id<NTKPclient>)me
		from:(in const char *)uName
		forCode:(in const char *)aCode
{
	[[self findClientNamed:uName]
		client:[me uniqueName]
		wantsToDisconnectForCode:aCode];
}

- (oneway void)
		refuseConnection:(in id<NTKPclient>)me
		to:(in const char *)uName
		forCode:(in const char *)aCode
{
	[[self findClientNamed:uName]
		client:[me uniqueName]
		refusesConnectionForCode:aCode];
}


/*****************************************************************/
/*  Methods from the NXSenderIsInvalid protocol                  */
/*****************************************************************/


- (id)
		senderIsInvalid:sender
{
	int         i = 0;
	BOOL        replaceServerStarter = NO;
	
	while (i < [clientList count])
	{
		if ([[(id)[clientList objectAt:i] connectionForProxy] isValid])
			i++;
		else
		{
			if ([clientList objectAt:i] == serverStarter)
				replaceServerStarter = YES;
			[clientList removeObjectAt:i];
		}
	}
	if (replaceServerStarter)
	{
		serverStarter = [clientList objectAt:0];
		[serverStarter setServerStarter:YES];
	}
	return self;
}


/*****************************************************************/
/*  Methods from the NTKPtrading protocol                        */
/*****************************************************************/


- (const char *)hostList
{
	return NULL;
}

- (BOOL)setAlternateHostName:(const char *)hostName
{
	return NO;
}

@end

