

//	Copyright H. Giesen, University of Koblenz-Landau 1996

#import "BrowserController.h"
#import "Controller.h"
#import "MyBrowserCell.h"
#import "BibliographicFile.h"
#import "BibTeXObject.h"
#import "DragView.h"
#import "Preferences.h"


#define NORMAL
//	#define LAZY
//	#define VERY_LAZY


@implementation BrowserController


- (void) setUpPopUpListAt:(int)inx
{
	NXRect		titleFrame;

	if( [theBrowser getTitleFrame:&titleFrame ofColumn:inx]==NULL )
		if( [theBrowser getTitleFrame:&titleFrame ofColumn:0]==NULL ) return;

	titleFrame.W -= 4;
	titleFrame.H -= 4;
	titleFrame.X += 2;
	titleFrame.Y += 2;

	if( popUpMatrix[inx].button ) return;	// already defined

	popUpMatrix[inx].button = [[Button alloc] initFrame:&titleFrame];
	// the tag of this button is the selected (default) popUpType

	popUpMatrix[inx].list = [[PopUpList alloc] init];
	// the tag of listitems (MenuCells) is the corresponding popUpType
	// the tag of list's Matrix is the corresponding browser column

	[[popUpMatrix[inx].list setAction:@selector(bibPopup:)] setTarget:self];
	NXAttachPopUpList( popUpMatrix[inx].button, popUpMatrix[inx].list );

	// fill the popUpMenu and set the initial text
	// addItem creates and returns a MenuCell
	//	
	if( inx==0 ){
		[[popUpMatrix[inx].list addItem:"file"] setTag:D_FILE];
		[popUpMatrix[inx].button setTitle:"file"];
		[popUpMatrix[inx].button setTag:D_FILE];
	}
	if( inx==1 ){
		[[popUpMatrix[inx].list addItem:"keys (sorted)"] setTag:D_KEY_SORTED];
		[[popUpMatrix[inx].list addItem:"keys (as read)"] setTag:D_KEY_AS_READ];
		[[popUpMatrix[inx].list addItem:"entries"] setTag:D_ENTRY];
		[popUpMatrix[inx].button setTitle:"keys (sorted)"];
		[popUpMatrix[inx].button setTag:D_KEY_SORTED];
	}
	if( inx>1 ){
		[[popUpMatrix[inx].list addItem:"keys (sorted)"] setTag:D_KEY_SORTED];
		[[popUpMatrix[inx].list addItem:"keys (as read)"] setTag:D_KEY_AS_READ];
		[popUpMatrix[inx].button setTitle:"keys (sorted)"];
		[popUpMatrix[inx].button setTag:D_KEY_SORTED];
	}

	[popUpMatrix[inx].list sizeToFit];
	[theBrowser addSubview:popUpMatrix[inx].button];
	//	itemlist is the matrix of MenuCells used by the Menu
	[[popUpMatrix[inx].list itemList] setTag:inx];
	[popUpMatrix[inx].button display];
}


- (void) setUp
{
	int		i;

	preferences = [Preferences new];

	[theBrowser setCellClass:[MyBrowserCell class]];
	[theBrowser setTitle:"bibFile" ofColumn:0];
	[theBrowser setAction:@selector(singleClick:)];
	[theBrowser setDoubleAction:@selector(doubleClick:)];
	[theBrowser reuseColumns:YES];
	[theBrowser setMultipleSelectionEnabled:YES];
	[theBrowser setBranchSelectionEnabled:YES];
	[theBrowser useScrollBars:YES];
	[theBrowser useScrollButtons:YES];

	//	the theBrowser must be the first responder :
	[theBrowser acceptArrowKeys:YES andSendActionMessages:YES];
	[theBrowser setTarget:self];
	[theBrowser setAutodisplay:NO];

	[theBrowser setMaxVisibleColumns:3];
	for(i=0; i<2; i++){
		[self setUpPopUpListAt:i];
	}
}


// both "icons" are of class DragView
- (void) setUpIcons:fIcon :eIcon
{
	entryIcon = eIcon;
	fileIcon = fIcon;
	[fileIcon clear];
	[entryIcon clear];
}


