/**
 **  HTMLConverter Mail Bundle
 **
 **/

/* C functions */
/* import <stdio.h> */
/* import <strings.h> */

/* Obj-C Classes */
#import <appkit/appkit.h>

/* Mail stuff */
#import "HTMLConverter.h"

@implementation HTMLConverter

/*****************/
/* Class Methods */
/*****************/
+ initialize;
{
    [NXApp addDisplayFilter:[[self alloc] init]];
    return self;
}

/********************/
/* Instance Methods */
/********************/
- init;
{
    if (nil == [super init])
        return nil;

    /* prepare instance variables */
    conversionMap = nil;
    htmlMapFileName = NULL;
    htmlSavePathName = NULL;
    htmlServiceName = NULL;
    [self setFileCount:0];

    /* build the HTMLConverter file name string
	and the flag on whether to convert */
    [self loadDefaults];

    /* if don't convert and don't display, don't use. */
    if (![self performHTMLConversion] && ![self performHTMLDisplay]) {
	[self free];
	return nil;
    }

    /* load up the file */
    if ([self performHTMLConversion]) {
	[self setConversionMap:[[NXStringTable alloc] init]];
	[[self conversionMap] readFromFile:[self htmlMapFileName]];
    
	/* if no conversion file data & not displaying, don't use. */
	if ((0 == [[self conversionMap] count]) && ![self performHTMLDisplay]) {
	    [self free];
	    return nil;
	}
    }

    /* delete old files */
    if ([self performHTMLDisplay]) {
	char systemCall[MAXPATHLEN] = "rm ";
	
	strcat(systemCall, [self htmlSavePathName]);
	strcat(systemCall, "HTMLConvert*");
	system(systemCall);	/* stdlib */
    }

    return self;
}

- free;
{
    /* This doesn't malloc space for htmlMapFileName, so not freeing it. */
    
    [self setConversionMap:nil];

    return [super free];
}

/********************/
/* Accessor Methods */
/********************/
    /* conversion info */
- (BOOL)performHTMLConversion;
{
    return performHTMLConversion;
}
- (void)setPerformHTMLConversion:(BOOL)value;
{
    performHTMLConversion = value;
}

- (const char *)htmlMapFileName;
{
    return htmlMapFileName;
}
- (void)setHtmlMapFileName:(const char *)value;
{
    htmlMapFileName = value;
}

- (NXStringTable *)conversionMap;
{
    return conversionMap;
}
- (void)setConversionMap:(NXStringTable *)value;
{
    [conversionMap free];
    conversionMap = value;
}

    /* display info */
- (BOOL)performHTMLDisplay;
{
    return performHTMLDisplay;
}
- (void)setPerformHTMLDisplay:(BOOL)value;
{
    performHTMLDisplay = value;
}

- (const char *)htmlSavePathName;
{
    return htmlSavePathName;
}
- (void)setHtmlSavePathName:(const char *)value;
{
    htmlSavePathName = value;
}

- (const char *)htmlServiceName;
{
    return htmlServiceName;
}
- (void)setHtmlServiceName:(const char *)value;
{
    htmlServiceName = value;
}

- (int)fileCount;
{
    return fileCount++;	/* increment for next request */
}
- (void)setFileCount:(int)value;
{
    fileCount = value;
}


/********************/
- (void)loadDefaults;
{
    /* The values MUST be unique, else all array elements are pointers */
    /*		to the exact same value! */
    static NXDefaultsVector	standardDefaults = {
	    {"HTMLServiceName", "OmniWeb/Open URL"}
	    ,{"HTMLSavePathName", "/tmp/"}
	    ,{NULL}
    };
    const char *boolValue = NULL;
    char path[MAXPATHLEN];
    
    NXRegisterDefaults([NXApp appName], standardDefaults);

    /* Should the conversion happen? */
    boolValue = NULL;
    boolValue = NXGetDefaultValue([NXApp appName], "HTMLConvert");
    if ((NULL == boolValue) || (strcmp(boolValue, "YES") == 0)) {
	[self setPerformHTMLConversion:YES];
    } else {
	[self setPerformHTMLConversion:NO];
    }
    
    /* Should the display happen? */
    boolValue = NULL;
    boolValue = NXGetDefaultValue([NXApp appName], "HTMLDisplay");
    if ((NULL == boolValue) || (strcmp(boolValue, "YES") == 0)) {
	[self setPerformHTMLDisplay:YES];
    } else {
	[self setPerformHTMLDisplay:NO];
    }
    
    if (![self performHTMLConversion] && ![self performHTMLDisplay]) {
	/* if don't convert or display, don't need any other defaults...return */
	return;
    }
    
    
    /* where is the path to use for saving */
    [self setHtmlSavePathName:(const char *)NXGetDefaultValue([NXApp appName], "HTMLSavePathName")];
    
    /* what is the name of the service to open URLs */
    [self setHtmlServiceName:(const char *)NXGetDefaultValue([NXApp appName], "HTMLServiceName")];
    
    /* where is the file to use for the conversion */
    [self setHtmlMapFileName:(const char *)NXGetDefaultValue([NXApp appName], "HTMLMapPathFileName")];
    
    /* if path found, done. */
    if (NULL != [self htmlMapFileName]) {
	return;
    }
    
    /* if NO path found, look in bundle */
    if ([[NXBundle bundleForClass:[self class]]
    getPath:path forResource:"HTMLMap" ofType:"plist"]) {
        [self setHtmlMapFileName:(const char *)path];
    } else {
        fprintf(stderr, "*** Can't find HTMLMap.plist in bundle\n");
        [self setHtmlMapFileName:(const char *)NULL];
	return;
    }
}

