/* Spread Sheet like n-tuple browser	by Imran Qureshi	August 1992
 *
 * Copyright (C)  1992  The Board of Trustees of  
 * The Leland Stanford Junior University.  All Rights Reserved.
 */

#import "SpreadSheetMgr.h"

const char SpreadSheetMgr_h_rcsid[] = SPREADSHEETMGH_H_ID;
const char SpreadSheetMgr_m_rcsid[] = "$Id: SpreadSheetMgr.m,v 2.7.2.1 1994/01/05 02:23:14 rensing Exp $";

#import <assert.h>

#import "HDrawApp.h"
#import "InspectFunc.h"
#import "InspectTuple.h"
#import "TileScrollView.h"

#define		INCREMENT	25

@implementation SpreadSheetMgr
+ new:sender
{
    NXBundle           *bundle;
    id                  mgrView, aWindow;
    char                buffer[MAXPATHLEN + 1];

    bundle = [NXBundle bundleForClass:[self class]];
    if ([bundle getPath:buffer forResource:"SpreadSheet" ofType:"nib"]) {
	[NXApp loadNibFile:buffer owner:self
	 withNames:YES fromZone:[self zone]];
    }
    aWindow = NXGetNamedObject("killWindow", self);
    mgrView = (id)[[[aWindow contentView] subviews] objectAt:0];
    [mgrView appDidInit:sender];
    self = mgrView;
    window = aWindow;
    hDraw = sender;
    return self;
}

/*** for the palette **/
- (const char*)inspectorName
{
 	return "SpreadSheetInspector";
}

