// 
// Based on the following example from LightHouse:
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Copyright 1994-1995 Lighthouse Design, Ltd. All rights reserved.
//
// QXExport.m
//
// THIS CODE IS FOR DEMONSTRATION PURPOSES ONLY!
// You may freely copy, distribute and reuse the code in this example.  
// Lighthouse disclaims any warranty of any kind, expressed or implied, as to 
// its fitness for any particular use.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// QXExportHtml.m
//
// Copyright 1996 Rudolf B. Blazek, Michigan State University. 
// blazek@stt.msu.edu
// All rights reserved.
//
// See the ReadMe.rtf file for details.
//
//
// Version 1.5 - November 26, 1996
// Modified by sanguish@digifix.com
// fixed:  empty cells no longer show up as a "."  it now inserts &nbsp;
// added:  support for font colors (although it doesn't seem to be settable 
//           in the UI)
//         support for alignment, only seems to work for fields explictly
//           aligned.
//         background colors for cells
//
//
// See the ReadMe.rtf file for details.
//
//
// Version 1.6 - September 19, 1997
// Changes by blazek@stt.msu.edu
// fixed:  color attributes work also for column labels now.
//         row labels can be exported now.
//         file name taken from the model name correctly.
// added:  user interface - accessory view in SavePanel and info panel.
//             - allows to set the HTML parameters.
//         
// See the ReadMe.rtf file for details and things to do.
//


#import <appkit/appkit.h>
#import "QXExportHtml.h"

#define FIRST_VALUE -1
#define DEFAULTS_OWNER "QuantrixExportHtml"
#define FIRST_VALUE -1

static QXExportHtml* instance = nil;

static void *rcs_id = (rcs_id, "$Id: QXExportHtml.m,v 1.6 1997/8/30 00:02:55 blazek Exp $");

@implementation QXExportHtml

+ q_bundleSelected:(NXBundle*)aBundle
{
    if (!instance) {
	instance = [[[self class] alloc] init];
	[instance setBundle:aBundle];
    }
    [instance menuSelected:self];
    return self;
}

- init
{
    [super init];
    bundle = nil;
    accessoryView = nil;
    lastColorWell = 0;
    qapiApp = qapiConnect();
    return self;
}

- free
{
    return [super free];
}

- setBundle:(NXBundle*)aBundle
{
    bundle = aBundle;
    return self;
}

- loadInterfaceFileFrom:(NXBundle*)aBundle;
{
    char fileName[MAXPATHLEN+1];
    char path[MAXPATHLEN+1];

    sprintf(fileName, "%s.nib", [[self class] name]);
    if (![aBundle getPath:path forResource:fileName ofType:"nib"] ||
    ![NXApp loadNibFile:path owner:self withNames:YES fromZone:[self zone]]) {
	NXLogError("QXExportHtml: Could not load interface %s\n", fileName);
    }
    return self;
}

- equalColorsOnOff:sender
{
    switch (lastColorWell) {
	case 1: [self pageColorChanged:self];  break;
	case 2: [self tableColorChanged:self]; break;
        default: break;
    }
    return self;
}

- pageColorChanged:sender
{
    lastColorWell = 1;
    if ([equalColorsSwitch state])
	[tableBgColorWell setColor:[pageBgColorWell color]]; 
    return self;
}

- tableColorChanged:sender
{
    lastColorWell = 2;
    if ([equalColorsSwitch state])
	[pageBgColorWell setColor:[tableBgColorWell color]]; 
    return self;
}

- registerDefaults
{
    static NXDefaultsVector myDefaults = {
        {"RowLabels","Off"},
        {"ColumnLabels","On"},
        {"UseColors","On"},
        {"EqualColors","On"},
        {"BorderSize", "4"},
        {"CellSpacing", "1"},
        {"CellPadding", "1"},
        {"LabelFontIncrease", "1"},
        {"TableBackground","#FFFFFF"},
        {"PageBackground","#FFFFFF"},
        {NULL}
    };
    NXRegisterDefaults(DEFAULTS_OWNER, myDefaults);
    [self restoreDefaults:self];
    return self;
}


