/* Controller.m -- Controller object for MailHelper application.
   Copyright 1991, Izumi Ohzawa and Manuel Alberto Ricart, All rights reserved.
   3-17-91  V1.0 (IO)
	* Starting project.
	* Some codes are borrowed from AtYourService NeXT demo application.
   4-6-91   V1.0 (IO)
	* Bug fix: fclose(fpin); was missing in method insertSignature.
   9-18-91  V1.1 (MAR)
	* Preferences panel and use of default database to store them.
	    Joint venture with Izumi? Perhaps.  Izumi sent me his code
	    for MailHelper.  I told him I implement some basic prefs for him.
   9-22-91  V1.1 (IO)
	* Defaults now written out as soon as OK button in Pref panel is pressed.
	* Signature insertion now adds a separator '---' within the code to
	    remove requirement of having it in signature file itself (to make MailHelper
	    conform with other programs which use .signature).
	* RTF signature insertion added.

   9-29-91 V1.1 (VD)   		<vince@whatnxt.cuc.ab.ca>
        * Added several methods to set and retrive the default settings of the Control
	    object

   To implement:
   Gray-out RTF quoting if RTF text is found on pasteboard.
   User selectable command keys for various functions.

*/


#import "Controller.h"
#import <appkit/Application.h>
#import <appkit/Listener.h>
#import <appkit/Pasteboard.h>
#import <appkit/defaults.h>

#import <stdlib.h>
#import <strings.h>
#import <mach_init.h>
#import <vm/vm_user.h>
#import <sys/stat.h>


@implementation Controller

- init
{
    self = [super init];
    [self setQuoteString: (char *)NXGetDefaultValue([NXApp appName],"Quote")];
    [self setSigFile:     (char *)NXGetDefaultValue([NXApp appName],"Sigfile")];
    [self setRtfSigFile:  (char *)NXGetDefaultValue([NXApp appName],"Rtfsigfile")];
    [self setWrapWidth:   atoi((char *)NXGetDefaultValue([NXApp appName],"Width"))];

    return self;
}

- setQuoteString:(char *)string
{
    strcpy(quoteString,string);
    return self;
}

- (char *)quoteString
{
    return quoteString;
}

- setSigFile:(char *)string
{
    strcpy(sigFile,string);
    return self;
}
- (char *)sigFile
{
    return sigFile;
}

- setRtfSigFile:(char *)string
{
    strcpy(rtfSigFile,string);
    return self;
}
- (char *)RtfSigFile
{
    return rtfSigFile;
}

- setWrapWidth:(int)value
{
    wrapWidth = value;
    return self;
}

- (int)wrapWidth
{
    return wrapWidth;
}

/* Reformats selected text so that it fits into a specified column width.
 * Alberto's Modifications:
 * initialized colLimit to wrapWidth global variable.
*/

- reformatSelection:(id)pbid userData:(const char *)udata error:(char **)errmsg
{
    char *data; 
    int   length;
    const char *const *types;
    int   hasAscii, i;
    int   column=1, nextcolumn=1, colLimit=wrapWidth;

    types = [pbid types];		/* get a list of pasteboard types */
    hasAscii = 0;
    for(i=0; !hasAscii && types[i]; i++)
	if(!strcmp(types[i], NXAsciiPboardType)) hasAscii = 1;
    if(hasAscii){
	[pbid readType:NXAsciiPboardType data:&data length:&length];
	if(data && length){

	    char *returnData, *dataptr, *endptr;
	    char *wordptr, *nextwordptr;
            
	    returnData=malloc(length+10);
	    dataptr = strncpy(returnData, data, length);
	    wordptr = nextwordptr = dataptr;
	    endptr = dataptr+length;
	    for (i=1;i<=length;i++){   /* remove all line breaks execpt doubles */

		if((*dataptr == '\n') && (*(dataptr+1) == '\n')){

		    dataptr += 2;
		    continue;
		}else 
		    if(*dataptr == '\n')
		    	*dataptr = ' ';	    
		dataptr++;
	    }

	    column = nextcolumn = 1;
	    while(nextwordptr < endptr){
		while((wordptr < endptr) && (*wordptr != ' ') && (*wordptr != '\n')){
		    wordptr++;
		    column++;
		}
		/* on exit from above while(), wordptr should still be at ' ' or '\n' */
		if(*wordptr++ == '\n'){
		    column = nextcolumn = 1;
		    continue;
		}    
		nextwordptr = wordptr;
		nextcolumn = column;
		while((nextwordptr < endptr) && (*nextwordptr != ' ') && (*nextwordptr != '\n')){
		    nextwordptr++;
		    nextcolumn++;
		}
		if(nextcolumn >= colLimit){
		    *(wordptr-1) = '\n';
		    column = nextcolumn =1;
		}
	    }
	    *endptr= '\n';
	    *(endptr+1) = '\0';
	    [pbid declareTypes:&NXAsciiPboardType num:1 owner:self];
	    [pbid writeType:NXAsciiPboardType data:returnData length:strlen(returnData)];
	    free(returnData);
	} else { /* end if(data && length) */
	    *errmsg = "Selection is empty.";
	    fprintf(stderr,"SpotLight: Selection is empty.\n");
	}
	vm_deallocate(task_self(), data, length);
    }else {   /* end if(hasAscii) */
	*errmsg = "No ASCII text found in your selection.";
	fprintf(stderr,"SpotLight: No ASCII text found in your selection.\n");
    }
    return self;
}

