/* --------------------------------------------------------------------------

Class:			MHDocConverter
Version:		0.1
File:			MHDocConverter.m				 

Written by:		Thomas Engel
Created:		17.05.1995	(Copyleft)
Last modified:	17.05.1995


Note:	For a detailed description please read the class documentation.

 ------------------------------------------------------------------------- */

#import "MHDocConverter.h"
#import "MHFhGL3DecoderTool.h"
#import "MHFhGL3EncoderTool.h"
#import "MHFileInfoTool.h"
#import "MHStdErrorTool.h"

#import <misckit/MiscString.h>
#import <misckit/MiscShell.h>
#import <misckit/MiscSwapView.h>
#import <misckit/MiscIconWell.h>


@implementation MHDocConverter

- init
{
	return [self initFromFile:""];
}

- initFromFile:(const char *)path
{
	self = [super init];
	if( !self ) return self;

	// OK. We really are an object...here we go with our init.

	if( !window )
	{
		if( [NXApp loadNibSection:"DocConverter.nib" owner:self] == nil )
			NXRunAlertPanel( NULL, "Couldn't load DocConverter.nib",
							 "OK", NULL, NULL );
	}

	// Now lets prepare the tool list

	shellTool = [MHStdErrorTool new];

	registeredTools = [List new];
	[registeredTools addObject:[MHFhGL3DecoderTool new]];
	[registeredTools addObject:[MHFhGL3EncoderTool new]];
	[registeredTools addObject:[MHFileInfoTool new]];
	[registeredTools addObject:shellTool];

	// Lets setup the window

	[window setFrameAutosaveName:"DocumentWindow"];
	[window setFrameUsingName:[window frameAutosaveName]];
	[window setMiniwindowImage:[NXImage findImageNamed:"Ring"]];

	filename = [MiscString new];
	outputFilename = [MiscString new];
	outputExtension = nil;

	[self setFilename:(char *)path];

	return self;
}

- free
{
	// No need to free the shellTool...it is part of the registerd tools.

	[[registeredTools freeObjects] free];
	[filename free];
	[outputFilename free];
	
	if( outputExtension ) [outputExtension free];
	
	return [super free];
}

- setFilename:(char *)path
{
	// This method should be used to change a converters file via the
	// program. This is the reason why we consider it is good to make the
	// window key in the same turn.
	
	id	aString;

	aString = [MiscString newWithString:path];
	[self takeFilenameFrom:aString];
	[aString free];

	[window makeKeyAndOrderFront:self];
	return self;
}

- checkFiles
{
	// This gets called when we might have lost the source file due to 
	// A filesystem change.

	[self _updateOutputDropView];

	// Well we will check if the file does exist or not. If it does not
	// We will bring up an Error.

	if( 	_skipAutoFileCheck == NO &&
		![filename doesExistInFileSystem] )
	{
		NXRunAlertPanel( NULL, "The source file does not exist anymore! Be careful...using a filter tool might have strange effects under these conditions.",
							 "Ooops", NULL, NULL );

		// We will remove the current entry...this makes shure that the
		// drop view really updates the visible represenation.
		
		[sourceDropView setImage:[NXImage findImageNamed:"NotExistingFile"]];

		// But now lets remember that we did the check !
		// otherwise we won't get out of this loop anymore.

		_skipAutoFileCheck = YES;
	}

	// BUG: A real File too should disable all the filter Buttons!
	// Yes I know that. But its a hack.
	
	return self;
}

- takeFilenameFrom:sender
{
	int	i;
	int	count;
	id	aTool;
	id	theCell;

	// If we are working where is not way to change the path !

	if( [self isProcessing] )
	{
		NXRunAlertPanel( NULL, "Can't change Sourcepath. We have "\
							 "a process running on the current files!",
							 "OK", NULL, NULL );
		return self;
	}

	// BUG: !
	// We should checki if this path is a valid input.
	// This should happen even during the drop !
	
	// Lets be sure that we will check the new file for existance again !

	_skipAutoFileCheck = NO;
	[filename setStringValue:[sender stringValue]];

	// Now update them all. We will for the output to go to the same
	// folder as the source.
	
	[sourceDropView setStringValue:[filename stringValue]];
	[sourcePathText setStringValue:[filename stringValue]];

	[outputPath free];
	outputPath = nil;
	[self _updateOutputFilename];
	[self _updateOutputDropView];

	// So lets init the list of useful tools. If might have changed.

	[toolMatrix renewRows:1 cols:0];
	count = 0;

	for( i=0; i<[registeredTools count]; i++ )
	{
		aTool = [registeredTools objectAt:i];
		if( [aTool canProcess:filename for:self] )
		{
			[toolMatrix addCol];
			theCell = [toolMatrix cellAt:0 :count];
			[theCell setImage:[aTool image]];
			
			// First set the trigger and then set the swapView.
			// settng the swapView requires a valid trigger.

			[aTool setTrigger:theCell];
			[aTool setSwapView:swapView];

			count++;
		}
	}
	[toolMatrix sizeToCells];

	// BUG NeXT:
	// Changing the selection like this seems to cause a ugly flicker on the
	// screen ..two cells are seletced until we do the full redraw.
	// This is strange because selectCell should desel the current sel first
	// AND redisplay it ??

	[toolMatrix selectCellAt:0 :0];
	[toolMatrix display];

	// Be sure that the swapView shows the right contents...just trigger and
	// virtual swap action.

	[swapView swapContentView:toolMatrix];

	return self;
}