- saveDefaults:sender
{
    [self saveField:borderSizeField  into:"BorderSize"];
    [self saveField:cellSpacingField into:"CellSpacing"];
    [self saveField:cellPaddingField into:"CellPadding"];
    [self saveField:headerFontIncreaseField into:"LabelFontIncrease"];

    [self saveSwitch:rowLabelsSwitch   into:"RowLabels"];
    [self saveSwitch:colLabelsSwitch   into:"ColumnLabels"];
    [self saveSwitch:colorAttribSwitch into:"UseColors"];
    [self saveSwitch:equalColorsSwitch into:"EqualColors"];

    [self saveColorWell:tableBgColorWell  into:"TableBackground"];
    [self saveColorWell:pageBgColorWell   into:"PageBackground"];

    return self;
}

- restoreDefaults:sender
{
    NXUpdateDefaults();

    [self restoreField:borderSizeField  from:"BorderSize"];
    [self restoreField:cellSpacingField from:"CellSpacing"];
    [self restoreField:cellPaddingField from:"CellPadding"];
    [self restoreField:headerFontIncreaseField from:"LabelFontIncrease"];

    [self restoreSwitch:rowLabelsSwitch   from:"RowLabels"];
    [self restoreSwitch:colLabelsSwitch   from:"ColumnLabels"];
    [self restoreSwitch:colorAttribSwitch from:"UseColors"];
    [self restoreSwitch:equalColorsSwitch from:"EqualColors"];

    [self restoreColorWell:tableBgColorWell  from:"TableBackground"];
    [self restoreColorWell:pageBgColorWell   from:"PageBackground"];

    [self pageColorChanged:self];

    return self;
}

- saveField:aField into:(char*)name
{
    NXWriteDefault(DEFAULTS_OWNER, name, [aField stringValue]);
    return self;
}

- restoreField:aField from:(char*)name
{
    [aField setStringValue:NXGetDefaultValue(DEFAULTS_OWNER, name)];
    [[aField target] takeIntValueFrom:aField];
    return self;
}

- saveSwitch:aSwitch into:(char*)name
{
    if ([aSwitch state])
	NXWriteDefault(DEFAULTS_OWNER, name,"On");
    else
	NXWriteDefault(DEFAULTS_OWNER, name,"Off");    
    return self;
}

- restoreSwitch:aSwitch from:(char*)name
{
    if (strcmp(NXGetDefaultValue(DEFAULTS_OWNER, name),"On")==0)
	[aSwitch setIntValue:1];
    else [aSwitch setIntValue:0];
    return self;
}

- saveColorWell:aColorWell into:(char*)name
{
    NXWriteDefault(DEFAULTS_OWNER, name, [self HTMLcolor:[aColorWell color]]);
    return self;
}

- restoreColorWell:aColorWell from:(char*)name
{
    char htmlColor[1024];
    int r,g,b;
    float rf, gf, bf;
    sprintf (htmlColor, "%s", NXGetDefaultValue(DEFAULTS_OWNER, name));
    sscanf  (htmlColor, "#%02x%02x%02x", &r, &g, &b);
    rf = r; gf = g; bf = b;
    [aColorWell setColor:NXConvertRGBToColor(rf/255, gf/255, bf/255)];
    return self;
}





