#import "NetTalkThinker.h"
#import "NetTalkClient.h"
#import "OpenTalk.h"
#import "TalkController.h"
#import <appkit/appkit.h>

#define		NXLS(bla) NXLocalizedString(bla, 0, 0)
#define   COCA const char *

@implementation NetTalkThinker(Connecting)

- connect:sender
{
	const char            *aClientUName;
	TalkRequest           *aRequest;
	const char            *realUserName;
	View<NTKPclientview>  *newClientView;
	TalkController        *controller = nil;
	Window                *talkWindow;
	
	if ([requestBrowser selectedCell] == nil)
		return 0;
	aRequest = [requestList objectAt:
		[[requestBrowser matrixInColumn:0] selectedRow]];
	aClientUName = [aRequest requestUName];
	realUserName = [[[client server] findClientNamed:aClientUName] realUserName];
	if (talkWindow = [self connectionForTopic:[aRequest requestTopic]])
	{
//		if (NXRunLocalizedAlertPanel)   << Ask for permission >>
		controller = [talkWindow delegate];
	}
	if (!controller)
		controller = [[self controllerClassFor:
			[[[aRequest requestDocument] class] name]] newFromNib];
	if (controller)
	{
		[controller setup];
		[controller markClientUNameInvited:aClientUName
			forCode:[aRequest requestCode]];
		[controller setTopic:[aRequest requestTopic]];
		newClientView = [controller addClientViewWith:[aRequest requestDocument]
			from:aClientUName forCode:[aRequest requestCode]];
		[newClientView setUserName:realUserName];
		[client
			sendConnectTo:aClientUName
			via:[controller document]
			withCode:[aRequest requestCode]
			topicIs:[aRequest requestTopic]];
		[requestList removeObject:aRequest];
		[aRequest free];
		[requestBrowser reloadColumn:0];
		[self setRequest:nil];
	}
	else
	{
		NXRunLocalizedAlertPanel(NULL
			, "Alert", "CouldNotEstablishConnection"
			, "OK", NULL, NULL);
	}
	return self;
}

- insert:sender
{
	const char            *aClientUName;
	TalkRequest           *aRequest;
	const char            *realUserName;
	View<NTKPclientview>  *newClientView;
	TalkController        *controller;
	
	if ([requestBrowser selectedCell] == nil)
		return 0;
	aRequest = [requestList objectAt:
		[[requestBrowser matrixInColumn:0] selectedRow]];
	aClientUName = [aRequest requestUName];
	realUserName = [[[client server] findClientNamed:aClientUName] realUserName];
	controller = [[NXApp mainWindow] delegate];
	if ([controller isKindOf:[TalkController class]])
	{
		newClientView = [controller
			addClientViewWith:[aRequest requestDocument]
			from:aClientUName forCode:[aRequest requestCode]];
		[newClientView setUserName:realUserName];
		[client
			sendConnectTo:aClientUName
			via:[controller document]
			withCode:[aRequest requestCode]
			topicIs:[controller topic]];
		[requestList removeObject:aRequest];
		[aRequest free];
		[requestBrowser reloadColumn:0];
		[self setRequest:nil];
	}
	return self;
}

- refuse:sender
{
	const char   *aClientUName;
	TalkRequest  *aRequest;
	
	if ([requestBrowser selectedCell] == nil)
		return 0;
	aRequest = [requestList objectAt:
		[[requestBrowser matrixInColumn:0] selectedRow]];
	aClientUName = [aRequest requestUName];
	[client sendRefuseTo:aClientUName forCode:[aRequest requestCode]];
	[requestList removeObject:aRequest];
	[aRequest free];
	[requestBrowser reloadColumn:0];
	[self setRequest:nil];
	
	return self;
}


- (Window *) connectionFor:(COCA)aClientUName andCode:(COCA)aCode
{
	id   window = nil;
	int i = [[NXApp windowList] count];
	
	while (i-- > 0)
	{
		window = [[NXApp windowList] objectAt:i];
		if ([[window delegate] isKindOf:[TalkController class]])
		{
			if ([[window delegate] hasClientUName:aClientUName andCode:aCode])
				i = 0;
			else
				window = nil;
		}
		else
			window = nil;
	}
	return window;
}


- (Window *)connectionForTopic:(COCA)aTopic
{
	id      window = nil;
	int     i = [[NXApp windowList] count];
	COCA    topic;
	
	while (i-- > 0)
	{
		window = [[NXApp windowList] objectAt:i];
		if ([[window delegate] isKindOf:[TalkController class]])
		{
			topic = [[window delegate] topic];
			if ((topic) && (strcmp(topic, aTopic) == 0))
				i = 0;
			else
				window = nil;
		}
		else
			window = nil;
	}
	return window;
}

- (TalkRequest *)requestFromUName:(COCA)uName forCode:(COCA)aCode
{
	TalkRequest  *request = nil;
	int     i = [requestList count];
	BOOL    codesMatch;
	COCA    requestCode;
	
	while (i-- > 0)
	{
		request = [requestList objectAt:i];
		requestCode = [request requestCode];
		if (aCode)
		{
			codesMatch = ((requestCode) && (strcmp(requestCode, aCode) == 0));
		}
		else
			codesMatch = YES;
		if (codesMatch && (strcmp([request requestUName], uName) == 0))
				i = 0;
		else
				request = nil;
	}
	return request;
}

