/**************************************************************************
* main.c:	The main program and supporting stuff.
*		Part of MP, the MIDI Playground.
*
* Author:	Daniel Barrett
* Version:	See the file "version.h".
* Copyright:	None!  This program is in the Public Domain.
*		Please share it with others.
***************************************************************************/

	
#include "mp.h"

BOOL WorkbenchProgram(char *argv[]);
BOOL CommandLineProgram(int argc, char *argv[]);
	
main(int argc, char *argv[])
{
	BOOL success;

	if (argc == 0)
	    success = WorkbenchProgram(argv);
	else
	    success = CommandLineProgram(argc, argv);

	exit(success ? RETURN_OK : RETURN_FAIL);
}

	
/************************************************************************
* Initialization of important variables.
************************************************************************/

void InitStuff(FLAGS theFlags[], FILE **in, FILE **out, char **inFile,
		char **outFile)
{
	int i;

	for (i=0; i<NUM_FLAGS; i++)	/* Flags. */
		theFlags[i] = (FLAGS)0;

	*in 	 = stdin;		/* Input file. */
	*out	 = stdout;		/* Output file. */
	*inFile  = NULL;		/* Input file name. */
	*outFile = NULL;		/* Output file name. */
}

	
/************************************************************************
* Open the serial port if necessary, and have fun!
************************************************************************/

BOOL MIDIPlayground(FLAGS theFlags[], FILE *in, FILE *out)
{
	if ((theFlags[FLAG_ITYPE] == OPT_MIDI)
	||  (theFlags[FLAG_OTYPE] == OPT_MIDI))
	{
		if (!SerialSetup(theFlags[FLAG_SYSEX]))
			return(FALSE);
		ResetSerialPort();
	}

	ReadAndWriteStuff(theFlags, in, out);


	if ((theFlags[FLAG_ITYPE] == OPT_MIDI)
	||  (theFlags[FLAG_OTYPE] == OPT_MIDI))
		SerialShutdown();

	return(TRUE);		/* Stub. */
}

	
/************************************************************************
* Use the appropriate I/O functions until we're done.
************************************************************************/

void ReadAndWriteStuff(FLAGS theFlags[], FILE *in, FILE *out)
{
	MIDI_RESULT	result;
	MIDI_VALUE	value;
	MIDI_RESULT	(*getfcn)(FILE *f, MIDI_VALUE *value);
	BOOL		(*putfcn)(FILE *f, MIDI_VALUE value);
	void		(*skipfcn)(FILE *f, MIDI_VALUE value);

	SetTheFunctions(&getfcn, &putfcn, &skipfcn, theFlags);
	
	while ((result = getfcn(in, &value)) != RESULT_STOP)
	{
		switch (result)
		{
			case RESULT_OK:
				putfcn(out, value);
				break;
			case RESULT_ERROR:
				fprintf(out, "ERROR\n");
				skipfcn(in, value);
				break;
			case RESULT_OVERFLOW:
				fprintf(out, "VALUE TOO BIG (overflow)\n");
				skipfcn(in, value);
				break;
			default:
				skipfcn(in, value);
				fprintf(out, "An unknown error occurred.\n");
				break;
		}
	}
}


/************************************************************************
* Choose the appropriate I/O functions.
************************************************************************/

void SetTheFunctions(MIDI_RESULT (**getfcn)(), BOOL (**putfcn)(),
		    void (**skipfcn)(), FLAGS theFlags[])
{
	switch (theFlags[FLAG_ITYPE])
	{
		case OPT_TEXT:
			*getfcn = FromText;
			*skipfcn = SkipText;
			break;
		case OPT_BINARY:
			*getfcn = FromBinary;
			*skipfcn = SkipBinary;
			break;
		case OPT_MIDI:
			*getfcn = FromMidi;
			*skipfcn = SkipMidi;
			break;
		default:
			*getfcn = FromText;	/* Least dangerous fcn. */
			*skipfcn = SkipText;	/* Least dangerous fcn. */
	}

	switch (theFlags[FLAG_OTYPE])
	{
		case OPT_TEXT:
			*putfcn = ToText;
			break;
		case OPT_BINARY:
			*putfcn = ToBinary;
			break;
		case OPT_MIDI:
			*putfcn = ToMidi;
			break;
		default:
			*putfcn = ToText;	/* Least dangerous fcn. */
			break;
	}
}


/* Is "opt" a valid input/output type?  Set the flag too. */
	
BOOL CheckIOType(char opt, int ioFlag, FLAGS theFlags[])
{
	return(IsIOType(theFlags[ioFlag] = opt));
}


/* Is "ioType" a valid input/output type? */
	
BOOL IsIOType(char ioType)
{
	return(	(ioType == OPT_TEXT)
	||	(ioType == OPT_BINARY)
	||	(ioType == OPT_MIDI));
}


/* Did user specify both input and output types? */
	
BOOL CheckFlags(FLAGS theFlags[])
{
	return(theFlags[FLAG_ITYPE] && theFlags[FLAG_OTYPE]);
}

	
/************************************************************************
* ^C handling -- Manx stuff.
************************************************************************/

void _abort(void)
{
	SerialShutdown();
	exit(RETURN_FAIL);
}