-setRows:(int)rows columns:(int)cols
{
	int		oldRows;
	int		i;
	NXRect	rect;
	
	/* turn off drawing (to the screen) */
	[window disableFlushWindow];
	oldRows = numRowsD;
	numRowsD = rows; numColsD = cols;
	[cellMatrix renewRows:numRowsD cols:numColsD];
	[cellMatrix sizeToCells];
	[cellMatrix getFrame:&rect];
	[cellMatrix update];
	[spreadView sizeTo:rect.size.width :rect.size.height];
	[lineNumberMatrix renewRows:numRowsD cols:1];
	[lineNumberMatrix sizeToCells];
	for (i = oldRows; i < numRowsD; i++)
			[[lineNumberMatrix cellAt:i :0] setIntValue:i];

	/* update scroller */
	[scrollView reflectScroll:[[scrollView subviews] objectAt:0]];
	[scrollView update];
	//[self display];
	/* send results to screen */
	[[window reenableFlushWindow] flushWindow];
	return self;
}
-awake
{
    [super awake];
	//printf("awake\n");
    /* class-specific initialization goes here */
    return self;
}
-initFrame:(const NXRect *)frameRect
{
    [super initFrame:frameRect];
    numRowsD = DEFAULT_ROWS;
    numColsD = DEFAULT_COLS;
    scrollView = [[TileScrollView alloc] initFrame:frameRect];
    [scrollView setAutosizing:
     (NX_MINXMARGINSIZABLE | NX_WIDTHSIZABLE |
      NX_MAXXMARGINSIZABLE | NX_MINYMARGINSIZABLE |
      NX_HEIGHTSIZABLE | NX_MAXYMARGINSIZABLE)];
    [self addSubview:scrollView];
    spreadView = [[View alloc] initFrame:frameRect];
    [self appDidInit:self];
    [self setAutoresizeSubviews:YES];
    return self;
}
-(ntuple)ntuple
{
	return tuple;
}
-setColumnNameMatrix:(id)matrix
{
	columnNameMatrix = matrix;
	return self;
}
-setLineNumberMatrix:(id)matrix
{
	lineNumberMatrix = matrix;
	return self;
}
-open:sender
{
	id	myOpenPanel;
	int	j;
	myOpenPanel = [OpenPanel new];
	[myOpenPanel setTitle:"Open a spreadsheet"];
	[myOpenPanel setPrompt:"File:"];
	j = [myOpenPanel runModal];
	/* if user cancelled, just return */
	if (!j) return self;
	[self openFile:(char*)[myOpenPanel filename]];
	return self;

}
-openFile:(char*)afilename;
{	
	minRowT = 0;
	
	strcpy(filename,afilename);
	currentFile = fopen(filename,"r");
	assert(currentFile);
	
	/**ntuple h_fileParse(FILE* ifile, ntuple oldnt, int verbose);**/
	tuple = h_fileParse(currentFile, NULL, FALSE);
	assert(tuple);
	
	[self tupleToSpreadSheet:tuple];
	fclose(currentFile);
	return self;
}
-save:sender
{	
	printf("Saving file\n");
	currentFile = fopen(filename,"w");
	h_nt2text( currentFile, tuple );
	fclose(currentFile);
	return self;
		
}
-tupleToSpreadSheet:(ntuple)atuple
{
	int x=0,y=0;
	NXRect	rect;
	
	tuple = atuple;
	numRowsD = MIN( h_getNtNdata(tuple), DEFAULT_ROWS );
	
	newTupleFlag = NO;
	[[scrollView window] disableFlushWindow];

	[[scrollView window] setTitle:h_getNtTitle(atuple)];
	[[scrollView window] update];
	
	[columnNameMatrix renewRows:1 cols:h_getNtDim(atuple)];
	[columnNameMatrix sizeToCells];
		
	/**set the column names */
	for(x=0; x<h_getNtDim(atuple);x++)
		[[columnNameMatrix cellAt:0 :x] setStringValue:h_getNtLabel(atuple,x)];
		
	/** resize the cellMatrix to fit the cells */
	x = h_getNtDim(atuple);
	[cellMatrix renewRows:numRowsD cols:x];
	[cellMatrix sizeToCells];
	[cellMatrix getFrame:&rect];
	[spreadView sizeTo:rect.size.width :rect.size.height];
			
	/** read data **/
	for (y=0;y<h_getNtDim(atuple);y++) {
	 	float	*floatArray;
		floatArray = (float*)h_getNtColumn(atuple,y);
		for (x=0; x < numRowsD; x++) 
			[[cellMatrix cellAt:x :y] setFloatValue:floatArray[x]];
	}

	[scrollView update];
	[scrollView reflectScroll:[[scrollView subviews] objectAt:0]];
	[[[scrollView window] reenableFlushWindow] flushWindow];
	minRowT = 0;
	maxRowT = numRowsD - 1;
	return self;
}
-readMore:sender
{
	int	newRows;
	int	i;
	int	x, y;
		
	newRows = INCREMENT;
	if ( (maxRowT+newRows) > (h_getNtNdata(tuple) -1) ) {
	    newRows = h_getNtNdata(tuple) - maxRowT - 1;
	}
	if ( newRows <= 0 ) {
	    NXBeep();
	    return self;
	}
	for (i=0; i < newRows; i++) {
		[cellMatrix removeRowAt:0 andFree:NO];
		[cellMatrix addRow];
		[cellMatrix sizeToCells];
	}	
	for (y=0;y<h_getNtDim(tuple);y++) {
	    float	*floatArray;
	    i=0;
	    floatArray = (float*)h_getNtColumn(tuple,y);
	    for (x=numRowsD - newRows; x < numRowsD; x++,i++) 
		[[cellMatrix cellAt:x :y]
		    setFloatValue:floatArray[i+maxRowT]];
	}
	maxRowT += newRows;
	minRowT += newRows;
	
	/** update the line numbers */
	for (i = 0; i < numRowsD; i++) {
		[[lineNumberMatrix cellAt:i :0] setIntValue:i+minRowT];
	}
	
	[self redisplay];
	return self;
}
-readLess:sender
{
	int	newRows;
	int	i;
	int	x,y;
	
	newRows = INCREMENT;
	if ( (minRowT-newRows) < 0 ) {
	    newRows = minRowT;
	}
	if ( newRows <= 0 ) {
	    NXBeep();
	    return self;
	}	
	for (i=0; i < newRows; i++) {
		[cellMatrix removeRowAt:(numRowsD-1) andFree:NO];
		[cellMatrix insertRowAt:0];
		[cellMatrix sizeToCells];
	}
	minRowT -= newRows;
	
	for (y=0;y<h_getNtDim(tuple);y++) {
	 	float	*floatArray;
		i=0;
		floatArray = (float*)h_getNtColumn(tuple,y);
		for (x = 0; x < newRows; x++,i++) 
		    [[cellMatrix cellAt:x :y] 
			setFloatValue:floatArray[i+minRowT]];
	}
	maxRowT -= newRows;
	
	/** update the line numbers */
	for (i = 0; i < numRowsD; i++) {
		[[lineNumberMatrix cellAt:i :0] setIntValue:i+minRowT];
	}
	
	[self redisplay];
	return self;
}
-redisplay
{
	[[scrollView window] disableFlushWindow];
   
	[lineNumberMatrix update];
	[cellMatrix update];
	[spreadView update];
	[scrollView reflectScroll:[[scrollView subviews] objectAt:0]];
	[scrollView update];

	[[[scrollView window] reenableFlushWindow] flushWindow];
   	return self;
}