- (NXBrowser *) theBrowser
{
	return theBrowser;
}


//	return a list of NXBrowserCells
- (List *)selectedFiles
{
	if( tempList ) [tempList empty];
	else tempList = [[List alloc] initCount:10];
	[[theBrowser matrixInColumn:0] getSelectedCells:tempList];
	return tempList;
}


- (BibliographicFile *)selectedFile
{
	List *aList = [self selectedFiles];
	if( [aList count]==0 ) return nil;
	return [[aList objectAt:0] fileObject];
}


- bibPopup:sender	// sender is matrix of a popUpList
{
	int	col = [sender tag];	// tag is the browsercolumn

	if( col<0 ) return self;

	[popUpMatrix[col].button setTag:[[sender selectedCell] tag]];
	[theBrowser doClick:[theBrowser matrixInColumn:(col>0)?col-1:0]];
	return self;
}


- singleClick:sender	// sender is BibBrowser
{
	int		i = 0;
	int		selCol = [sender selectedColumn];
	Matrix	*matrix;
	List	*selList;
	char	locBuffer[256];

	if( selCol<0 ) return self;

	matrix	= [sender matrixInColumn:selCol];
	selList	= [matrix getSelectedCells:nil];

	if( [selList count]==0 ){	// nothing selected
		[sender getPath:locBuffer toColumn:selCol];
		if( locBuffer[0] == '\0' ){
			locBuffer[0] = '/';
			locBuffer[1] = '\0';
		}
		[sender setPath:locBuffer];
		[entryIcon clear];
		if( [self displayTypeInCol:selCol]==D_FILE ) [fileIcon clear];
		[[NXApp delegate] browserDidChange:sender];
		[[[bibWindow reenableDisplay] displayIfNeeded] reenableFlushWindow];
		[sender displayColumn:selCol];
		[selList free];
		return self;
	}

	if( [self displayTypeInCol:selCol]==D_FILE ){
		[[NXApp delegate] P:self];
		[fileIcon setList:selList];
		[entryIcon clear];
	
		[selList free];
		[[NXApp delegate] browserDidChange:sender];
		[[[bibWindow reenableDisplay] displayIfNeeded] reenableFlushWindow];
		[[NXApp delegate] V:self];
		return self;
	}

	//	show column entrytypes ?
	if( [self displayTypeInCol:selCol]==D_ENTRY ){
		[entryIcon clear];
		[selList free];
		[[NXApp delegate] browserDidChange:sender];
		[[[bibWindow reenableDisplay] displayIfNeeded] reenableFlushWindow];
		return self;
	}

	// [self displayTypeInCol:selCol]==D_KEY_SORTED	
	[entryIcon setList:selList];
	[selList free];

	[[NXApp delegate] browserDidChange:sender];
	
	//[selectionButton display];
	while( popUpMatrix[i].button ){
		[popUpMatrix[i++].button display];
	}
	[[[bibWindow reenableDisplay] displayIfNeeded] reenableFlushWindow];
	return self;
}


- doubleClick:sender
{
	NXTextStyle *theStyle;

	int	selCol;
	Matrix *matrix;
	BibliographicFile *fileObj;
	char	locBuffer[1024];

	selCol = [sender selectedColumn];
	matrix = [sender matrixInColumn:selCol];
	fileObj = [[matrix selectedCell] fileObject];

	switch( [self displayTypeInCol:selCol] ){
		case D_FILE :
			{
				if( BIBTEST==NO ) return self;
				[fileObj showFile];	
				return self;
			}
	
		case D_KEY_SORTED  :
		case D_KEY_AS_READ :
			{
				BibTeXObject *obj = [[matrix selectedCell] object];	// ?????
				locType theRange = [obj range];
				char *buf = [obj buffer];
				
				[testDocView setSel:0 :[testDocView textLength]];
				theStyle = [testDocView defaultParaStyle];
				[testDocView setParaStyle:theStyle];
		
				[testDocView replaceSel:&buf[theRange.start]
					length:theRange.length];		
				[testDocView setSel:0 :0];
				[testDocView scrollSelToVisible];
				[testPanel setDelegate:self];
				sprintf( locBuffer, "%s in %s",
					[[matrix selectedCell] stringValue], [fileObj fileName] );
				[testPanel setTitle:locBuffer];
				[testPanel orderFront:self];
				[asciiDragView setTextObject:testDocView];
				[testDocView addText:"\n"];
		
				if(0)[obj callTheEditorForFile:[fileObj fullPath]
						inLine:[obj line]];
				return self;
			}

		case D_ENTRY : return self;
		default : return self;
	}

	return self;
}