- filename
{
	return filename;
}

- outputFilename
{
	return outputFilename;
}

- takeOutputFilenameFrom:sender
{
	id	aString;
	
	aString = [MiscString newWithString:[sender stringValue]];
	
	if( [aString isFileOfType:Misc_Directory] )
	{
		if( outputPath == nil )
			outputPath = [MiscString new];
			
		[outputPath setStringValue:[aString stringValue]];
	}
	[aString free];
	[self _updateOutputFilename];
	[self _updateOutputDropView];

	return self;
}

- _updateOutputDropView
{
	// The final action is to sync the dropWell with the current path.
	// If it is an existing file then we will show it..otherwise we won't.
	
	if( [outputFilename isFileOfType:Misc_PlainFile] )
		[outputDropView setStringValue:[outputFilename stringValue]];
	
	else
	{	
		[outputDropView setStringValue:""];

		if( outputExtension != nil &&
			[outputExtension isKindOf:[NXImage class]] )
			[outputDropView setImage:[outputExtension copy]];
	}
	// NOTE: This could be improved so that a target dir different from the
	// original dir is display also.
	
	return self;
}

- _updateOutputFilename
{
	id	outname;
	id	basename;
	
	if( outputExtension != nil &&
		[outputExtension isKindOf:[MiscString class]] )
	{
		basename = [filename fileBasename];

		if( outputPath != nil )
				outname = [outputPath copy];
		else	outname = [filename pathName];
		
		[outname addChar:[MiscString pathSeparator]];
		[outname concatenate:basename];
		[basename free];
		[outname cat:"."];
		[outname concatenate:outputExtension];
		[outputFilename takeStringValue:outname];
		[outname free];
	}
	else
		[outputFilename setStringValue:""];

	[outputPathText setStringValue:[outputFilename stringValue]];

	return self;
}

- setOutputExtension:anObject
{
	if( outputExtension ) [outputExtension free];
	
	outputExtension = anObject;

	// Now force an update of the output filename...

	[self _updateOutputFilename];
	[self _updateOutputDropView];
	return self;
}

- sharedShell
{
	return [(MHStdErrorTool *)shellTool shell];
}

- (BOOL)isProcessing
{
	if( activeTool )
		return YES;

	return NO;
}

- windowDidBecomeKey:sender
{
	// As the windows delegate we will tkae care of change which happened
	// during the last time.
	
	[self checkFiles];
	return self;
}

- toolWillStartProcessing:sender
{
	int	result;

	if( activeTool != nil ) return nil;

	// Lets check if we are bound to overwrite an existing file.

	if( [outputFilename emptyString] == NO &&
		[outputFilename doesExistInFileSystem] )
	{
		result = NXRunAlertPanel( "Process", 
						"The file %s already exists. Overwrite it?", 
						"Replace", "Cancel", NULL, 
						[outputFilename stringValue] );

		if( result != NX_ALERTDEFAULT )
			return nil;
	}

	activeTool = sender;
	[window setTitle:"MPEG L3 Converter ¼ processing"];

	[sourceDropView setAllowDestinationDragging:NO];
	[outputDropView setAllowDestinationDragging:NO];

	return self;
}

- toolDidStopProcessing:sender
{
	if( activeTool == sender )
	{
		[window setTitle:"MPEG L3 Converter"];
		activeTool = nil;
		[sourceDropView setAllowDestinationDragging:YES];
		[outputDropView setAllowDestinationDragging:YES];
	}

	// If it is the shellTool the this means that we can stop the currently
	// active process.

	else if( sender == shellTool )
	{
		[activeTool stopProcessing:self];
	}

	// Lets check the files. It is quite obvious that something has changed.

	[self checkFiles];
	return self;
}

@end

/*

Known Bugs:   Dropping Multiple Files does not work properly. The IconWell
			 should discourage that somehow. At least we get our strange Alert.
*/