- menuSelected:sender
{
    SavePanel *savePanel = [SavePanel new];
    id <QAPIModel> aModel = [[qapiApp q_currentView] q_model];
    char path[1024], name[1024];
    size_t position;

    if (!accessoryView) {
	[self loadInterfaceFileFrom:bundle];
	[self registerDefaults];
    };

    [infoPanel setWorksWhenModal:YES];
//    [infoPanel setFloatingPanel:YES];

    [savePanel setAccessoryView:accessoryView];
    [savePanel setTitle:"Export Html Table"];
    [savePanel setRequiredFileType:"html"];

    sprintf (name, "%s", [aModel q_name]);
    position = strlen(name);
    name[position-9]=0;
    sprintf (path, "%s%s%s%s", [aModel q_path], "/../", name, ".html");
    if ([savePanel runModalForDirectory:path file:name]) {
	useRowLabels = [rowLabelsSwitch state];
	useColLabels = [colLabelsSwitch state];
	useColors    = [colorAttribSwitch state];
	prevRow = FIRST_VALUE;
	aStream = NXOpenMemory(NULL, 0, NX_WRITEONLY);

        NXPrintf(aStream, "<HTML>\n\n<HEAD>\n<TITLE>");
        NXPrintf(aStream, "Table Exported From Quantrix.app");
        NXPrintf(aStream, "</TITLE>\n</HEAD>\n\n<BODY");
        if (useColors) NXPrintf(aStream, " BGCOLOR=%s", 
		[self HTMLcolor:[pageBgColorWell color]]);
        NXPrintf(aStream, ">\n");
        NXPrintf(aStream, "<TABLE BORDER=%i", [borderSizeField intValue]);
        NXPrintf(aStream, " CELLSPACING=%i", [cellSpacingField intValue]);
        NXPrintf(aStream, " CELLPADDING=%i", [cellPaddingField intValue]);
        if (useColors) NXPrintf(aStream, " BGCOLOR=%s", 
		[self HTMLcolor:[tableBgColorWell color]]);
        NXPrintf(aStream, ">\n");

	[self exportHTMLData:qapiApp];

        NXPrintf(aStream, "\n</TABLE>");
        NXPrintf(aStream, "\n</BODY>\n\n</HTML>\n");
	NXSaveToFile(aStream, [savePanel filename]);
	NXCloseMemory(aStream, NX_FREEBUFFER);
    }
    return self;
}

- exportHTMLData:(id <QAPIApp>)anApp
{
    id <QAPIView> aView;
    id <QAPITable> aTable;
    id <QAPISelection> aSelection;
    id <QAPINode> aCategory, anItem;
    qs_categoryRange aRange;
    int nItems, item;
    char *rowLabel;

    aView = [anApp q_currentView];
    aTable = [aView q_table];
    aSelection = [aView q_alternateSelection];

    //  Row Labels;
    if (useRowLabels) {
	aCategory = [aTable q_categoryAt:1];
	nItems = [aCategory q_itemCount];
	aRange.start = [aCategory q_itemAt:0];
	aRange.end = [aCategory q_itemAt:nItems-1];
	[aSelection q_setCategoryRange:aRange clearOther:YES];
	labelsArray = (char **) malloc (nItems * 4);
	for (item=0; item < nItems; item++) {
	    anItem  = [aCategory q_itemAt:item];
            rowLabel = (char *) malloc(1024);
            sprintf(rowLabel,"%s", [self evaluateItem:anItem in:aSelection]);
	    labelsArray[item] = rowLabel;
	}
      }

    // Column Labels
    aCategory = [aTable q_categoryAt:0];
    nItems = [aCategory q_itemCount];
    aRange.start = [aCategory q_itemAt:0];
    aRange.end = [aCategory q_itemAt:nItems-1];
    [aSelection q_setCategoryRange:aRange clearOther:YES];
    if (useColLabels) {
	NXPrintf(aStream, "<TR>\n");
	if (useRowLabels) NXPrintf(aStream, "<TD></TD>");
	for (item=0; item < nItems; item++) {
	    anItem = [aCategory q_itemAt:item];
	    NXPrintf(aStream, "%s", [self evaluateItem:anItem in:aSelection]);
	}
    NXPrintf(aStream, "</TR>\n");
    }

    // All Table Cells
    NXPrintf(aStream, "<TR>\n");
    [aSelection q_iterateWithDelegate:self];
    NXPrintf(aStream, "</TR>\n");

    if (useRowLabels) free (labelsArray);

    return self;
}

- (char*)HTMLcolor:(NXColor)theColor;
{
// written by sanguish@digifix.com and moved by blazek@stt.msu.edu
    int r,g,b;
    char tempString[1024];

    r=(NXRedComponent(theColor)*255);
    g=(NXGreenComponent(theColor)*255);
    b=(NXBlueComponent(theColor)*255);
    sprintf(tempString,"#%02X%02X%02X", r, g, b);
    return tempString;
}