- entryObjectChanged:(BibTeXObject *)obj
{
	int		pos;
	int		lastCol	= [theBrowser lastColumn];
	int		dspType = [self displayTypeInCol:lastCol];
	List	*objList;
	Matrix	*matrix = [theBrowser matrixInColumn:lastCol];
	int		selRow	= [matrix selectedRow];
	MyBrowserCell 	*selCell = [theBrowser selectedCell];
	MyBrowserCell 	*newCell;

	if( dspType!=D_KEY_SORTED )
		if( dspType!=D_KEY_AS_READ ) return self;

	if( [self displayTypeInCol:lastCol-1]!=D_FILE ){
		objList = [[selCell fileObject]
			listForType:[[theBrowser matrixInColumn:lastCol-1] selectedRow]
			sorted:dspType==D_KEY_SORTED];
	}
	else
		if( [self displayTypeInCol:[theBrowser lastColumn]]==D_KEY_AS_READ )
			 objList = [[selCell fileObject] listOfBibObjects];
		else objList = [[selCell fileObject] listOfSortedBibObjects];

	usedEntryList = objList;
	if( obj==[selCell object] ){
		[[matrix removeRowAt:selRow andFree:NO] sizeToCells];
	}
	pos = [objList indexOf:obj];
	if( pos<0 ){
		newCell = nil;
	}
	else{	//NORMALBROWSER
		[matrix insertRowAt:pos];
		//newCell = [matrix cellAt:pos :0];
		newCell = [theBrowser getLoadedCellAtRow:pos inColumn:lastCol];
		[newCell setEnabled:YES];
		[obj setStringOf:[obj key] to:newCell];
		[newCell setLeaf:YES];
		[newCell setObject:obj inFile:[selCell fileObject]];
		[newCell setLoaded:YES];
	}

	[matrix sizeToCells];
	[matrix selectCell:newCell];
	{
		List *selList = [matrix getSelectedCells:nil];
		[entryIcon setList:selList];
		[selList free];
	}
	[matrix scrollCellToVisible:pos :0];
	[theBrowser displayColumn:[theBrowser lastColumn]];
	return self;
}


// includesType() returns YES if type is included within types.

BOOL includesType (const NXAtom *types, NXAtom type)
{
	if (types)
		while (*types){
			//fprintf( stderr, "%s\n", *types );
			if (*types++ == type) return YES;
		}
	return NO;
}

- getBibdata:(id)pasteboard
		userData:(const char *)serviceArgs
		error:(char **)errorMessage
{
	int length;
	const char *data;

	if( includesType([pasteboard types], NXAsciiPboardType) ){
		[pasteboard readType:NXAsciiPboardType data:&data length:&length];		
		[testDocView setSel:0 :[testDocView textLength]];
		[testDocView setParaStyle:[testDocView defaultParaStyle]];
	
		[testDocView replaceSel:data length:length];		
		[testDocView setSel:0 :0];
		[testDocView scrollSelToVisible];
		[testPanel setDelegate:self];
		[testPanel orderFront:self];
		[asciiDragView setTextObject:testDocView];
	}
	else *errorMessage = "could not copy selection";
	return self;
}


- selectFile:(BibliographicFile *)aFile
{
	Matrix	*matZero = [theBrowser matrixInColumn:0];
	int	rowCount, colCount, i;

	[matZero getNumRows:&rowCount numCols:&colCount];
	[matZero selectCellAt:-1 :-1];	// deselect

	for( i=0; i<rowCount; i++ ){
		if( [[theBrowser getLoadedCellAtRow:i inColumn:0] fileObject]==aFile ){
			[[matZero selectCellAt:i :0] scrollCellToVisible:i :0];
			[matZero sendAction];	// calls - singleClick:
			[theBrowser displayColumn:0];
			//[theBrowser loadColumnZero];
			return self;
		}
	}
	return self;
}