/***** MEthods for accessing data ****/
-(float*)row:(int)number
{
	float	*floatArray;
	int	size;
	
	/**float *h_getNtData( ntuple nt, int i_nt, float *f, int *fSize );**/
	floatArray = h_getNtData(tuple,number,NULL, &size);
	
	return floatArray;
}
-setRow:(int)number to:(float*)data
{
	/**int h_arrayReplData( ntuple nt, int i_nt, float *data );*/

	h_arrayReplData(tuple, number, data);
	return self;
}
-(float*)column:(int)number
{
	float	*floatArray;
		
	/**float *h_getNtData( ntuple nt, int i_nt, float *f, int *fSize );**/
	floatArray = (float*)h_getNtColumn(tuple,number);
	
	return floatArray;
}
-addColumn:(char*)name with:(float*)data
{
	int		i,j;
	
	i = h_getNtDim(tuple);
	i--;  /* as dimensions start from 1 and everything else starts from 0 */
	tuple->data[i] = data;
	
	[self addColumn:self];
	for (j=minRowT; (j<=maxRowT) && (j < h_getNtNdata(tuple)); j++) 
		[[cellMatrix cellAt:j-minRowT :i] setFloatValue:data[j]];
		
	return self;
	

}
-addColumn:sender
{
	int 	i;
	i = h_addColumn(tuple);
	//h_setNtLabel(tuple, i,name );

	/**Now for the graphic part **/
	[columnNameMatrix addCol];
	[columnNameMatrix sizeToCells];
	//[[columnNameMatrix cellAt:0 :i] setStringValue:name];
	//[columnNameMatrix update];
	
	[cellMatrix addCol];
	[cellMatrix sizeToCells];

	{
		NXRect	rect;
		[cellMatrix getFrame:&rect];
		[spreadView sizeTo:rect.size.width :rect.size.height];
	}

	[self redisplay];
	return self;
}
-addRow:sender
{
	int 	i;
	float 	*array;
	i = h_getNtDim(tuple);
	
	array = (float*)malloc((i+1)*sizeof(float));
	/**int h_arrayFill(ntuple nt, float *data );**/
	
	h_arrayFill(tuple,array);
	//h_setNtLabel(tuple, i,name );

	/**Now for the graphic part **/
	//[columnNameMatrix addCol];
	//[columnNameMatrix sizeToCells];
	//[[columnNameMatrix cellAt:0 :i] setStringValue:name];
	//[columnNameMatrix update];
	
	//[cellMatrix addCol];
	//[cellMatrix sizeToCells];

	//{
	//	NXRect	rect;
	//	[cellMatrix getFrame:&rect];
	//	[spreadView sizeTo:rect.size.width :rect.size.height];
	//}

	//[self redisplay];
	return self;
}
-temp:sender
{
	return self;
}
-addColFunction:sender
{
	id	inspectFunc;
	
	inspectFunc = [[InspectFunc alloc] initInspFor:hDraw];
	[inspectFunc newColumnFunction:
		[[hDraw inspectTuple] currentHTuple]];
	
	[self tupleToSpreadSheet:tuple];

	return self;
}
-addRowFunction:sender
{
	id	inspectFunc;
	
	inspectFunc = [[InspectFunc alloc] initInspFor:hDraw];
	[inspectFunc newFunction:[[hDraw inspectTuple] currentHTuple]];
	
	[self tupleToSpreadSheet:tuple];
	return self;
}
/**** DELEGATE METHOD FOR TEXT OBJECT ******/
-textDidEnd:textObject endChar:(unsigned short)whyEnd
{
	int		row,col,size;
	float	*floatArray;
	
	//printf("text did end\n");
	if (newTupleFlag==YES) {
		int		i;
		for (i=0; i<numRowsD; i++) {
			float	*array;
			array = (float*)calloc(h_getNtDim(tuple)+1,sizeof(float));
			h_arrayFill(tuple,array);
		}
	}
			
	row = [cellMatrix selectedRow];
	row += minRowT;  /** this is the actual row in the document **/
	col = [cellMatrix selectedCol];
	/**float *h_getNtData( ntuple nt, int i_nt, float *f, int *fSize );**/
	floatArray = h_getNtData( tuple, row, NULL, &size );
	
	floatArray[col] = [[cellMatrix selectedCell] floatValue];
	h_arrayReplData( tuple, row, floatArray );
	
	//printf("value = %f\n",[[cellMatrix selectedCell] floatValue]);
	return self;
}
-appDidInit:(id)sender
{
	NXRect	rect;
	//printf("appDidInit:\n");
	
	newTupleFlag = YES;
	
	//printf("scrollView = %x",scrollView);
	//scrollView = NXGetNamedObject("TileScrollView",self);
	//printf("scrollView = %x",scrollView);
	
	/*  set up the scroll view */
	[scrollView setBackgroundGray:NX_LTGRAY];	
	[scrollView setDocView:spreadView];
	[scrollView setVertScrollerRequired:YES];
	[scrollView setHorizScrollerRequired:YES];
	[scrollView setDynamicScrolling:YES]; 
	[scrollView setAutodisplay:YES];
	
	[spreadView setFlipped:YES];
	
	[[scrollView docView] setAutosizing:NX_WIDTHSIZABLE];
	
	/*  make everything autodisplay */
	[spreadView setAutodisplay:NO];
	//[cellMatrix renewRows:0 cols:0];
	
	{
		id		cellPrototype;
		NXSize	size={80.0, 19.0};
		
		cellPrototype = [[TextFieldCell alloc] initTextCell:"           "];
		[cellPrototype setTextGray:NX_BLACK];
		[cellPrototype setAlignment:NX_RIGHTALIGNED];
		[cellPrototype setBordered:YES];
		[cellPrototype setEditable:YES];
  		cellMatrix = [[Matrix alloc] initFrame:&rect mode:NX_TRACKMODE
				prototype:cellPrototype numRows:1 numCols:1];
		[cellMatrix setCellSize:&size];
		[cellMatrix setPrototype:cellPrototype];
		[cellMatrix setCellBackgroundGray:NX_WHITE];
		size.width = 0.0; size.height = 0.0;
		[cellMatrix setIntercell:&size];
		[cellMatrix removeColAt:0 andFree:YES];
		[cellMatrix setAutodisplay:NO];
		[cellMatrix setTextDelegate:self];
	}

	/*  set number of rows and columns */
	[cellMatrix renewRows:numRowsD cols:numColsD];
	[spreadView addSubview:cellMatrix];
	
		
	[cellMatrix sizeToCells];
	
		/** size and move everything */
	{
		int width;
		
		/** move the stuff */
		[cellMatrix getFrame:&rect];
		[cellMatrix moveTo:0 :0];
		width = rect.origin.x + NX_SCROLLERWIDTH + 12.0;
		
		/*** size the stuff ***/
		[cellMatrix getFrame:&rect];
		width += rect.size.width;
		[spreadView sizeTo:rect.size.width :rect.size.height];
	}
	
	/* update scroller */
	[scrollView reflectScroll:[[scrollView subviews] objectAt:0]];
	[scrollView update];
	[window orderFront:self];
	
	/** create a new tuple **/
	tuple = h_new(numColsD);		
	return self;

}
-read:(NXTypedStream*)typedStream
{
	//printf("SSM read:\n");
	[super read:typedStream];
	NXReadTypes(typedStream,"ii",&numRowsD,&numColsD);
	scrollView = NXReadObject(typedStream);
	spreadView = NXReadObject(typedStream);
	cellMatrix = NXReadObject(typedStream);
	lineNumberMatrix = NXReadObject(typedStream);
	columnNameMatrix = NXReadObject(typedStream);
	return self;
}
-write:(NXTypedStream*)typedStream
{
	//printf("SSM write:\n");
	[super write:typedStream];
	NXWriteTypes(typedStream,"ii",&numRowsD,&numColsD);
	NXWriteObject(typedStream,scrollView);
	NXWriteObject(typedStream,spreadView);
	NXWriteObject(typedStream,cellMatrix);
	NXWriteObjectReference(typedStream, lineNumberMatrix);
	NXWriteObjectReference(typedStream, columnNameMatrix);
	
	return self;
}

@end
