// Tue Mar  5 20:28:08 MET 1996

#import "MiscSplitBrowser.h"

/*	toDo	fix graphicbug in initial display (on the right)
 *			(which diappears by ther way after niling out a view and then move the divider
 *			 back to the middle)
 */
enum {MiscLeft=0,MiscRight=1};

# define MISCSPLITBROWSER_VERSION 1

@implementation MiscSplitBrowser
+ initialize
{	if(self == [MiscSplitBrowser class])
	{	[self setVersion:MISCSPLITBROWSER_VERSION];
	
	}
	[self setMatrixClass:[Matrix class]];
	return self;
}

static id matrixClass;
+ matrixClass
{	return matrixClass;
}
+ setMatrixClass:theMatrixClass
{	return matrixClass=theMatrixClass;
}

#if 0
- getBounds:(NXRect *)lr
{	NXCoord borderWidth=-5;
	[super getBounds:lr];
	lr->origin.x+=borderWidth,lr->origin.y+=borderWidth;
	lr->size.width-=(borderWidth*2),lr->size.height-=(borderWidth*2);
	return self;
}
#endif

-(Matrix*) createMatrix:(NXRect *) theRect
{	Matrix *theMatrix=[[MiscSplitBrowser matrixClass] alloc];

	 theMatrix=[theMatrix initFrame:theRect];
	[theMatrix setAutoscroll:YES];
	[theMatrix setEmptySelectionEnabled:NO];
	[theMatrix setCellClass:[NXBrowserCell class]];
	[theMatrix setTarget:self],[theMatrix setAction:@selector(didClick:)];

	return theMatrix;
}

- initFrame:(NXRect *) theRect
{	NXRect halfRect=*theRect;
	ScrollView *leftScroll=[ScrollView alloc],*rightScroll=[ScrollView alloc];
	halfRect.size.width/=2;
	leftScroll=[leftScroll initFrame:&halfRect], rightScroll=[rightScroll initFrame:&halfRect];
	[leftScroll setVertScrollerRequired:YES];
	[leftScroll setBorderType:NX_BEZEL];
	[rightScroll setVertScrollerRequired:YES];
	[rightScroll setBorderType:NX_BEZEL];
	[leftScroll	 setDocView: leftMatrix=[self createMatrix:&halfRect]];
	[rightScroll setDocView:rightMatrix=[self createMatrix:&halfRect]];
	[super initFrame:theRect];
	[self setLeftView:leftScroll];
	[self setRightView:rightScroll];
	[self initViews];
	pathSeparator='/';
	return self;
}
- setSizeForMatrix:(Matrix *)theMatrix
{	NXRect	theRect;
	NXSize	cellSize;
	[theMatrix getCellSize:&cellSize];
	[[theMatrix superview] getFrame:&theRect];
	cellSize.width= theRect.size.width;
	[theMatrix setCellSize:&cellSize];
	[theMatrix sizeToCells];
	return self;
}

- sideSplitViewDidResizeSubviews: sender
{	[self setSizeForMatrix:leftMatrix];
	[self setSizeForMatrix:rightMatrix];
	return self;
}

- selectCellNamed:(const char*)theName inMatrix:(Matrix*)theMatrix
{	List *cellList=[theMatrix cellList];
	Cell *currCell;
	int i;
	for(i=0; currCell=[cellList objectAt:i];i++)
	{	if(!strcmp([currCell stringValue],theName))
		{	[theMatrix selectCellAt:i:0];
			[theMatrix scrollCellToVisible:i:0];
			return self;
		}
	} return nil;
}
- setPath:(const char *)thePath
{	char *str=NXCopyStringBuffer(thePath),
		 *ps=strchr(str,pathSeparator),*ps1;
	if(ps) *ps=0;
	[self selectCellNamed:str inMatrix:leftMatrix];
	[self reloadColumn:1];
	if(ps)
	{	ps1=strchr(ps+1,pathSeparator);
		if(ps1) *ps1=0;
		[self selectCellNamed:ps+1 inMatrix:rightMatrix];
	}
	[self sendAction];
	free((void*) str);
	return self;
}