- (int) fillMatrix:locMatrix withFiles:(List *)listOfFiles
{
	int i;

	//	listOfFiles is the sorted list of all loaded files
	if( (listOfFiles==nil) || ([listOfFiles count]==0) ){
		[fileIcon clear];	// no file selected
		[entryIcon clear];
		return 0;
	}

	for( i=0; i<[listOfFiles count]; i++ ){
		NXBrowserCell *newCell;
		BibliographicFile *fileObj = [listOfFiles objectAt:i];

		[locMatrix addRow];
		newCell = [locMatrix cellAt:i :0];
		[newCell setEnabled:YES];
		[[[[newCell	setStringValue:[fileObj fileName]]
					setLeaf:NO]
					setLoaded:YES]
					setObject:nil inFile:fileObj];
	}
	[fileIcon clear];	// no file selected
	[entryIcon clear];
	return [listOfFiles count];
}


- resetBrowser:sender
{
	[theBrowser loadColumnZero];
	[[[bibWindow reenableDisplay] displayIfNeeded] reenableFlushWindow];
	return self;
}


- (int) fillMatrix:locMatrix withKeysForFile:(BibliographicFile *)file
			display:(int)dspType
{
	int				i;
	MyBrowserCell	*newCell;
	BibTeXObject 	*litObj;
	List			*theList;

	[[bibWindow disableDisplay] disableFlushWindow];//  enabled in singleClick

	[entryIcon clear];

	if( dspType==D_KEY_AS_READ ) theList = [file listOfBibObjects];
	else						 theList = [file listOfSortedBibObjects];

	usedEntryList = theList;

	litObj = [theList objectAt:0];
	for( i=0; litObj; i++ ) {
		[locMatrix addRow];
		newCell = [locMatrix cellAt:i :0];
		[newCell setEnabled:YES];
		[litObj setStringOf:[litObj key] to:newCell];
		[newCell setLeaf:YES];
		[newCell setObject:litObj inFile:file];
		[newCell setLoaded:YES];
		litObj = [theList objectAt:i+1];
	}
	return i;
}


- (int) fillMatrix:locMatrix withKeysForFile:(BibliographicFile *)file
					andEntryType:(int)entryType display:(int)dspType
{
	int	i;
	BibTeXObject		*litObj;
	List				*typedList;
	NXBrowserCell		*newCell;

	[[bibWindow disableDisplay] disableFlushWindow];//  enabled in singleClick

	[entryIcon clear];

	typedList = [file listForType:entryType sorted:dspType==D_KEY_SORTED];
	usedEntryList = typedList;
	for( i=0; i<[typedList count]; i++ ){
		litObj = [typedList objectAt:i];
		[locMatrix addRow];
		newCell = [locMatrix cellAt:i :0];
		[newCell setEnabled:YES];
		[litObj setStringOf:[litObj key] to:newCell];
		[[newCell	setLeaf:YES]
					setObject:litObj inFile:file];
		[newCell 	setLoaded:YES];
	}
	return [typedList count];
}


- (int) fillMatrix:locMatrix withEntryTypesForFile:(BibliographicFile *)file
{
	int				i;
	NXBrowserCell	*newCell;
	List			*entryNameList = [preferences entryNameList];

	[[bibWindow disableDisplay] disableFlushWindow];// enabled in singleClick

	for( i=0; i<[entryNameList count]; i++ ){
		[locMatrix addRow];
		newCell = [locMatrix cellAt:i :0];
		[newCell setStringValue:(const char *)[entryNameList objectAt:i]];
		[[newCell setLeaf:NO] setObject:nil inFile:file];
		[newCell setLoaded:YES];
		[newCell setEnabled:([file countForType:i]!=0)];
	}
	return [entryNameList count];
}


- (Matrix *) matrixInColumn:(int) col
{
	return [theBrowser matrixInColumn:col];
}


