	/*
	  Copyright (c) 1990, Scott Hess.  No rights reserved.  No
	  warrenty is provided for this software, neither explicit
	  nor implied.  The source and object code for this file
	  may be used and modified as the user sees fit.
	*/

#import <appkit/Listener.h>
#import "StuartSpeaker.h"
#import <mach/mach.h>
#import <mach/message.h>
#import <servers/netname.h>
#import <string.h>
#import <stdio.h>
#import <stdlib.h>
#import <math.h>
#import <libc.h>

extern port_t name_server_port;
extern id NXResponsibleDelegate();

@implementation  StuartSpeaker :Speaker
{
  int nDefaults;		// The number of defaults.
  StuartDefault *defaults;	// defaults/values for the new Stuart.
  
  BOOL activate;		// activate Stuart when we call?
  char *host;			// host to run on.
}

+ new
{
  self=[super new];
  nDefaults=0;
  defaults=NULL;
  host=NULL;
  activate=YES;
  return self;
}
- free
{
  free( defaults);
  return [super free];
}

-(int)_stuartNew:(char *)defs activate:(int)flag
{
  return [self selectorRPC:"_stuartNew:activate:" paramTypes:"ci", defs, flag];
}

-(int)_stuartGet:(char **)defs
{
  return [self selectorRPC:"_stuartGet:" paramTypes:"C", defs];
}

static const char *sValue;		// a temp variable.

static char buffer[ 1024];

const char *itoa( int i)
{
  sprintf( buffer, "%d", i);
  return buffer;
}
const char *ftoa( float f)
{
  sprintf( buffer, "%f", f);
  return buffer;
}
const char *btoa( BOOL b)
{
  sprintf( buffer, "%s", b ? "YES" : "NO");
  return buffer;
}
BOOL atob( const char *s)
{
  if( !strcmp( s, "YES"))
    return YES;
  else if( !strcmp( s, "NO"))
    return NO;
  else
    return atoi( s);
}

-(const char *)default:(const char *)name
{
  int i=nDefaults;
  while( i--)
    if( !strcmp( defaults[ i].defName, name))
      return defaults[ i].defValue;
  return NULL;
}
-(int)defaultAsInt:(const char *)name
{
  return (sValue=[self default:name]) ? atoi( sValue) : 0;
}
-(float)defaultAsFloat:(const char *)name
{
  return (sValue=[self default:name]) ? atof( sValue) : NAN;
}
-(BOOL)defaultAsBOOL:(const char *)name
{
  return (sValue=[self default:name]) ? atob( sValue) : NO;
}
- default:(const char *)name as:(const char *)value
{
  int i=nDefaults;
  while( i--)
    if( !strcmp( defaults[ i].defName, name))
      {
        defaults[ i].defValue=realloc((char *)defaults[ i].defValue, strlen( value)+1);
	strcpy((char *)defaults[ i].defValue, value);
	return self;
      }
  defaults=realloc((char *)defaults, (++nDefaults)*sizeof( struct _StuartDefault));
  defaults[ nDefaults-1].defValue=malloc( strlen( value)+1);
  strcpy((char *)defaults[ nDefaults-1].defValue, value);
  defaults[ nDefaults-1].defName=malloc( strlen( name)+1);
  strcpy((char *)defaults[ nDefaults-1].defName, name);
  return self;
}
- default:(const char *)name asInt:(int)value
{
  return [self default:name as:itoa( value)];
}
- default:(const char *)name asFloat:(float)value
{
  return [self default:name as:ftoa( value)];
}
- default:(const char *)name asBOOL:(BOOL)value
{
  return [self default:name as:btoa( value)];
}

-(int)stuartNew
{
  int i, size=0;
  char *defs, *pos;
  for( i=nDefaults; i--;)
    size+=strlen( defaults[ i].defName)+strlen( defaults[ i].defValue)+2;
  pos=defs=malloc( size+1);
  for( i=nDefaults; i--;)
    {
      strcpy( pos, defaults[ i].defName);
      strcat( pos, "=");
      strcat( pos, defaults[ i].defValue);
      pos+=strlen( pos);
      *pos++='\n';
    }
  *pos++=0;			// double-null at the end.
  i=[self _stuartNew:defs activate:activate];
  free( defs);
  return i;
}
-(int)stuartGet
{
  int i;
  char *defs, *pos;
  i=[self _stuartGet:&defs];
  if( i)
    return i;
  while( *defs)
    {
      if( pos=index( defs, '='))
        {
	  *pos++=0;
	  [self default:defs as:pos];
	  *--pos='=';
	}
      else
        [self default:defs as:""];
      defs+=strlen( defs)+1;
    }
  return 0;
}
-(int)stuartSend:(int)fd
{
  NXStream *s=NXOpenMemory( NULL, 0, NX_WRITEONLY);
  char buffer[ 1024];
  int ret, len;
  char *buf;
  while( (ret=read( fd, buffer, 1024))>0)
    NXWrite( s, buffer, ret);
  NXPutc( s, 0);
  NXGetMemoryBuffer( s, &buf, &len, &ret);
  ret=[self _stuartNew:buf activate:activate];
  NXCloseMemory( s, NX_FREEBUFFER);
  return ret;
}
-(int)stuartConnectAndNew
{
  int ret=-1;
  port_t stuartPort=NXPortFromName( "Stuart", host);
  if( stuartPort!=PORT_NULL)
    {
      [self setSendPort:stuartPort];
      ret=[self stuartNew];
      port_deallocate( task_self(), stuartPort);
    }
  else
    fprintf( stderr, "Stuart not running\n");
  return ret;
}
-(int)stuartConnectAndGet
{
  int ret=-1;
  port_t stuartPort=NXPortFromName( "Stuart", host);
  if( stuartPort!=PORT_NULL)
    {
      [self setSendPort:stuartPort];
      ret=[self stuartGet];
      port_deallocate( task_self(), stuartPort);
    }
  else
    fprintf( stderr, "Stuart not running\n");
  return ret;
}
-(int)stuartConnectAndSend:(int)fd
{
  int ret=-1;
  port_t stuartPort=NXPortFromName( "Stuart", host);
  if( stuartPort!=PORT_NULL)
    {
      [self setSendPort:stuartPort];
      ret=[self stuartSend:fd];
      port_deallocate( task_self(), stuartPort);
    }
  else
    fprintf( stderr, "Stuart not running\n");
  return ret;
}

-(BOOL)activate
{
  return activate;
}
- setActivate:(BOOL)flag
{
  activate=flag;
  return self;
}
-(const char *)host
{
  return host;
}
- setHost:(const char *)h
{
  if( h==NULL)
    free( host), host=NULL;
  else
    host=strcpy( realloc( host, strlen( h)+1), h);
  return self;
}

@end