-(char *) getPath:(char *)pathString toColumn:(int) column
{	switch(MAX(column-1,0))
	{	case MiscLeft:
			sprintf(pathString,"%c%s",pathSeparator,[[leftMatrix selectedCell] stringValue]);
			if(strlen(pathString) == 1) pathString[0]=0;
		break;
		case MiscRight:
		{	const char *rptr=[[rightMatrix selectedCell] stringValue];
			sprintf(pathString,"%c%s%c%s",pathSeparator,[[leftMatrix selectedCell] stringValue],
										  rptr? pathSeparator:0,rptr? rptr:"");
		} break;
	} return pathString;
}

- sendAction
{	if(target && action) [NXApp sendAction:action to:target from:self];
	return self;
}

- reloadColumn:(int) theColumn
{	int		numRows;
	Matrix	*theMatrix=nil;
	[window disableFlushWindow];
	switch(theColumn)		// [self matrixOfColumn
	{	case MiscLeft:
			theMatrix=leftMatrix;
		break;
		case MiscRight:
			theMatrix=rightMatrix;
		break;
		default: return nil;
	}
	numRows=[browserDelegate browser:self fillMatrix:theMatrix inColumn:theColumn];
	[theMatrix renewRows:numRows cols:1];
	[self setSizeForMatrix:theMatrix];
	[theMatrix display];
	[[window reenableFlushWindow] flushWindow];
	return self;
}

- didClick:sender
{	if(sender == leftMatrix)
	{	[self reloadColumn:1];
	} return [self sendAction];
}

-(int) indexOfSelectedCellInMatrix:(Matrix*) theMatrix
{	int x,y;
	if(!theMatrix) return -1;
	[theMatrix getRow:&y andCol:&x ofCell:[theMatrix selectedCell]];
	return y;
}

- loadColumnZeroPreserveSel:(BOOL)preserve
{	int		 leftSel=[self  indexOfSelectedCellInMatrix:leftMatrix],
			rightSel=[self indexOfSelectedCellInMatrix:rightMatrix];

	if(preserve) [window disableFlushWindow];
	[self reloadColumn:0];
	if(preserve && leftSel >=0)		[leftMatrix selectCellAt:leftSel:0];
	if([leftMatrix selectedCell])	[self reloadColumn:1];
	if(preserve && rightSel >=0)	[rightMatrix selectCellAt:rightSel:0];
	if(preserve) [[window reenableFlushWindow] flushWindow];
	[self sendAction];
	return self;
}
- loadColumnZero
{	return [self loadColumnZeroPreserveSel:NO];
}

-(Matrix*) matrixInColumn:(int) col
{	switch(col)
	{	case MiscLeft:	return leftMatrix;
		case MiscRight:	return rightMatrix;
	} return nil;
}
-(int) selectedColumn
{	if([rightMatrix selectedCell])	return MiscRight;
	if([leftMatrix selectedCell])	return MiscLeft;
	return -1;
}
-(int) selectedRow
{	Matrix *theMatrix=[self matrixInColumn:[self selectedColumn]];
	if(!theMatrix) return -1;
	else return [self indexOfSelectedCellInMatrix:theMatrix];
}
-(int) lastColumn
{	if(![rightMatrix cellCount]) return		MiscLeft;
	else 						 return		MiscRight;
}
-(Matrix*) selectedMatrix
{	int selCol=[self selectedColumn];
	if(selCol == -1) return nil;
	return [self matrixInColumn:selCol];
}
-(Cell *) selectedCell
{	return [[self selectedMatrix] selectedCell];
}
- emptyValidationForRow:(int)y inMatrix:(Matrix *) theMatrix minCount:(int)min
{	if([theMatrix cellCount] > min)
	{	if(y == [theMatrix cellCount]-1)
			[theMatrix selectCellAt:MAX(y-1,0):0];
		return self;
	} return	nil;
}

- reestablishSelection
{	[window disableFlushWindow];
	if(([self selectedColumn] == MiscLeft) || ![self emptyValidationForRow:[self indexOfSelectedCellInMatrix:rightMatrix]
																  inMatrix:rightMatrix minCount:1])
	{	[self emptyValidationForRow:[self indexOfSelectedCellInMatrix:leftMatrix] inMatrix:leftMatrix minCount:0];
	} [[window reenableFlushWindow] flushWindow];
	return self;
}
- selectPrevious
{
	return self;
}
- selectNext
{
	return self;
}
- acceptArrowKeys:(BOOL) doAccept andSendActionMessages:(BOOL) doSendActions
{
	return self;
}