/* Adds quotation marks "> " to the head of each line of selected text.
 * Alberto's Modification:
 * Only changed the definition of quotestr to point to the quoteString global.
*/

- quoteSelection:(id)pbid userData:(const char *)udata error:(char **)errmsg
{
    char *data; 
    int   length;
    const char *const *types;
    char *quotestr = quoteString;
    int   hasAscii, i, quotelen;

    quotelen = strlen(quotestr);
    types = [pbid types];		/* get a list of pasteboard types */
    hasAscii = 0;
    for(i=0; !hasAscii && types[i]; i++)
	if(!strcmp(types[i], NXAsciiPboardType)) 
	    hasAscii = 1;
    if(hasAscii){
	[pbid readType:NXAsciiPboardType data:&data length:&length];
	if(data && length){
	    int numlines;
	    char ch;
	    char *returnData, *dataptr, *endptr, *outptr;

	    numlines = 1;
	    dataptr = data;		  /* ptr to original data */
	    endptr = data+length;	  /* ptr to end of data */

	    while(dataptr < endptr)   /* count the number of lines */
		if(*dataptr++ == '\n')
		    numlines++;
	    returnData=malloc(length+numlines*quotelen+10);
	    dataptr = data;		  /* reinitialize ptr to orig data */
	    outptr = returnData;
	    for(i=0;i<quotelen;i++)
		*outptr++ = quotestr[i];
	    while(dataptr < endptr){
		if((ch = *dataptr++) == '\n'){
		    *outptr++ = ch;
		    for(i=0;i<quotelen;i++)
			*outptr++ = quotestr[i];
		}else
		    *outptr++ = ch;
	    }
	    *outptr = '\n';
	    *(outptr+1) = '\0';
	    [pbid declareTypes:&NXAsciiPboardType num:1 owner:self];
	    [pbid writeType:NXAsciiPboardType data:returnData length:strlen(returnData)];
	    free(returnData);
	} else{ /* end if(data && length) */
	    *errmsg = "Selection is empty.";
	    fprintf(stderr,"SpotLight: Selection is empty.\n");
	}
	vm_deallocate(task_self(), data, length);
    }else{ /* end if(hasAscii) */
	*errmsg = "No ASCII text found in your selection.";
	fprintf(stderr,"SpotLight: No ASCII text found in your selection.\n");
    }
    return self;
}


// Adds the content of ~/.signature at the current cursor location.

- insertSignature:(id)pbid userData:(const char *)udata error:(char **)errmsg
{
    char *data, *dataptr;
    char *signaturefile = sigFile;
    char signaturepath[1024];
    int length, i;
    struct stat filestat;
    FILE *fpin;

    sprintf(signaturepath, "%s/%s", NXHomeDirectory(), signaturefile);
    if(stat(signaturepath, &filestat)){
	data = "";
	length = 0;
	*errmsg = "No signature file found in your home directory.";
	fprintf(stderr,"SpotLight: No signature file found in your home directory.\n");
    }else{
	length = filestat.st_size;
        if((fpin = fopen(signaturepath, "r")) != NULL){
	    dataptr = data = malloc(length+NUMSIGDASH+10);  /* data remains unchanged */
	    for(i=0; i<NUMSIGDASH; i++)		/* Add '---' signature separator here */
	        *dataptr++ = '-';
	    *dataptr++ = '\n';
	    fread((void *)dataptr, 1, length, fpin);
	    fclose(fpin);		/* This was missing in V1.0 release */
	    *(dataptr+length) = '\0';
            [pbid declareTypes:&NXAsciiPboardType num:1 owner:self];
    	    [pbid writeType:NXAsciiPboardType data:data length:strlen(data)];
	    free(data);
        }else{
	    *errmsg = "Cannot open signature file.";
	    fprintf(stderr,"SpotLight: Cannot open signature file.\n");
	}
    }
    return self;
}

// Adds the content of ~/.signature.rtf at the current cursor location.
// RTF signature insertion method.
- insertRtfSignature:(id)pbid userData:(const char *)udata error:(char **)errmsg
{
    char *data;
    char *signaturefile = rtfSigFile;
    char signaturepath[1024];
    int length;
    struct stat filestat;
    FILE *fpin;
    
    sprintf(signaturepath, "%s/%s", NXHomeDirectory(), signaturefile);
    if(stat(signaturepath, &filestat)){
	data = "";
	length = 0;
	*errmsg = "No RTF signature file found in your home directory.";
	fprintf(stderr,"SpotLight: No RTF signature file found in your home directory.\n");
    }else{
	length = filestat.st_size;
        if((fpin = fopen(signaturepath, "r")) != NULL){
	    data = malloc(length+10);
	    fread((void *)data, 1, length, fpin);
	    fclose(fpin);
	    *(data+length) = '\000';
            [pbid declareTypes:&NXRTFPboardType num:1 owner:self];
    	    [pbid writeType:NXRTFPboardType data:data length:strlen(data)];
	    free(data);
        }else{
	    *errmsg = "Cannot open RTF signature file.";
	    fprintf(stderr,"SpotLight: Cannot open RTF signature file.\n");
	}
    }
    return self;
}

@end
