/* InspectTuple	by Paul Kunz	October 1991
 * The supervisor for the tuple inspection panel
 * 
 * Copyright (C)  1991  The Board of Trustees of
 * The Leland Stanford Junior University.  All Rights Reserved.
 */ 

#import "InspectTuple.h"

const char InspectTuple_h_rcsid[] = INSPECTTUPLE_H_ID;
const char InspectTuple_m_rcsid[] = "$Id: InspectTuple.m,v 1.27 1992/04/19 21:42:20 pfkeb Rel $";

#import <appkit/Application.h>
#import <appkit/Box.h>
#import <appkit/Form.h>
#import <appkit/Matrix.h>
#import <appkit/NXBrowser.h>
#import <appkit/NXBrowserCell.h>
#import <appkit/OpenPanel.h>
#import <appkit/Pasteboard.h>
#import <appkit/TextField.h>
#import <appkit/Window.h>
#import <appkit/nextstd.h>
#import <objc/List.h>
#import "DrawDocument.h"
#import "HDraw.h"
#import "HGraphicView.h"
#import "HTuple.h"
#import "NewInspector.h"
#import "Plot.h"
#import "stdio.h"
#import "strings.h"
#import <appkit/defaults.h>
#import <sys/types.h>
#import <sys/stat.h>

@implementation InspectTuple
- initInspFor:aDraw
{
    [super initInspFor:aDraw];
    
    [NXApp loadNibSection:"InspectTuple.nib" owner:self
           withNames:NO fromZone:[self zone]];
    [theInspector addView:[contentBox contentView]
                  withName:"Tuple List"
		  withSupervisor:self];
    
    openPanel = [OpenPanel new];
  /* the following avoids getting "/private/Net/..." as default */
    [openPanel setDirectory:NXHomeDirectory()];

    tupleList = [[ List allocFromZone:[self zone]] init]; 
    
    [[fileForm cellAt: 0 :0 ] setSelectable:YES];
    [[fileForm cellAt: 1 :0 ] setEditable:NO];
    [[fileForm cellAt: 2 :0 ] setEditable:NO];
    [[fileForm cellAt: 3 :0 ] setEditable:NO];
    [ fileForm setBordered:YES];
    
    return self;
}
- hTupleForTuple:(ntuple) nt
{
    id			hTuple;
    int			i, count;
    
    count = [tupleList count];
    for ( i = 0; i < count; i++ ) {
        hTuple = [tupleList objectAt:i];
	if ( nt == [hTuple ntuple] ) {
	    return hTuple;
	}
    }
    return nil;
}

- (BOOL) isNewTupleFile:(const char *)filename
{
    id			hTuple;
    int			i, count;
    
    count = [tupleList count];
    for ( i = 0; i < count; i++ ) {
        hTuple = [tupleList objectAt:i];
	if ( strcmp( [hTuple filename], filename ) == 0 ) {
	    return NO;
	}
    }
    return YES;
}
- hTupleForFile:(const char *)filename index:(int)iValue
{
    const char	*altfile;
    id		hTuple;
    int		i;
    
    i = [tupleList count];
    while ( i-- ) {
        hTuple = [tupleList objectAt:i];
	if ( [hTuple index] == iValue ) {
	    if ( strcmp( [hTuple filename], filename ) == 0 ) {
		return hTuple;
	    }
	    altfile = [hTuple altfilename];
	    if ( altfile && (strcmp(altfile, filename) == 0 ) ) {
		return hTuple;
	    }
	}
    }
    
    return nil;
}
- (int) runModelForTypes
{
    static const char	*const filetype[2] = {"hippo", NULL};
    
    [openPanel setAccessoryView:accessoryView];
    if ( ![openPanel runModalForTypes:filetype] ) {
    	return HD_CANCEL;
    }
    return HD_OK;
}
- openTuple:sender
{
    int			irc;

    irc = [self runModelForTypes];
    if ( irc == HD_CANCEL ) {
        return self;
    }
    [self openTupleFile];
    return self;
}
- openTupleAsText:sender
{
    [openPanel setAccessoryView:accessoryView];
    if ( ![openPanel runModal] ) {
    	return self;
    }
    [self openTupleFile];
    return self;
}
- openTupleFile
{ 
    const char		*filename;
    int                 irc;
    BOOL		refFlag;

    filename = [openPanel filename];
    refFlag = [refFlagMatrix selectedRow] ? NO : YES;
    irc = [self openTupleFile:filename by:refFlag];
    if ( irc == HD_REPLACE ) {
        [self bindDisplays];
    }
    [self showPanel];
    return self;
}

