/* FontSearch.m				 
 *
 * This is the basic controller of the App. It manages all big abstraction
 * tasks for the panels, documents and connections to the outside.
 *
 * For interface-info see the header file. The comments in this file mostly
 * cover only the real implementation details.
 *
 * Written by: 		Thomas Engel
 * Created:    		23.02.1995 (Copyleft)
 * Last modified: 	06.03.1995
 */

#import "FontSearch.h"
#import "CEBrowserCell.h"

#import <misckit/misckit.h>
#import <misckit/MiscIconWell.h>


@implementation FontSearch

- init
{
	// Basic parts

	id	globalFontsDefault;
	id	ourFontsDefault;
	id	aString;
	char	*defaultValue;

	self = [super init];
	if( !self ) return self;
	
	// To be a little bit more flexible..comment out the lines is you want to
	// use it as a Prefs modul or app internal class.

	if( [NXApp loadNibForLayout:"FontSearch" owner:self] == nil )
	// if( [NXApp loadNibSection:"FontSearch.nib" owner:self] == nil )
	{
		NXRunAlertPanel( NULL, "Couldn't load FontSearch.nib", 
							   "OK", NULL, NULL );
		return nil;
	}

	// The next line is also needed for the prefs modul
	[view removeFromSuperview];

	// No lets get the default values for the searchable paths.

	globalFontsDefault = [MiscString new];
	defaultValue = NXGetDefaultValue( "GLOBAL", "NXFontsPaths" );
	if( defaultValue != NULL )
		[globalFontsDefault setStringValue:defaultValue];

	_activePathList = [List new];
	[globalFontsDefault tokenize:":" into:_activePathList];
	[self _checkPathList:_activePathList];

	ourFontsDefault = [MiscString new];
	defaultValue = NXGetDefaultValue( "Preferences", "FontSearchPaths" );
	if( defaultValue != NULL )
		[ourFontsDefault setStringValue:defaultValue];

	_pathList = [List new];
	[ourFontsDefault tokenize:":" into:_pathList];
	[self _checkPathList:_pathList];
	
	// Now lets see if the system prefs contain more pathes then we know about

	[self _syncPathLists];
	
	// The last we have to do is to see if we have a path at all.
	// If not we will add the NeXT default paths to both lists. 
	// At least the NeXT fonts should be available so a path without
	// Fonts won't be accepted !
	// Now that we did _sync both lists the follow is always true...

	if( [_pathList count] == 0 )
	{
		aString = [MiscString newWithString:"/NextLibrary/Fonts/"];
		[_pathList addObject:aString];
		[_activePathList addObject:aString];

		aString = [MiscString newWithString:"~/Library/Fonts/"];
		[_pathList addObject:aString];
		[_activePathList addObject:aString];

		aString = [MiscString newWithString:"/LocalLibrary/Fonts/"];
		[_pathList addObject:aString];
		[_activePathList addObject:aString];

		[self _checkPathList:_pathList];
		[self _checkPathList:_activePathList];
	}

 	[browser setCellPrototype:[CEBrowserCell new]];
	[browser setTarget:self];
	[browser setAction:@selector(selectNewPath:)];
	[browser setDoubleAction:@selector(activatePath:)];
	[browser loadColumnZero];

	return self;
}

- free
{
	[_pathList freeObjects];
	[_pathList free];
	[_activePathList freeObjects];
	[_activePathList free];
	return [super free];
}

- view
{
	return view;
}

- addPath:sender
{
	id	newString;
	int	position;

	newString = [MiscString newWithString:[sender stringValue]];
	[self _checkPath:newString];

	// Lets see if it is a really new path.

	position = [self _findPath:newString];

	if( position == -1 )
	{
		[_pathList addObject:newString];
		[browser loadColumnZero];
		position = [_pathList count]-1;
	}
	
	//if it is not new...just select the old one and free the new one.
	
	else
	{
		[newString free];
	}

	// Lets select the added path

	[[browser matrixInColumn:0] selectCellAt:position :0];
	[self selectNewPath:self];

	return self;
}

- removePath:sender
{
	id	aString;
	int i;

	aString = [[browser selectedCell] source];
	if( aString == nil ) return self;

	i = [self _findPath:aString inside:_activePathList];
	[_activePathList removeObjectAt:i];
	[_pathList removeObject:aString];
	[browser loadColumnZero];
	[self selectNewPath:self];
	
	// BUG: We might note free the aString !!

	return self;
}

- (int)_findPath:aString
{
	return [self _findPath:aString inside:_pathList];
}

- (int)_findPath:aString inside:aList;
{
	int	i;
	int	location;
	id	testString;

	location = -1;

	for( i=0; i<[aList count]; i++ )
	{
		testString = [aList objectAt:i];
		if( [testString compareTo:aString] == 0 )
		{
			location = i;
			break;
		} 
	}
	return location;
}

- _checkPathList:aList
{
	int	i;
	int	count;

	count = [aList count];
	for( i=0; i<count; i++ )
	{
		[self _checkPath:[aList objectAt:i]];
	}
	return self;
}