- (char*)evaluateItem:(id<QAPINode>)anItem in:aSelection;
{
// modified by sanguish@digifix.com
// copied here and further modified by blazek@stt.msu.edu

    NXColor theColor;
    char outString[1024], align[1024], bgColor[1024], 
	fontColor[1024], fontSize[1024];

//  if (![[aSelection q_itemFormatFor:anItem] q_isHidden])

    switch ([[aSelection q_itemFormatFor:anItem] q_textAlign]) {
	case qk_leftAlign:   strcpy(align," ALIGN=LEFT");   break;
	case qk_rightAlign:  strcpy(align," ALIGN=RIGHT");  break;
	case qk_centerAlign: strcpy(align," ALIGN=CENTER"); break;
	case qk_smartAlign:  strcpy(align,""); break;
	}

    if (useColors) {
	theColor=[[aSelection q_itemFormatFor:anItem] q_backgroundColor];
	sprintf(bgColor," BGCOLOR=%s", [self HTMLcolor:theColor]);
	theColor=[[aSelection q_itemFormatFor:anItem] q_textColor];
	sprintf(fontColor," COLOR=%s", [self HTMLcolor:theColor]);
    } else {
	strcpy(bgColor, "");
	strcpy(fontColor, "");
    }

// end modified by sanguish@digifix.com

    sprintf(fontSize," SIZE=+%i", [headerFontIncreaseField intValue]);

    sprintf(outString, "<TD%s%s><FONT%s%s><B>%s</B></FONT></TD>", 
	align, bgColor, fontSize, fontColor, [anItem q_name]);

    return outString;

}


- (void)q_evaluateCell:(id<QAPICell>)aCell in:aSelection;
{
    qs_cellLocation location;
    qenum_stringType stringType;
    qenum_dataType dataType;
    NXColor theColor;
    char *rowLabel;

    dataType = [aCell q_dataType];
    stringType = [[aSelection q_cellFormatFor:aCell] q_stringType];
    location = [aCell q_location];
    
    if (prevRow == FIRST_VALUE) {
	prevRow  = location.row;
	if (useRowLabels) {
//            rowLabel = (char *)[aStorage elementAt:prevRow];
            rowLabel = labelsArray[prevRow];
	    NXPrintf(aStream, "%s", rowLabel);
	    free (rowLabel);
	}
    }
    else if (location.row != prevRow) {
	prevRow = location.row;
	NXPrintf(aStream, "</TR>\n<TR>\n");
	if (useRowLabels) {
//            rowLabel = (char *)[aStorage elementAt:prevRow];
            rowLabel = labelsArray[prevRow];
	    NXPrintf(aStream, "%s", rowLabel);
	    free (rowLabel);
	}
    }


// modified by sanguish@digifix.com
// see notes for later modifications by blazek@stt.msu.edu

    NXPrintf(aStream, "<TD");

    switch ([[aSelection q_cellFormatFor:aCell] q_textAlign]) {
	case qk_leftAlign:   NXPrintf(aStream, " ALIGN=LEFT");   break;
	case qk_rightAlign:  NXPrintf(aStream, " ALIGN=RIGHT");  break;
	case qk_centerAlign: NXPrintf(aStream, " ALIGN=CENTER"); break;
	case qk_smartAlign:  NXPrintf(aStream, ""); break;
	}

    if (useColors) {	// condition added by blazek@stt.msu.edu
	theColor=[[aSelection q_cellFormatFor:aCell] q_backgroundColor];
	NXPrintf(aStream," BGCOLOR=%s", [self HTMLcolor:theColor]);
			// Moved some code into HTMLcolor. blazek@stt.msu.edu
    }

    NXPrintf(aStream, ">");

    if (useColors) {	// condition added by blazek@stt.msu.edu
	theColor=[[aSelection q_cellFormatFor:aCell] q_textColor];
	NXPrintf(aStream,"<FONT COLOR=%s>", [self HTMLcolor:theColor]);
			// Moved some code into HTMLcolor. blazek@stt.msu.edu
    }

// end modified by sanguish@digifix.com

    if (dataType == qk_empty || dataType == qk_error)
	NXPrintf(aStream, "&nbsp;");  
		// fixed so that empty cells image properly sanguish@digifix.com
    else
	NXPrintf(aStream, "%s", [aCell q_formattedValue]);

    if (useColors) NXPrintf(aStream, "</FONT>");
    NXPrintf(aStream, "</TD>");

}

- (void)q_evaluateNode:(id<QAPINode>)aNode in:aSelection
{
}

@end