- openTupleFromFile:(const char *)filename by:(BOOL)refFlag
{
    id		hTuple, newTupleList;
    FILE	*infile;
    ntuple	*ntlist;
    display     *dlist;
    char	*suffix;
    int		i, irc;
    BOOL	binFlag;
    
    suffix = rindex(filename, '.' );
    if ( (infile = fopen(filename, "r") ) == NULL ) {
	irc = NXRunAlertPanel("Reason Alert", "Couldn't open file",
			"OK", NULL, NULL);
	return nil;
    }
    if ( suffix && (strcmp(suffix, ".hippo" ) == 0) ) {
        binFlag = YES;
	if ( h_readStream(infile, &dlist, &ntlist) != 0 ) {
	    return nil;
	}
    } else {
        binFlag = NO;
        NX_ZONEMALLOC( [self zone], ntlist, ntuple, 2 );
	if ( !(ntlist[0] = h_fileParse( infile, NULL, 0) ) ) {
	    NXZoneFree([self zone], ntlist);
	    return nil;
	}
	ntlist[1] = NULL;
    }
    irc = fclose( infile );
    
    newTupleList = [[List allocFromZone:[self zone]] initCount:0];
    for ( i = 0; ntlist[i] != NULL; i++ ) {
	hTuple = [[HTuple allocFromZone:[self zone]]
	                  initTuple:ntlist[i] file:filename
			  by:refFlag mode:binFlag index:i];
	[tupleList addObject:hTuple];
	[newTupleList addObject:hTuple];
    }
    [tupleBrowser loadColumnZero];
    [ self setTuple:ntlist[0] ];
    return newTupleList;
}
- openTuple:pasteBoard
    userData:(const char *)args
    error:(char **)errorMsg
{
    id		hTuple;
    FILE 	*infile;
    ntuple	*ntlist;
    const char *const *ptypes;
    const char *data;
    char 	filename[25];
    char	*outbuffer;
    int		i, irc, length;
    BOOL	binFlag;

    ptypes = [pasteBoard types];
    for ( i = 0; ptypes[i]; i++ ) {
        if ( !strcmp(ptypes[i], NXAsciiPboardType) ) {
	    [pasteBoard readType:ptypes[i] data:&data length:&length];
	    NX_ZONEMALLOC([self zone], outbuffer, char, (length+2) );
	    strncpy( outbuffer, data, length);
	    outbuffer[length] = '\n';
	    outbuffer[length+1] = '\0';
	    strcpy(filename,"/tmp/file000000Selection" );
	    NXGetTempFilename(filename,9);
	    infile=fopen(filename,"w");
	    fprintf(infile,outbuffer);
	    fclose(infile);
	    NXZoneFree([self zone], outbuffer);
	    if ( (infile = fopen(filename, "r") ) == NULL ) {
		*errorMsg = "Couldn't open /tmp file";
		return nil;
	    }
	    binFlag = NO;
	    NX_ZONEMALLOC( [self zone], ntlist, ntuple, 2 );
	    if ( !(ntlist[0] = h_fileParse( infile, NULL, 0) ) ) {
		NXZoneFree([self zone], ntlist);
		*errorMsg = "Couldn't interpret data as n-tuple";
		return nil;
	    }
	    ntlist[1] = NULL;
	    irc = fclose( infile );
	    unlink(filename);
	    hTuple = [[HTuple allocFromZone:[self zone]]
	                      initTuple:ntlist[0] file:"From Pasteboard"
			      by:NO mode:NO index:0];
	    [hTuple setFakeFilename:YES];
	    [tupleList addObject:hTuple];
	    [tupleBrowser loadColumnZero];
	    [self setTuple:ntlist[0] ];
	    [self showPanel];
	}
    }
    return self;
}
- addTuple:(ntuple) nt
{
    id			hTuple;
    
    hTuple = [[HTuple allocFromZone:[self zone]]
     		      initTuple:nt file:"none"
                      by:NO mode:YES index:0];
    [hTuple setFakeFilename:YES];
    [tupleList addObject:hTuple];
    [tupleBrowser loadColumnZero];
    [ self setTuple:nt];
    return hTuple;
}
- (ntuple) currentTuple
{
    id			browserMatrix;
    id			hTuple;
    ntuple		nt;
    int			index;
    
    browserMatrix = [tupleBrowser matrixInColumn:0];
    index = [browserMatrix selectedRow];
    if ( index >= 0 ) {
        hTuple = [tupleList objectAt:index];
        nt = [hTuple ntuple];
    } else {
        nt = NULL;
    }
    return nt;
}