- (id)target
{	return target;
}
- setTarget:(id)aTarget
{	target=aTarget;
	return self;
}
- (SEL)action
{	return action;
}
- setAction:(SEL)aAction
{	action=aAction;
	return self;
}
- (unsigned short)pathSeparator
{	return pathSeparator;
}
- setPathSeparator:(unsigned short)aPathSeparator
{	pathSeparator=aPathSeparator;
	return self;
}

- (SEL)doubleAction
{	return doubleAction;
}
- setDoubleAction:(SEL)aDoubleAction
{	doubleAction=aDoubleAction;
	return self;
}
- (id)browserDelegate
{	return browserDelegate;
}
- setBrowserDelegate:(id)aBrowserDelegate
{	browserDelegate=aBrowserDelegate;
	return self;
}
- setDelegate:theDelegate
{	[super setDelegate:theDelegate];
	if(![self browserDelegate])
		[self setBrowserDelegate:theDelegate];
	return self;
}
- leftView
{	return leftView;
}
- rightView
{	return rightView;
}
- setDivider:(NXCoord) divx
{	dividerRect.origin.x =divx;
	[window disableFlushWindow];
	[self adjustSubviews];
	[self display];
	[[window reenableFlushWindow] flushWindow];
	return self;
}

- awake
{	[super awake];
	return self;
}

- read:(NXTypedStream *)stream
{	int version;

    [super read:stream];
   
	version = NXTypedStreamClassVersion(stream, "MiscSplitBrowser");

	/*
	 * **** Archiving: READ ME **** This code (and its analogue in write:) is
	 * critical. When you bump MISC_DRAG_VIEW_VERSION, copy the whole _current_
	 * case ("case MISC_DRAG_VIEW_VERSION: ... break;"), and duplicate it.
	 * Change the "MISC_DRAG_VIEW_VERSION" in the old case to the OLD
	 * (pre-bump) version number. Now, dork the "new current" version into
	 * whatever you want. See how this code can now read EITHER version out of
	 * the typed stream?
	 *
	 * If you are adding yet another version, leave the previous versions in
	 * place. That way you can still read archived objects that are more than
	 * one version old. Don't forget to take whatever actions are necessary to
	 * harmonize those old values. For example, if you converted an "int" ivar
	 * to "double", you'd need to (in the old version) to read the int version
	 * into a temp variable, and convert it in to the double var. BJM 5/24/94
	 */
    switch (version)
    {	case 1:
			NXReadTypes(stream,"@::I@",&target,&action,&doubleAction,&pathSeparator,
									   &browserDelegate);
			leftMatrix=NXReadObject(stream);
			rightMatrix=NXReadObject(stream);
		break;
	} return self;
}
- write:(NXTypedStream *)stream
{	[super write:stream];
    
	/*
	 * **** Archiving: READ ME **** Home stretch. Now (just like read:)
	 * duplicate the current case ("case MISC_DRAG_VIEW_VERSION: ... break;").
	 * Once again, change the "MISC_DRAG_VIEW_VERSION" of the first one to the
	 * OLD version number. Now adjust the new/current MISC_DRAG_VIEW_VERSION
	 * (remember, you've bumped it) to the new way of writing vars. See how
	 * this code (because the constant is in the switch statement) always
	 * writes out ONLY the current version, but leaves the old version(s)
	 * around to posterity. DO NOT DELETE THE OLD VERSIONS. Leave them to
	 * clutter up the world. BJM 5/24/94  
	 */
    switch (MISCSPLITBROWSER_VERSION)
    {	case MISCSPLITBROWSER_VERSION:
			NXWriteTypes(stream,"@::I@",&target,&action,&doubleAction,&pathSeparator,
									   &browserDelegate);
			NXWriteObject(stream,leftMatrix); // was writing references
			NXWriteObject(stream,rightMatrix); // was writing references
		break;
	} return self;
}

@end