- _checkPath:aString
{
	id	dummyString;
	int	length;

	// if( [aString isAbsolutPath] == NO )... BUG

	if( [aString isPlainFile] )
	{
		dummyString = [aString pathName];
		[aString setStringValue:[dummyString stringValue]];
		[dummyString free];
	}
	[aString replaceHomeWithTilde];
	[aString trimSpaces];

	length = [aString length];
	if( [aString charAt:length-1] == '/' )
		[aString removeFrom:length-1 to:length-1];

	return self;
}

- updateFontPaths:sender
{
	id	aString;
	int	i;
	int	count;

	aString = [MiscString new];

	// With no path we won't move on !!

	count = [_pathList count];
	if( count == 0 )
	{
		NXRunAlertPanel( NULL, "Sorry you must specify at least on path.", 
				"OK", NULL, NULL );
		return nil;
	}

	for( i=0; i<count; i++ )
	{
		[aString concatenate:[_pathList objectAt:i]];
		[aString addChar:'/'];
		if( i < count-1 )
			[aString addChar:':'];
	}
	NXWriteDefault( "Preferences", 
				   "FontSearchPaths", [aString stringValue] );

	// And now lets update the systems active list..

	[aString freeString];
	count = [_activePathList count];
	for( i=0; i<count; i++ )
	{
		[aString concatenate:[_activePathList objectAt:i]];
		[aString addChar:'/'];
		if( i < count-1 )
			[aString addChar:':'];
	}
	NXWriteDefault( "GLOBAL", "NXFontsPaths", [aString stringValue] );

	[aString free];
	return self;
}

- updateFontCaches:sender
{
	id	aString;
	int	i;
	int	count;

	// If there was an error pushing the paths we won't do the update !

	if( [self updateFontPaths:self] == nil ) return nil;


	aString = [MiscString new];
	count = [_activePathList count];
	
	// Ok now lets remove the old cache files and build the new ones for
	// every active dir.

	for( i=0; i<count; i++ )
	{
		[aString setStringValue:"rm -f "];
		[aString addChar:'"'];
		[aString concatenate:[_activePathList objectAt:i]];
		[aString cat:"/.afmcache"];
		[aString addChar:'"'];
		system( [aString stringValue] );

		[aString setStringValue:"rm -f "];
		[aString addChar:'"'];
		[aString concatenate:[_activePathList objectAt:i]];
		[aString cat:"/.fontlist"];
		[aString addChar:'"'];
		system( [aString stringValue] );

		[aString setStringValue:"rm -f "];
		[aString addChar:'"'];
		[aString concatenate:[_activePathList objectAt:i]];
		[aString cat:"/.fontdirectory"];
		[aString addChar:'"'];
		system( [aString stringValue] );

		[aString setStringValue:"buildafmdir "];
		[aString addChar:'"'];
		[aString concatenate:[_activePathList objectAt:i]];
		[aString addChar:'"'];
		system( [aString stringValue] );

		[aString setStringValue:"cacheAFMData "];
		[aString addChar:'"'];
		[aString concatenate:[_activePathList objectAt:i]];
		[aString addChar:'"'];
		system( [aString stringValue] );
	}

	[aString free];
	return self;
}

- selectNewPath:sender
{
	id	aString;
	id	ourString;

	aString = [[browser selectedCell] source];
	if( aString == nil )
			ourString = [MiscString newWithString:""];
	else		ourString = [aString copy];

	[selectedPathField setStringValue:[ourString stringValue]];
	
	[ourString replaceTildeWithHome];	
	[pathDropWell setImageByFilename:[ourString stringValue]];

	[ourString free];
	
	return self;
}

- activatePath:sender
{
	id	aString;
	int	pos;

	aString = [[browser selectedCell] source];
	if( aString != nil )
	{
		// If the path is inside the activeList we will remove him..otherwise
		// we will add him
		
		pos = [self _findPath:aString inside:_activePathList];
		if( pos > -1 )
			[_activePathList removeObjectAt:pos];

		else
			[_activePathList addObject:[aString copy]];

		// the last action is to update the view.

		[browser loadColumnZero];
	}
	return self;
}

- _syncPathLists
{
	int	i;
	
	for( i=0; i<[_activePathList count]; i++ )
		if( [self _findPath:[_activePathList objectAt:i]] == -1 )
			[_pathList addObject:[_activePathList objectAt:i]];

	return self;
}

- (int)browser:sender fillMatrix:matrix inColumn:(int)column
{
	// We just fill the matrix with the needed number of cells.
	// According the methods inside the list.
	
	int	i, n;
	
	n = [_pathList count];
	for( i=0; i<n; i++ ) [matrix addRow];

	return n;
}

- browser:sender loadCell:cell atRow:(int)row inColumn:(int)column
{
	// Just set the atoms name as the String value.
	id	aString;
	
	aString = [_pathList objectAt:row];
	[cell setStringValue:[aString stringValue]];
	[cell setSource:aString];
	[cell setLoaded:YES];
	[cell setLeaf:YES];

	// Now check if it is active..

	if( [self _findPath:aString inside:_activePathList] > -1 )
			[cell setFont:[Font newFont:"Helvetica" size:12]];
	else		[cell setFont:[Font newFont:"Helvetica-Oblique" size:12]];

	return self;
}
@end

/*
 * History: 13.01.95 Bla.
 *
 *
 * Bugs: No bugs and birds seen....
 */