- (const char *) realNameFor:(COCA)aClientUName
{
	return [[[client server] findClientNamed:aClientUName] realUserName]; 
}

@end

@implementation NetTalkThinker(OpenTalkDelegate)

- (int)getClientCount
{
	int   count;
NX_DURING
	count = [[[client server] clientList] count];
NX_HANDLER
	count = 0;
NX_ENDHANDLER
	return count;
}

- (int)getClientName:(char*)cName at:(int)pos
{	
	id           peer;
	const char  *realName;
	
NX_DURING
	if ((pos < 0) || (pos >= [[[client server] clientList] count]))
		return NT_NOCLIENT;
	peer = [[[client server] clientList] objectAt:pos];
	realName = [peer clientName];
	strcpy(cName, realName);
	if (peer != client)
		free((char*)realName);
NX_HANDLER
	strcpy(cName, NXLS("Invalid"));
	return 0;
NX_ENDHANDLER
	return (peer != client);
}

- (int)getUniqueName:(char*)aClientUName at:(int)pos
{	
	id      peer;
	COCA    uName;
	
NX_DURING
	if ((pos < 0) || (pos >= [[[client server] clientList] count]))
		return NT_NOCLIENT;
	peer = [[[client server] clientList] objectAt:pos];
	uName = [peer uniqueName];
	strcpy(aClientUName, uName);
	if (peer != client)
		free((char *)uName);
NX_HANDLER
	strcpy(aClientUName, NXLS("Invalid"));
	return 0;
NX_ENDHANDLER
	return (strcmp(aClientUName, [client uniqueName]) != 0);
}

@end


@implementation NetTalkThinker(NetTalkClientDelegate)

- (id) updateClientData
{
	if (openTalkPanel)
		[openTalkPanel rescan:nil];
	return self;
}

- (id) handleDisconnectFrom:(COCA)aClientUName forCode:(COCA)aCode
{
	TalkRequest  *aRequest;
	
	fprintf(stderr, "NetTalk: Disconnecting from %s for %s.\n", aClientUName, aCode);
	
	if (openTalkPanel)
		[openTalkPanel rescan:nil];
	if ((aCode) && (strcmp(aCode, "*") == 0))
		aCode = NULL;
	while (aRequest = [self requestFromUName:aClientUName forCode:aCode])
	{
		[requestList removeObject:aRequest];
		[aRequest free];
	}
	[requestBrowser reloadColumn:0];
	[self setRequest:nil];
	return self;
}

- (id) handleRefuseFrom:(COCA)aClientUName forCode:(COCA)aCode
{
	id    window;
	
	window = [self connectionFor:aClientUName andCode:aCode];
	if (window)
	{
		const char  *userName;
		userName = [[[client server] findClientNamed:aClientUName] realUserName];
		if (!userName) userName = aClientUName;
		NXRunLocalizedAlertPanel(NULL
			, "ConnectionRefused", "ConnectionRefused-1-User", "OK", 0, 0
			, userName);
		[[[window delegate]
			viewForClientUName:aClientUName andCode:aCode]
			freeDocument:self];
	}
	return self;
}

- (id) handleConnectFrom:(COCA)aClientUName via:aDocument
		withCode:(COCA)aCode topicIs:(COCA)aTopic
{
	id    window = nil;
	id    controller;
	
	window = [self connectionFor:aClientUName andCode:aCode];
	if (window)
	{
		controller = [window delegate];
		if ([controller viewForClientUName:aClientUName
			andCode:aCode] != controller)
			return self;
		if (aTopic)
		{
			if ([controller topic])
			{
				if (strcmp(aTopic, [controller topic]) != 0)
				{
					switch(NXRunLocalizedAlertPanel(NULL
						, "Attention"
						, "TopicChange-3-Name-Old-New"
						, "OK", "Keep", "Refuse"
						, [self realNameFor:aClientUName], [controller topic], aTopic))
					{
						case NX_ALERTDEFAULT:
							[controller setTopic:aTopic];
							break;
						case NX_ALERTALTERNATE:
							window = nil;
							break;
						case NX_ALERTOTHER:
							[client sendRefuseTo:aClientUName forCode:aCode];
							return nil;
							break;
					}
				}
			}
			else
				window = nil;
		}
		else
			window = nil;
	}
	if (window)
	{
		View<NTKPclientview> *newClientView;
		
		newClientView = [[window delegate]
			addClientViewWith:aDocument from:aClientUName forCode:aCode];
		[newClientView setUserName:[self realNameFor:aClientUName]];
		[client
			sendConnectTo:aClientUName
			via:[(TalkController *)[window delegate] document]
			withCode:aCode
			topicIs:aTopic];
	}
	else
	{
		if (![self requestFromUName:aClientUName forCode:aCode])
		{
			TalkRequest *newRequest;
			
			[self newRequest:nil];
			newRequest = [[TalkRequest alloc]
				initFor:aDocument
				from:aClientUName
				code:aCode
				topicIs:aTopic];
			[requestList addObject:newRequest];
			[requestBrowser reloadColumn:0];
		}
	}
	return self;
}

@end

