#import <stdio.h>
#import <stdlib.h>
#import <libc.h>
#import <sys/ioctl.h>
#import <mach.h>
#import <appkit/defaults.h>
#import <appkit/Application.h>
#import <dpsclient/dpsclient.h>
#import "BlackHand.h"
#import "EtermSupport.h"
#import "etermSupport.h"

extern char **environ;

extern void kc_init(void);

/*
 * write(2), except it will keep retrying upon partial success.
 */
static int write_safely(int fd, char *buf)
{
    int i, start = 0, n;
    
    n = strlen(buf);

    while (start < n) {
	i = write(fd, buf+start, n - start);
	if (i == -1) return i; /* Some error */
	start += i;
    }
    return n;
}

/*
 * Handle a connection to the event server socket
 */
static void connection_from_apps(int fd, void *rock)
{
    BlackHand *handle = (BlackHand *)rock;
    int newfd = accept_server_connection(fd);

    if (newfd == -1) return;

    if ([handle eventChannel]) {
	close(newfd);
    }
    else {
	[handle setEventChannel: fdopen(newfd, "w")];
    }
}

@implementation BlackHand

+ initialize
{
    static NXDefaultsVector etermDefaults = {
	{"NXAutoLaunch", "NO" },
	{"NXFixedPitchFont", "Ohlfs" },
	{"NXFixedPitchFontSize", "10" },
	{"Columns", "80" },
	{"Rows", "24" },
	{"WinLocX", "205"},
	{"WinLocY", "85"},
	{"HideOnAutoLaunch", "NO" },
	{NULL}
    };

    NXRegisterDefaults(AppsName, etermDefaults);
    kc_init();
    
    return self;
}

- (FILE *)eventChannel;
{
    return eventChannel;
}

- setEventChannel: (FILE *)fp;
{
    eventChannel = fp;
    return self;
}


// Start up the child apps process

- startApps;
{
    int master, slave, portno;
    char **env;
    static char *args[] = 
	{
	ProgName,
	NULL,
	NULL
	};
  
    /* Grab a pty/tty pair */
    create_channel (&master, &slave);
    masterChannel = master;

    /* Create the server socket */
    eventServerSocket = create_server_socket(&portno);
    DPSAddFD(eventServerSocket, connection_from_apps, (void *)self, NX_RUNMODALTHRESHOLD);

    /* Frob the environment */
    env = patch_env(environ, portno);

// get the application arguments. NOT IMPLEMENTED YET
    
    /* Fork off the Apps */
    fork_shell(ProgName, args, env, slave);
    (void) close(slave);

    DPSAddFD(master, input_from_apps, new_display_rock(deputy), NX_RUNMODALTHRESHOLD);

    return self;
}

- requestFromDeputy:(char *)request;
{
    write_safely(masterChannel, request);

    return self;
};

- quitApps
{
    if (!eventChannel) return nil;
    fprintf(eventChannel, "(event-quit)\n");
    fflush(eventChannel);
    return self;
}

@end
