/*
 * This Object is the application's delegate. It is responsible for setting
 * itself up as the Delegate for Services requests specific to this
 * application. It interfaces with another object which handles services
 * preferences 
 */

#import "ServicesHandler.h"
#import "MyDelegate.h"
#import <appkit/defaults.h>
#import <appkit/nextstd.h>
#import <appkit/Application.h>
#import <appkit/Listener.h>
#import <appkit/Window.h>
#import <appkit/Pasteboard.h>
#import <soundkit/Sound.h>
#import <sound/sound.h>
#import <NXCType.h>
#import <strings.h>
#import <mach.h>
#import <math.h>				 /* for MAXINT */
#import <vm/vm_user.h>
#import <sys/param.h>				 /* for MAXPATHLEN */
#import <ctype.h>

#define READ_SELECTION 0
#define SPELL_SELECTION 1

@implementation MyDelegate

/**
 **     which-dir -- find the directory for the named exectuable file
 ** Returns malloc'd string if it finds it, or NULL if it can't
 **
 **     Lennart <Lovstrand@EuroPARC.Xerox.COM>, September 1,1991 / January 5, 1992.
 ** slightly modified by sam 910902
 **/
static char *launchDir = NULL; /* if this is NULL, it will be calculated */

const char *which_dir(const char *file)    
{
    static char buf[MAXPATHLEN];
    const char *dirs, *p, *q;

    dirs = getenv("PATH");
    if (dirs == NULL)
        return NULL;

    for (p = q = dirs; *q != '\0'; p = q + 1) {
        q = index(p, ':');
        if (q == NULL)
            q = p + strlen(p);

        sprintf(buf, "%.*s/%s", q - p, p, file);
        if (access(buf, X_OK) == 0)
            return NXUniqueString(buf);
    }

    return NULL;
}

const char *appDirectory()
{
    char buf[MAXPATHLEN];
    char *suffix, *path;

    if (launchDir) return launchDir;
        
    strcpy (buf,NXArgv[0]);
    suffix = rindex(buf,'/');
    if (suffix != NULL)                 // explicit path
    {
        *suffix = '\0';                 // remove executable name
    }
    else
    {
        path = (char *)which_dir([NXApp appName]);
        if (path != NULL)
        {
                launchDir = path;
                return launchDir;
        }
        else
        {
                // Don't know where we came from -- arbitrarily
                // presume "." and continue (it's better than breaking)
                strcpy(buf, ".");
        }
    }

    launchDir = malloc((strlen(buf)+1)*sizeof(char));
    strcpy(launchDir,buf);
    return launchDir;
}


/*
 * this private method does the acoustics 
 */
- speak:(char *)outbuffer
{
    int     i,
            j,
            sndnumber = MAXINT;
    char   *sndname = malloc(7);
    id      sound;
    for (i = 0; ((outbuffer[i] != EOF) && (outbuffer[i] != '\0')); i++)
    {
	j = 0;
	if ((outbuffer[i] == ' ')
	    ||
	    (outbuffer[i] == '\n')
	    ||
	    (outbuffer[i] == '\r'))
	{
	    sndname[j++] = '_';
	}
	else
	if (isupper(outbuffer[i]))
	{
	    sndname[j++] = outbuffer[i++];
	    sndname[j++] = outbuffer[i];
	}
	else
	{
	    sndname[j++] = outbuffer[i];
	}
	sndname[j++] = '.';
	sndname[j++] = 's';
	sndname[j++] = 'n';
	sndname[j++] = 'd';
	sndname[j] = '\0';
#ifdef DEBUG
	printf("sndname:%s\n", sndname);
	sound = [Sound findSoundFor:sndname];
	if (sound == nil)
	    printf("error finding sound\n");
	/* [sound setDelegate:self]; */
	printf("sounds internal name: %s\n",[sound name]);
	/* printf("sndplay error:%i\n",[sound play]); */
	printf("Error:%s\n",SNDSoundError(SNDStartPlaying([sound soundStruct],
			sndnumber,
			sndnumber--,
			0,
			SND_NULL_FUN,
			SND_NULL_FUN)));
	if (sndnumber == 1)
	    sndnumber = MAXINT;
#else
	/* [[[Sound findSoundFor:sndname] setDelegate:self] play]; */
	/* [[Sound findSoundFor:sndname] play]; */
	sound = [Sound findSoundFor:sndname];
	SNDStartPlaying([sound soundStruct],
			sndnumber,
			sndnumber--,
			0,
			SND_NULL_FUN,
			SND_NULL_FUN);
	if (sndnumber == 1)
	    sndnumber = MAXINT;
#endif
    }
    return self;
}
/*
 * private function called from both read and spell 
 */