- currentHTuple
{
    id		browserMatrix;
    id		hTuple;
    int		index;
    
    browserMatrix = [tupleBrowser matrixInColumn:0];
    index = [browserMatrix selectedRow];
    if ( index >= 0 ) {
        hTuple = [tupleList objectAt:index];
    } else {
        hTuple = nil;
    }
    return hTuple;
}

- bindDisplays
{
    id		windowList;
    id		window, document, view;
    int		wcount;
    
    windowList = [NXApp windowList];
    wcount = [windowList count];
    while ( wcount-- ) {
        window = [windowList objectAt:wcount];
	document = [window delegate];
	if ( [document isKindOf:[DrawDocument class]] ) {
	    view = [document view];
	    [view bindDisplays];
            [view reDrawPlot];
	}
    }        
    return self;
}

- addTuplesIfAbsent:newList for:aView
{
    id		newTuple, hTuple;
    int		newCount, count;
    int		i, j, irc;
    BOOL	isNew;
    
    newCount = [newList count];
    for ( i = 0; i < newCount; i++ ) {
        newTuple = [newList objectAt:i];
	isNew = YES;
	count = [tupleList count];
	for ( j = 0; j < count; j++ ) {
	    hTuple = [tupleList objectAt:j];
	    if ( [hTuple isSameAs:newTuple] ) {
	        isNew = NO;
		[aView replace:newTuple with:hTuple];
		[newTuple free];
		break;
	    }
	}
	if ( isNew ) {
	    if ( [newTuple isRef ] ) {
	        irc = [self openTupleFile:[newTuple filename] by:YES];
		if ( irc == HD_NOTEXIST ) {
		    [ self openAltTupleFile:[newTuple filename]];
		}
		j = [tupleList count];
		while ( j-- ) {
		    hTuple = [tupleList objectAt:j];
		    if ( [hTuple isSameAs:newTuple] ) {
		        [aView replace:newTuple with:hTuple];
			[newTuple free];
			break;
		    }
		}
	    } else {
		[tupleList addObject:newTuple];
		[tupleBrowser loadColumnZero];
		[ self setTuple:[newTuple ntuple]];
	    }
	}
    }
    [self showPanel];
    return self;
}
- (int) openTupleFile:(const char *)filename by:(BOOL) refFlag
{
    id			newTupleList;
    struct stat		statbuf;
    int			irc, rvalue;
    
    
    if ( stat(filename, &statbuf) ) {
        return HD_NOTEXIST;
    }
    rvalue = HD_OK;
    if( ![self isNewTupleFile:filename] ) {
        irc = NXRunAlertPanel( "Open", "Tuple file already open",
	                       "Replace", "Cancel", NULL);
	if ( irc != NX_ALERTDEFAULT ) {
	    return HD_CANCEL;
	}
	[self closeTupleFile:filename];
	rvalue = HD_REPLACE;
    }		       
    if ( !(newTupleList = [self openTupleFromFile:filename by:refFlag]) ) {
	irc = NXRunAlertPanel("Open", "Couldn't open file",
			"OK", NULL, NULL);
	return HD_CANCEL;
    }
    [newTupleList free];
    return rvalue;
}
- openAltTupleFile:(const char *)filename
{
    id			newTupleList;
    id			hTuple;
    const char 		*newfilename;
    char		*suffix;
    float		gray;
    int			i, count;
    int			rows, cols;
    int                 irc;
    BOOL		refFlag;

    [msgMatrix getNumRows:&rows numCols:&cols];
    for (i = 0; i < rows; i++) {
	[[msgMatrix cellAt:i :0] setTextGray:0.];
    }
    [[msgMatrix cellAt:1 :0] setStringValue:filename];
    
    suffix = rindex(filename, '.');
    if (suffix && (strcmp(suffix, ".hippo") == 0)) {
	irc = [self runModelForTypes];
    } else {
	[openPanel setAccessoryView:accessoryView];
	if ( ![openPanel runModal] ) {
	    irc = HD_CANCEL;
	} else {
	    irc = HD_OK;
        }
    }
    gray = [msgMatrix backgroundGray];
    for (i = 0; i < rows; i++) {
	[[msgMatrix cellAt:i :0] setTextGray:gray];
    }
    if ( irc == HD_CANCEL ) {
        return self;
    }
    
    newfilename = [openPanel filename];
    if ( ![self isNewTupleFile:newfilename] ) {
        newTupleList = [self tupleListForFile:newfilename];
	count = [newTupleList count];
	for ( i = 0; i < count; i++ ) {
	    hTuple = [newTupleList objectAt:i];
	    [hTuple setAltFilename:filename];
	}
	return self;
    }
    refFlag = [refFlagMatrix selectedRow] ? NO : YES;
    if ( !(newTupleList = [self openTupleFromFile:newfilename by:refFlag]) ) {
	irc = NXRunAlertPanel("Open", "Couldn't open file",
			"OK", NULL, NULL);
	return self;
    }
    count = [newTupleList count];
    for ( i = 0; i < count; i++ ) {
        hTuple = [newTupleList objectAt:i];
	[hTuple setAltFilename:filename];
    }
    return self;
}
- closeTupleFile:(const char *)filename
{
    id		windowList;
    id		window, document, view;
    id		hTuple;
    int		count;
    
    windowList = [NXApp windowList];
    count = [windowList count];
    while ( count-- ) {
        window = [windowList objectAt:count];
	document = [window delegate];
	if ( [document isKindOf:[DrawDocument class]] ) {
	    view = [document view];
	    [view closeTupleFile:filename];
	}
    }
    tmpTupleList = [self tupleListForFile:filename];
    count = [tmpTupleList count];
    while ( count-- ) {
        hTuple = [tmpTupleList objectAt:count];
	[tupleList removeObject:hTuple];
    }
    [tupleBrowser reloadColumn:0];
    [self browserSelect:self];
    [tmpTupleList freeObjects];
    return self;
}
- tupleListForFile:(const char *) filename
{
    id		hTuple;
    int		i, count;
    
    if ( tmpTupleList ) {
        [tmpTupleList empty];
    } else {
        tmpTupleList = [[List allocFromZone:[self zone]] initCount: 0];
    }
    count = [tupleList count];
    for ( i = 0; i < count; i++ ) {
        hTuple = [tupleList objectAt:i];
	if ( strcmp( [hTuple filename], filename ) == 0 ) {
	        [tmpTupleList addObject:hTuple];
	}
    }
    return tmpTupleList;
}
- showPanel
{
    theInspector = [hDraw newInspector];
    [theInspector show:"Tuple List"];
    [theInspector orderFrontPanel:self];
    return self;
}
- select:sender
{
    selectedTuple = [self currentTuple];
    return self;
}

