// Server for vending an object either trhough a NSMessagePort or NSSocketPort

#import <Foundation/Foundation.h>
#import "Protocol.h"

// configure ------

BOOL loopback=NO;	// use a single socket for sending and receiving, otherwise compile as Zaurus-Server and Mac-Client
BOOL useSocket=YES;	// if YES, use NSSocketPort, if NO, use NSMessagePort

#ifdef __mySTEP__
#define client NO	/* make Zaurus a Server */
#else
#define client YES	/* make Mac a Client */
#endif

// end configure ------

@interface MyClass : NSObject <MyServer>
@end

@implementation MyClass

- (NSString *) method;
{
	NSLog(@"client calls -[MyClass method]");
	return @"this is the instance of MyClass";
}
- (bycopy NSString *) method2:(byref NSString *) arg;
{
	NSLog(@"client calls -[MyClass method2:%@]", arg);
	NSLog(@"Arg class:%@", NSStringFromClass([arg class]));
	return @"result bycopy";
}

@end

@interface PortDelegate : NSObject
// - (void)handlePortMessage:(NSPortMessage *)portMessage;
@end

@implementation PortDelegate

- (void) invalidated:(NSNotification *) n
{
	NSLog(@"invalidated NSPort: %@", [n object]);
}

#if 0

- (void) handleMachMessage:(void *) msg;
{
	NSLog(@"received MachMessage: %@", [NSData dataWithBytes:msg length:64]);
}

#else

- (void) handlePortMessage:(NSPortMessage *)portMessage;
{
	static int cnt;
	BOOL b;
	NSSocketPort *s;
//	NSLog(@"runloop: %@", [NSRunLoop currentRunLoop]);
	NSLog(@"received NSPortMessage: %@", portMessage);
	NSLog(@"  runloop mode: %@", [[NSRunLoop currentRunLoop] currentMode]);
	NSLog(@"  msgid: %u", [portMessage msgid]);
	s=[portMessage sendPort];
	NSLog(@"  send: %p, %@, %@", s, s, NSStringFromClass([s class]));
		  // is the port we should send the response to - this is DIFFERENT from the port created in main()
	NSLog(@"    address=%@", [s address]);
	NSLog(@"    protocol=%d", [s protocol]);
	NSLog(@"    protocolFamily=%d", [s protocolFamily]);
	NSLog(@"    socket=%d", [s socket]);
	NSLog(@"    socketType=%d", [s socketType]);
	NSLog(@"    delegate=%@", [s delegate]);
	NSLog(@"    reservedSpaceLength=%d", [s reservedSpaceLength]);
	s=[portMessage receivePort];
	NSLog(@"  recv: %p, %@", s, s);	// is the originating port
	NSLog(@"    address=%@", [s address]);
	NSLog(@"    protocol=%d", [s protocol]);
	NSLog(@"    protocolFamily=%d", [s protocolFamily]);
	NSLog(@"    socket=%d", [s socket]);
	NSLog(@"    socketType=%d", [s socketType]);
	NSLog(@"    delegate=%@", [s delegate]);
	NSLog(@"    reservedSpaceLength=%d", [s reservedSpaceLength]);
	NSLog(@"  comp: %@", [portMessage components]);
	[(NSMutableArray *) [portMessage components] addObject:[@"3" dataUsingEncoding:NSUTF8StringEncoding]];	// mutable - yes
	if(cnt++ < 3)
		{
		b=[portMessage sendBeforeDate:[NSDate dateWithTimeIntervalSinceNow:10.0]];	// send back
		if(!b)
			NSLog(@"send failed");
		}
	else
		NSLog(@"no more replys");
}

#endif

@end

