/***********************************************************************
Controller class for Convert FONT which converts Mac fonts to NeXT fonts.
Copyright (C) 1993 David John Burrowes

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

The author, David John Burrowes, can be reached at:
	davidjohn@kira.net.netcom.com
	David John Burrowes
	1926 Ivy #10
	San Mateo, CA 94403-1367
***********************************************************************/



#import "PreFontConverter.h"
#import "FontConverter.h"
#import "PSFile.h"
#import "TextFile.h"
#import <appkit/Cell.h>	// for menu enabling.
#import <appkit/Matrix.h>

#import <stdio.h>
#import <libc.h>			// for mkdir  and rmdir
#import	<string.h>		// for strrchr
#import <errno.h>		// 93.01.24	for errno

@implementation PreFontConverter


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	Routine:		init
//	Parameters:	none
//	Returns:		self
//	Stores:		none
//	Description:
//		This overrides the defalut init method.  The purpose of this overriding
//		is to give ourselves a chance to set up some internal variables which are used
//		later on, and allocate the converter instance.
//	Bugs:
//	History
//		93.03.14	Added code for encoding vector choice
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- init
{	
	static NXDefaultsVector theDefaults =
	{
		{USENSENCODING, "YES"},
	};

	[super init];

	ConversionString = "Converting Mac FONT to Type 3 PS font";
	SourcePrompt = "FONT file:";
	DestPrompt = "Type 3 file:";
	DestExtension = ".font";
	
	DefaultsOwner = "ConvertFONT";
	NXRegisterDefaults(DefaultsOwner, theDefaults);
	UseNSEncoding = [self   GetBoolPref: USENSENCODING];

	converterInst = [[FontConverter alloc] init];
	return self;
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	Routine:		free
//	Parameters:	none
//	Returns:		a null instance
//	Stores:		none
//	Description:
//		This simply free's the converter instance, which we allocated in the init.
//	Bugs:
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- free
{
	if (converterInst != NullInstance)
		[converterInst	free];
	[super   free];
	return NullInstance;
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	Routine:		displayPreferences: 
//	Parameters:	the object that called us
//	Returns:		self
//	Stores:		none
//		This is called whenever we need to bring the preferences panel onto the screen.
//		Using the value in our preferences variable, we set the button in
//		the preferences panel to reflect the current value, and then shows the panel.
//	Bugs:
//		As pointed out elsewhere, we don't really need to do this after the first time,
//		since the buttons keep their own state.  So this paradigm needs revising!!
//	History
//		93.03.14	Created
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-displayPreferences: target
{
	//
	//	Get the default preference values, and compare judge what buttons to
	//	highlight for the user.
	//
	if (UseNSEncoding == YES)
		[EncodingButton  selectCellWithTag: 0];
	else
		[EncodingButton  selectCellWithTag: 1];
	//
	//	Display the panel for the user.
	//
	[prefPanel	makeKeyAndOrderFront:self];
	return self;
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	Routine:		ChangeEncodingVector: 
//	Parameters:	the object that called us
//	Returns:		self;
//	Description:
//		This method gets called whenever the user clicks on a button to change
//		the setting of whether to use the NS or the Mac encoding.  If the button they
//		clicked on had a key of '1', then we will use NS, otherwise we don't.
//	History
//		93.03.14	Created
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-ChangeEncodingVector: sender
{
	if ( [[sender selectedCell] tag] == 0)
		UseNSEncoding = YES;
	else
		UseNSEncoding = NO;

	[self   SetBoolPref: USENSENCODING To: UseNSEncoding];

	return self;
}



//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	Routine:		openDestFile
//	Parameters:	the path to the file to be opened
//	Returns:		the opened file object  (or junk if error is TERMINALERROR()
//	Stores:		errors
//	Description:
//		This is used to open the destination file object (a PS file).  This is needed so
//		that our superclass, when it is doing some of the work that we don' want to,
//		will open an instance of the right class.
//	Bugs:
//	History:
//		93.01.10	djb	Added last minute name processing.  Specifically, give the font converter
//					the full name with spaces, and other illegal characters.  then, expanded
//					original 'replace spaces with _'s' with 'remove all delimiters and other
//					evil characters'
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- openDestFile: (CString) theFile
{
	CString			pathname;
	CString			theDir;
	CString			filename;
	CString			location;
	Instance			fontFile	= NullInstance;
	PositiveInteger	index;
	PositiveInteger	destIndex;
	Integer			result;
	CString			buffer;
	[self  ResetResults];
	//
	//	Build some names needed.  If   theFile is: /foo/bar/ginger.font  then this builds:
	//		filename:   ginger
	//		theDir: /foo/bar/
	//	And then we create the files
	//		$theDir/$filename.font
	//		$theDir/$filename.font/$filename
	//		$theDir/$filename.font/$filename.afm
	//
	//	First, obtain the directory name.  (nuke everything after the final /.
	//
	theDir = NewCString(strlen(theFile));	// max possible size for the directory name
	strcpy (theDir, theFile);
	location = strrchr(theDir, '/');
	location[0] = EndOfCString;
	//
	//	Now, build the base filename, find the last /, and copy all the rest over, and then
	//	find the last period, and put a terminator there 
	//
	filename = NewCString(strlen(theFile));	// max possible size for file basename =)
	location = strrchr(theFile, '/');
	strcpy (filename, &(location[1]));
	location = strrchr(filename, '.');
	location[0] = NullCharacter;
	//
	//	Let the actual font converter know what the actual font name should be, so it
	//	can store it in the afm file.  We could store this name and send it to it later, but this
	//	seems like as good a time as any.  
	//
	[converterInst   SetFullNameTo: filename];
	//
	//	Remove all those characters in the name that may cause the font to be misprocessed.
	//	The list I'm now aware of is: (, ), <, >, [, ], {, }, \, %.  Also, space because it breaks
	//	up the name in the PS file, and period and backslash because they mess up the
	//	filename, and finally single quotes because they make me uncomfortable
	//	Replace all these characters with nothing	//
	destIndex = 0;
	for (index = 0; index < strlen(filename); index++)
	{
		if ((filename[index] != ' ') &&
			(filename[index] != '.') &&
			(filename[index] != '`') &&
			(filename[index] != '\'') &&
			(filename[index] != '(') &&
			(filename[index] != '<') &&
			(filename[index] != '[') &&
			(filename[index] != '{') &&
			(filename[index] != '}') &&
			(filename[index] != ']') &&
			(filename[index] != '>') &&
			(filename[index] != ')') &&
			(filename[index] != '\\') &&
			(filename[index] != '/') &&
			(filename[index] != '%'))
		{
			filename[destIndex] = filename[index];
			destIndex++;
		}
	}
	filename[destIndex] =EndOfCString;
	//
	//	Create a directory for the font files by
	//		1) getting the file's basename (now done above)
	//		2) Creating a directory with the name of the requested font
	//		3) Create a font file in said directory
	//		4) Create a .afm file in said directory
	//
	//
	//		2) Creating a directory with the name of the requested font
	//
	pathname = NewCString(strlen(theFile)+5);// 5 extra incase no .font thefile
	sprintf(pathname, "%s/%s.font", theDir, filename);
	errno = 0;
	result = mkdir(pathname, 0700 | 0070 | 0007); // strange perms
	FreeCString(pathname);
	if (result != 0)
	{
		buffer = NewCString(100);
		sprintf(buffer,  "The font folder could not be created. (mkdir error: %d)", errno);
		[self   StoreErrorCode: ERR_CREATEFAILED  AndText:buffer];
		FreeCString(filename);
		FreeCString(theDir);
		FreeCString(buffer);
		rmdir(theFile);
	}
	else
	{
		//
		//	Allocate space for path to font folder, plus font or font.afm name
		//
		pathname = NewCString(strlen(theFile) + 5 + 1 + strlen(filename)+4);
		sprintf(pathname, "%s/%s.font/%s", theDir, filename, filename);
		//
		//		3) Create a font file in said directory
		//
		fontFile =  [[PSFile alloc] initAndUse: pathname];
		if ([fontFile GetErrorCode] == ERR_OK)
			[fontFile CreateAndOpenFor: FILE_WRITE];
		if ([fontFile GetErrorCode] != ERR_OK)
		{
			[self   StoreErrorCode: ERR_CREATEFAILED
				AndText: "We failed to create the PS font file"];
			fontFile = NullInstance;
			rmdir(theFile);
		}
		else
		{
			//
			//		4) Create a .afm file in said directory
			//
			strcat(pathname, ".afm");
			afmFile =  [[TextFile alloc] initAndUse: pathname];
			if ([afmFile GetErrorCode] == ERR_OK)
				[afmFile CreateAndOpenFor: FILE_WRITE];
			if ([afmFile GetErrorCode] != ERR_OK)
			{
				[self   StoreErrorCode: ERR_CREATEFAILED
					AndText: "We failed to create the font's afm file."];
				[fontFile	  CloseAndDelete];
				[fontFile   free];
				rmdir(theFile);
				afmFile = NullInstance;
			}
		}
		FreeCString(pathname);
	}
	return fontFile;
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	Routine:		closeDestFile:andDelete:
//	Parameters:	the path to the file to be opened
//	Returns:		the opened file object  (or junk if error is TERMINALERROR()
//	Stores:		errors
//	Description:
//		This is used to open the destination file object (a PS file).  This is needed so
//		that our superclass, when it is doing some of the work that we don' want to,
//		will open an instance of the right class.
//	Bugs:
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- closeDestFile: fileInstance  andDelete: (Boolean) deleteit
{
	CString	thepath;

	[self   ResetResults];

	if (deleteit == NO)
	{
		[fileInstance   CloseAndSave];
		[afmFile   CloseAndSave];
	}
	else
	{
		thepath = [fileInstance   GetDirectory];
		[fileInstance   CloseAndDelete];
		[afmFile   CloseAndDelete];
		rmdir(thepath);
		FreeCString(thepath);
	}

	[self   StoreErrorCode: [fileInstance  GetErrorCode]
		AndText:  [fileInstance  GetErrorText]];
	[fileInstance   free];
	[afmFile   free];

	return self;
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	Routine:		ConvertFrom:To: 
//	Parameters:	The file to be converted from, and the file to be converted to
//	Returns:		self
//	Stores:		error code
//	Description:
//		This merely acts (like the rest of this object) as a kinda minimal interface
//		shell.  This merely creates the converting object, asks it to convert the stuff,
//		stores whether there were any results, and returns.
//	Bugs
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ConvertFrom: sourceFile To: destinationFile
{

	[self   ResetResults];
	[super   ConvertFrom: sourceFile To: destinationFile];

	[ConvertCommand	setEnabled: NO];
	//
	//	93.0314	Added SetNSEncodingUse call
	//
	[converterInst  SetNSEncodingUse:  UseNSEncoding];
	[converterInst ConvertMacFONT: sourceFile
		ToType3Font: destinationFile AndAFM: afmFile];

	if ( [converterInst   GetErrorCode] < ERR_OK)
		[self   StoreErrorCode:  [converterInst   GetErrorCode]
			AndText:  [converterInst   GetErrorText] ];
	else
		[self   StoreErrorCode: ERR_OK
			AndText: "Converted Successfully" ];

	[ConvertCommand	setEnabled: YES];

	return self;
}

@end