- (void) entryListDidChange:(int)row to:(int)nr
{
	int	lastColumn = [theBrowser lastColumn];
	Matrix	*matrix;

	if( lastColumn==0 ) return;
	if( [self displayTypeInCol:lastColumn-1]!=D_ENTRY ) return;
	matrix = [theBrowser matrixInColumn:lastColumn-1];
	[[theBrowser getLoadedCellAtRow:row inColumn:lastColumn-1] setEnabled:nr>0];
	if( nr==0 ) [matrix selectCellAt:-1 :-1];	// deselect
	[matrix display];
}


- (void) deselectColumn:(int)col
{
	if( col<0 ) col = [theBrowser lastColumn];

	[entryIcon setList:nil];
	[[theBrowser matrixInColumn:col] selectCellAt:-1 :-1];	// deselect

}


- (void) selectList:(List *)aList inColumn:(int)column
{
	int		i, row=0;
	Matrix	*matrix = [theBrowser matrixInColumn:column];

	[matrix selectCellAt:-1 :-1];	// deselect all
	for( i= [aList count]-1; i>=0; i-- ){
		row = [usedEntryList indexOf:[aList objectAt:i]];
		if( row>=0 )
			[matrix setSelectionFrom:row to:row anchor:row lit:YES];
	}
	[matrix scrollCellToVisible:row :0];	// scroll to last row
}


- (void) selectEntryObjects:(List *)aList
{
	int		i, row=0;
	int		column = [theBrowser lastColumn];
	int		dspType = [self displayTypeInCol:column];
	Matrix	*matrix = [theBrowser matrixInColumn:column];
	List	*selList;

	[matrix selectCellAt:-1 :-1];	// deselect all
	
	if( (dspType!=D_KEY_SORTED) )
		if( (dspType!=D_KEY_AS_READ) ) return;

	for( i= [aList count]-1; i>=0; i-- ){
		row = [usedEntryList indexOf:[aList objectAt:i]];
		if( row>=0 )
			[matrix setSelectionFrom:row to:row anchor:row lit:YES];
	}
	selList = [matrix getSelectedCells:nil];
	[entryIcon setList:selList];
	[selList free];
	[matrix scrollCellToVisible:row :0];	// scroll to last row
	[[NXApp delegate] browserDidChange:self]; 
}


- (int)displayTypeInCol:(int)col
{
	return [popUpMatrix[col].button tag];
}


- (int) fillMatrix:locMatrix forFile:(BibliographicFile *)aFile
							 display:(int)dspType
							  select:(int)entryType
{

	if( dspType==D_ENTRY ){
			return [self fillMatrix:locMatrix withEntryTypesForFile:aFile];
	}
	if( entryType==-1 ){	// show all keys
		return [self fillMatrix:locMatrix withKeysForFile:aFile display:dspType];
	}
	// show keys for a selected entryType only
	return [self fillMatrix:locMatrix
			withKeysForFile:aFile andEntryType:entryType display:dspType];
	
	return 0;
}


- browserDidScroll:sender
{
	//[[sender reenableDisplay] display];
	if(0)fprintf( stderr, "%s didScroll %d %d (%d)\n",
		[sender name],
		[sender firstVisibleColumn],
		[sender lastVisibleColumn], [sender lastColumn] );
	[self windowDidResize:sender];
	return self;
}


#ifdef VERY_LAZY
- browser:sender loadCell:cell atRow:(int)row inColumn:(int)column
{
	if(0)fprintf( stderr, "loadCellat %d %d isLoaded=%d\n",
		row, column, [cell isLoaded] );
	if( column==0 ){
		BibliographicFile *fileObj = [[[NXApp delegate] listOfFiles] objectAt:row];

		[cell setEnabled:YES];
		[cell setStringValue:[fileObj fileName]];
		[cell setLeaf:NO];
		[cell setLoaded:YES];
		[cell setObject:nil inFile:fileObj];
		[fileIcon clear];	// no file selected
		[entryIcon clear];
		return self;
	}

	if( column==1 ){
		BibliographicFile *selFile=
			[[[self matrixInColumn:0] selectedCell] fileObject];
		BibTeXObject	*litObj;

		usedEntryList = [selFile listOfBibObjects];
		litObj = [usedEntryList objectAt:row];
		[cell setEnabled:YES];
		[litObj setStringOf:[litObj key] to:cell];
		[cell setLeaf:YES];
		[cell setObject:litObj inFile:selFile];
		[cell setLoaded:YES];
		return self;
	}
	return self;
}