- replace:sender
{
    id 			browserMatrix;
    id 			doc;
    id			hTuple;
    int			index;
    
    doc = [hDraw currentDocument];
    if ( !doc ) return self;
    graphicView = [doc view];
    browserMatrix = [tupleBrowser matrixInColumn:0];
    index = [browserMatrix selectedRow];
    if ( index < 0 ) return self;
    hTuple = [tupleList objectAt:index];
    selectedTuple = [hTuple ntuple];
    [graphicView graphicsPerform:@selector(replaceTupleWith:)
	    with: hTuple andDraw:YES ];
    [[graphicView window] flushWindow];
    return self;
}

- close:sender
{
    id		windowList;
    id		window, document, view;
    id		usedTupleList;
    id		hTuple;
    id 		browserMatrix;
    int		wcount;
    int		i, irc, index;
    
    browserMatrix = [tupleBrowser matrixInColumn:0];
    index = [browserMatrix selectedRow];
    if ( index < 0 ) return self;
    hTuple = [tupleList objectAt:index];
    windowList = [NXApp windowList];
    wcount = [windowList count];
    while ( wcount-- ) {
        window = [windowList objectAt:wcount];
	document = [window delegate];
	if ( [document isKindOf:[DrawDocument class]] ) {
	    view = [document view];
	    usedTupleList = [view tupleList];
	    i = [usedTupleList indexOf:hTuple];
	    if ( i != NX_NOT_IN_LIST ) {
        	irc = NXRunAlertPanel( "Close", "Tuple in use",
	                               "OK", NULL, NULL);
		return self;
	    }
	}
    }        
    [self closeTupleFile:[hTuple filename]];
    return self;
}
- browserSelect:sender
{
    id			browserMatrix;
    id			hTuple;
    ntuple		nt;
    char		filename[FILENAME_MAX];
    float		mb;
    int			i, index, rows, cols;

    browserMatrix = [tupleBrowser matrixInColumn:0];
    index = [browserMatrix selectedRow];
    if ( index < 0 ) {
        for ( i = 0; i < 4; i ++ ) {
	    [fileForm setStringValue:"" at:i];
	}
	return self;
    }
    hTuple = [tupleList objectAt:index];
    nt = [hTuple ntuple];
    rows = h_getNtNdata(nt);
    cols = h_getNtDim(nt);
    mb = (4*rows*cols)/1000000.;
    
    strcpy( filename, NXHomeDirectory() );
    index = strspn( [hTuple filename], filename );
    if ( index != (strlen(filename) + 1) ) {
    	strcpy( filename, [hTuple filename]); /* not in home directory */
    } else {
    	strcpy( filename, "~");		/* file in home directory */
	strcat( filename, [hTuple filename]+(index-1) );
    }
    
    [ fileForm setStringValue:filename at:0];
    [ fileForm setIntValue:cols at:1];
    [ fileForm setIntValue:rows at:2];
    [ fileForm setFloatValue:mb at:3];
    return self;
}    
- updateView
{
    id                  browserMatrix;

    browserMatrix = [tupleBrowser matrixInColumn:0];
    if ( !selectedPlot ) {
        [browserMatrix selectCellAt:-1 :-1];
	return self;
    }
    [self setTuple:[selectedPlot ntuple]];
    if (selectedTuple == NULL) {
        [browserMatrix selectCellAt:-1 :-1];
	return self;
    }
    return self;
}
- setTuple:(ntuple) atuple
{
    id                  browserMatrix;
    id			hTuple;
    unsigned int	i, count;
    
    if (selectedTuple == atuple)
	return self;
    selectedTuple = atuple;
    if (selectedTuple == NULL)
	return self;
    browserMatrix = [tupleBrowser matrixInColumn:0];
    count = [tupleList count];
    for ( i = 0; i < count; i++ ) {
        hTuple = [tupleList objectAt:i];
        if ( selectedTuple == [hTuple ntuple] ) {
	    [ browserMatrix selectCellAt:i :0];
	    [ self browserSelect:self];
	    break;
	}
    }
    return self;
}
/* Delegate Methods for NXBrowsers */
- (int) browser: sender fillMatrix: matrix inColumn: (int) column
{
    id                  aCell;
    id			hTuple;
    const char		*title;
    int                 i, count;

    count = [tupleList count];
    for (i = 0; i < count; i++) {
	[matrix insertRowAt:i];
	aCell = [matrix cellAt:i :0];
	hTuple = [tupleList objectAt:i];
	title = [hTuple title];
	if ( title && strcmp(title, "") ) {
	    [aCell setStringValue:title];
	} else {
	    [aCell setStringValue:"<none>"];
	}
	[aCell setLeaf:YES];
	[aCell setLoaded:YES];
    }
    [matrix allowEmptySel:NO];
    return count;
}
- setMsgMatrix:anObject
{
    float	gray;
    int		i, rows, cols;
    
    msgMatrix = anObject;
    gray = [msgMatrix backgroundGray ];
    [msgMatrix getNumRows:&rows numCols:&cols];
    for ( i = 0; i < rows; i++ ) {
       [[msgMatrix cellAt:i :0] setTextGray:gray];
    }
    return self;
}
/* Obsolete methods, maintained for backward compatibility */
- newTuple:(ntuple) nt 
{

   [self addTuple:nt];
   return self;
}
@end