int main(int argc, const char *argv[])
{
	NSAutoreleasePool *arp=[NSAutoreleasePool new];
#if 0
	{
	PortClass *p=[[PortClass new] autorelease];	// create new port
	NSConnection *c=[NSConnection connectionWithReceivePort:p sendPort:p];
	NSLog(@"started");
	NSLog(@"connection %@", c);
	[c setRootObject:[MyClass new]];	// vend some object
	NSLog(@"root object: %@", [c rootObject]);
	[c registerName:@"fexpserver" withNameServer:[NameServerClass sharedInstance]];
	NSLog(@"registered as fexpserver");
	NSLog(@"connections %@", [NSConnection allConnections]);
	}
#endif
#if 1
	{ // simple NPort tests
		BOOL b;
		NSPort *send;
		NSPort *recv;
		if(useSocket)
			{
			if(loopback)
				send=[[NSSocketPort alloc] initWithTCPPort:4550];	// run as a server
			else if(client)
				send=[[NSSocketPort alloc] initRemoteWithTCPPort:4551 host:@"192.168.129.201"];	// run as client connecting the server
			else
				{
				send=[[NSSocketPort alloc] initWithTCPPort:4551];	// run as a server and publish
#ifdef __mySTEP__
		//		[[NSPortNameServer systemDefaultPortNameServer] registerPort:send name:@"port"];	// this blocks for 1.0 seconds for socketports (due to ZeroConf publishing)
#endif
				}
			[send setDelegate:[PortDelegate new]];
			[[NSNotificationCenter defaultCenter] addObserver:[send delegate] selector:@selector(invalidated:) name:NSPortDidBecomeInvalidNotification object:nil];
			if(loopback)
				recv=send;
			else
				{
				recv=[[NSSocketPort alloc] initWithTCPPort:4551];	// use a second port to receive from (cache should map both)
				[recv setDelegate:[send delegate]];
				[[NSNotificationCenter defaultCenter] addObserver:[recv delegate] selector:@selector(invalidated:) name:NSPortDidBecomeInvalidNotification object:nil];
				}
			[recv scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];	// listen on otherport for incoming connection and data
			}
		else
			{
			if(loopback)
				send=[[NSMessagePort alloc] init];
			else if(client)
				send=[[NSMessagePortNameServer sharedInstance] portForName:@"port"];
			else
				{
				send=[[NSMessagePort alloc] init];
#ifdef __mySTEP__
				[[NSPortNameServer systemDefaultPortNameServer] registerPort:send name:@"port"];	// this blocks for 1.0 seconds for socketports (due to ZeroConf publishing)
#endif
				}
			if(loopback)
				recv=send;
			else
				recv=[[NSMessagePort alloc] init];	// use a second port to receive from
			}
#if 0
		{ // try to connect the same again - does this return the same or a different NSSocketPort? Answer: There is a Cache!
		NSPort *again=[[NSSocketPort alloc] initRemoteWithTCPPort:4550 host:@"localhost"];	// fails! i.e. from can only be a local port
		NSLog(@"again=%@ %p", again, again);
		NSLog(@" again=%@", [again address]);
		}
#endif
		NSLog(@"send=%@ %p", send, send);
#if 0
		NSLog(@" address=%@", [send address]);
		NSLog(@" protocol=%d", [send protocol]);
		NSLog(@" protocolFamily=%d", [send protocolFamily]);
		NSLog(@" socket=%d", [send socket]);
		NSLog(@" socketType=%d", [send socketType]);
		NSLog(@"recv=%@ %p", recv, recv);
		NSLog(@" address=%@", [recv address]);
#endif

		NSLog(@"delegate=%@", [recv delegate]);
		NSLog(@"reservedSpaceLength=%d", [send reservedSpaceLength]);
		if(client)
			{
			b=[send sendBeforeDate:[NSDate dateWithTimeIntervalSinceNow:10.0]
						 msgid:12
					components:[NSMutableArray arrayWithObjects:
						[@"123" dataUsingEncoding:NSUTF8StringEncoding],
						[NSData data],	// empty component
						[@"987654321" dataUsingEncoding:NSUTF8StringEncoding],
//						send,
//						recv,
					//	[[NSMessagePort alloc] init],	// sending a NSMessagePort through an NSSocketPort doesn't work on MacOS X
						nil]
						  from:recv	// must not be nil or it fails!
					  reserved:100];
			if(!b)
				NSLog(@"send failed");
			else
				NSLog(@"did send");
			}
	}
#endif	
	NSLog(@"running loop in default mode");
	[[NSRunLoop currentRunLoop] run];
	NSLog(@"loop done");
	[arp release];
	exit(0);
}