- (int) browser:sender getNumRowsInColumn:(int)column
{
	//fprintf( stderr, "getNumRowsInColumn %d\n", column );
	if( column==0 ){
		return [[[NXApp delegate] listOfFiles] count];
	}
	if( column==1 ){
		BibliographicFile *selFile=
			[[[self matrixInColumn:0] selectedCell] fileObject];
		return [[selFile listOfBibObjects] count];
	}

	return 2;
}
#endif	// very lazy

#ifdef NORMAL
- (int) browser:sender fillMatrix:locMatrix inColumn:(int)column
{
	int		count, dspType, eType;
	BibliographicFile *selFile=
		[[[self matrixInColumn:0] selectedCell] fileObject];
	Matrix	*matrix = [theBrowser matrixInColumn:column-1];
	int	index = [matrix selectedRow];

	if( popUpMatrix[column].button==nil ){
		//fprintf( stderr, "new button\n" );
		[self setUpPopUpListAt:column];
		[popUpMatrix[column].button display];
	}

	if( column==0 ){
		count = [self fillMatrix:locMatrix
					  withFiles:[[NXApp delegate] listOfFiles] ];
		[[NXApp delegate] colZeroIsFilled];
		return count;
	}
	
	if( [self displayTypeInCol:column-1]==D_FILE )
		 eType = -1;	// display keys for all entryTypes
	else eType = index;	// entryType is the selectedRow (by accident)

	switch( dspType = [self displayTypeInCol:column] ){
		case D_FILE :	break;	// col 0 ???
		case D_ENTRY:
		case D_KEY_SORTED  :
		case D_KEY_AS_READ :
			return [self fillMatrix:locMatrix
							forFile:selFile display:dspType select:eType];

		default : return 0;
	}
fprintf( stderr, "ERROR in fillmatrix\n" );
	return 0;	
}
#endif	// normal

//	returns the new state of the menuCell
	// YES = enabled
	//	NO = disabled

- (BOOL)updateMenuFor:menuCell
{
	BOOL	newState=NO;	// .. and the compiler keeps silent

	switch( [menuCell tag] ){
		case CUT			:
		case COPY			:
		case PASTE			:
		case SELECTALL		:
		case ENTERSELECTION : newState = YES; break;

		default : newState = [[NXApp delegate]updateMenuFor:menuCell];
				  break;
		}

	return newState;
}


// copy selected text to findPasteBoard

- enterSelection:sender
{
	[[NXApp delegate] enterSelectionFor:testDocView];

	return self;
}


- windowDidResize:sender
{
	NXRect	titleFrame;
	int		i = 0;

	while( popUpMatrix[i].button ){
		if( [theBrowser getTitleFrame:&titleFrame ofColumn:i] ){
			titleFrame.W -= 4;
			titleFrame.H -= 4;
			titleFrame.X += 2;
			titleFrame.Y += 2;
			if( [popUpMatrix[i].button superview]==nil )
				[theBrowser addSubview:popUpMatrix[i].button];
			[popUpMatrix[i].button setFrame:&titleFrame];
		}
		else [popUpMatrix[i].button removeFromSuperview];
		i++;
	}
	return self;
}


- selectAllIn:matrix column:(int)col
{
	List *selList = nil;
	
	switch( [self displayTypeInCol:col] ){
		case D_FILE :
			selList = [matrix getSelectedCells:nil];
			[fileIcon setList:selList];
			break;

		case D_KEY_SORTED  :
		case D_KEY_AS_READ :
			selList = [matrix getSelectedCells:nil];
			[entryIcon setList:selList];

		default : break;
	}
	if( selList ) [selList free];
	[[NXApp delegate] browserDidChange:self];
	return self;
}


- (BOOL)browser:sender columnIsValid:(int)column
{
	return YES;
}


- (BOOL)browser:sender selectCell:(const char *)entry inColumn:(int)column
{
	return YES;
}


@end