- (BOOL)convertText:(Text*)text;
{
/*  This is how to enumerate through a hashTable (NSStringTable is subclass) */
    NXStringTable *table = [self conversionMap];
    const   void *key;
	    void *value;
    NXHashState  state = [table initState];
    
    /* Enumerate (loop) through the key/values.  Perform conversion. */
    while ([table nextState:&state key:&key value:&value]) {
/*
printf("test*** key:%s   value:%s\n", (const char *)key, (char *)value);
*/
	/* have to loop through replacing multiple -keys- */
	while ([text findText:key ignoreCase:YES backwards:NO wrap:YES]) {
	    [text replaceSel:value];
	}
    }
    return YES;
}

- (BOOL)openBrowserWithText:(Text*)text;
{
    Pasteboard *pboard = nil;
    const char *pboardTypes[1];
    char fileName[MAXPATHLEN];
    char pbData[MAXPATHLEN] = "file:";
    int length = 0;
    
    /* save Text to a file */
    /* generate fileName with format like: "/tmp/HTMLConverter0.html" */
    sprintf(fileName, "%sHTMLConverter%d.html", [self htmlSavePathName], [self fileCount]);
    [self saveText:text toFileNamed:fileName];
    
    /* open file in HTML Browser through services */
    /* filename with format like: "file:/tmp/HTMLConverter0.html" */
    strcat(pbData, fileName);
    length = strlen(pbData) + 1;
    pboard = [Pasteboard newName:NXGeneralPboard];
    /* Have to declare types & self as owner before able to successfully write to pboard */
    pboardTypes[0] = NXAsciiPboardType;
    [pboard declareTypes:pboardTypes num:1 owner:self];
    [pboard writeType:NXAsciiPboardType data:pbData length:length];
    
    /* pboard data must include the "file:" http designation */
    return NXPerformService([self htmlServiceName], pboard);
    
    /* standard pasteboards generally should not be freed at all. */
}
- (BOOL)saveText:(Text*)text toFileNamed:(const char *)filename;
{
    NXStream *stream;
    BOOL failed = NO;
    
    /* open data stream */
    stream = NXOpenMemory(NULL, 0, NX_READWRITE);
    
    if (stream) {
	/* write data to stream */
	NX_DURING
	    [text writeText:stream];
	NX_HANDLER
	    failed = YES;
	NX_ENDHANDLER
    
	if (!failed) {
	    /* write steam data to file */
	    NX_DURING
		NXSaveToFile(stream, filename);
	    NX_HANDLER
		failed = YES;
	    NX_ENDHANDLER
	}
	NXCloseMemory(stream, NX_FREEBUFFER);
    }
    
    if (failed || !stream) {
	NXRunAlertPanel("Error", "Couldn't save HTML to: %s", 
		NULL, NULL, NULL, filename);
	return NO;
    }
    
    return YES;
}


/********************/
/* Delegate Methods */
/********************/
- (void)willDisplayText:(Text *)text;
{
    /* Check if conversion is wanted & possible */
    if ( !text && ([text textLength] < 10)) {
	return;
    }
    
    /* Check if conversion should be performed */
    /* does <html> tag exist.  (could also check that </html> tag exists) */
    if ( !([text findText:"<html>" ignoreCase:YES backwards:NO wrap:YES])) {
	return;
    }
    
    /* This Text Object does contain HTML! */

    /* if display requested, display */
    if ([self performHTMLDisplay]) {
	[self openBrowserWithText:text];
    }

    /* if conversion requested, perform AFTER display */
    if ([self performHTMLConversion]) {
	[self convertText:text];
    }
}

@end