- doit:pb :(const char *)userData :(char **)errorMessage :(int)opCode
{
    char   *data;
    int     length;
    const char *const * types;
    int     hasAscii,
            i;
    types = [pb types];
    hasAscii = 0;
    for (i = 0; !hasAscii && types[i]; i++)
	if (!strcmp(types[i], NXAsciiPboardType))
	    hasAscii = 1;
    if (hasAscii)
    {
	[pb readType:NXAsciiPboardType data:&data length:&length];
	if (data && length)
	{

	    FILE   *temp,
	           *process;
	    int     i;
	    char    filename[MAXPATHLEN],
	            command[MAXPATHLEN * 2];
	    char   *outbuffer;
#ifdef DEBUG
	    printf("Pasteboard:\n%s\n", data);
#endif
	    outbuffer = calloc((length + 2) * 25,sizeof(char));
	    /*
	     * *2 or * 3 should be enough when reading / spelling resp., but
	     * the results of spelling might be quite a bit bigger. If you have a 
	     * nice way of handling it dynamically, then do it. I'm too lazy... 
	     */
	    if (!opCode)
		{
		    strncpy(outbuffer, data, length);
		    outbuffer[length]='\0';
		}
	    else
	    {
		for (i = 0; i < length; i++)
		{
		    outbuffer[(i * 2) + 0] = data[i];
		    outbuffer[(i * 2) + 1] = ' ';
		    outbuffer[(i * 2) + 2] = '\0';
		}
	    };
	    i = strlen(outbuffer);
	    if (outbuffer[i - 1] != '\n')
	    {
		/*
		 * parse data needs a newline at the end,  add one 
		 */
		outbuffer[i] = '\n';
		outbuffer[i + 1] = '\0';
	    }
#ifdef DEBUG
	    printf("Outbuffer before parse:\n%s\n", outbuffer);
#endif
	    /*
	     * Make a temporary file to give to parse 
	     */
	    strcpy(filename, "/tmp/file000000Selection");
	    NXGetTempFilename(filename, 9);
	    temp = fopen(filename, "w");
	    fprintf(temp, outbuffer);
	    fclose(temp);
	    /*
	     * Call parse using popen(),  The userData supplied has the
	     * arguments for Sort (see "services" file). 
	     */
#ifdef DEBUG
	    printf("parse command: %s/parse %s\n", appDirectory(), filename);
#endif
	    sprintf(command, "%s/parse %s\n", appDirectory(), filename);
	    process = popen(command, "r");

	    for (i = 0; ((outbuffer[i] = getc(process)) != EOF); i++);
	    outbuffer[i + 1] = '\0';
	    unlink(filename);
	    pclose(process);
#ifdef DEBUG
	    printf("Outbuffer after parse:\n%s\n", outbuffer);
#endif
	    /*
	     * here goes the talking of the outbuffer 
	     */
	    [self speak:outbuffer];
	}
	else
	    *errorMessage = "No data in your selection.";
    }
    else
	*errorMessage = "No ASCII text found in your selection.";
    return self;
}

/*
 * Setup Services Delegate and Initialize Preferences Panel 
 */

- appDidInit:sender
{
    [[NXApp appListener] setServicesDelegate:self];

    [servicesHandler prefSetup:self];
    return self;
}
- read:pb userData:(const char *)userData error:(char **)errorMessage
{
    [self doit:pb :userData :errorMessage :READ_SELECTION];
    [NXApp deactivateSelf];
    return self;
}
- spell:pb userData:(const char *)userData error:(char **)errorMessage
{
    [self doit:pb :userData :errorMessage :SPELL_SELECTION];
    [NXApp deactivateSelf];
    return self;
}
@end
