//-----------------------------------------------------------------------------
//
//  $Logfile:: /Code/Shared/qcommon/output.cpp                                $
// $Revision:: 14                                                             $
//   $Author:: Steven                                                         $
//     $Date:: 10/06/02 7:10p                                                 $
//
// Copyright (C) 1998 by Ritual Entertainment, Inc.
// All rights reserved.
//
// This source is may not be distributed and/or modified without
// expressly written permission by Ritual Entertainment, Inc.
//


#include "output.h"
#include <game/str.h> // Was uilib/str.h

//================================================================
// Name:				DocFileOutput
// Class:			DocFileOutput
//
// Description:	Constructor
//
// Parameters:		None
//
// Returns:			None
//
//================================================================
DocFileOutput::DocFileOutput()
{
	typeFlag = 0;
	fileptr = NULL;
	classCount = 0;
	eventCount = 0;
}


//================================================================
// Name:				~DocFileOutput
// Class:			DocFileOutput
//
// Description:	Destructor
//
// Parameters:		None
//
// Returns:			None
//
//================================================================
DocFileOutput::~DocFileOutput()
{
	
}


//================================================================
// Name:				OutputClasses
// Class:			DocFileOutput
//
// Description:	Loops through all the classes and calls OutputClass on each
//						(which will usually be a derived classes' version of it).
//
// Parameters:		ClassDef *classlist -- The list of classes to loop through
//
// Returns:			None
//
//================================================================
void DocFileOutput::OutputClasses(ClassDef *classlist)
{
	ClassDef *c;
	int num = 0;
	
	for( c = classlist->next; c != classlist; c = c->next )
	{
		if ( num < MAX_CLASSES )
		{
			OutputClass(c);
			num++;
		}
	}
}

//================================================================
// Name:				OutputClass
// Class:			DocFileOutput
//
// Description:	This function is normally overriden by a subclass.
//						The subclass's OutputClass will call this function
//						when its done with its own version.
//
// Parameters:		ClassDef *in_class -- The class to output
//
// Returns:			None
//
//================================================================
void DocFileOutput::OutputClass(ClassDef *in_class)
{
	OutputEvents(in_class);
	classCount++;
}

//================================================================
// Name:				OutputEvents
// Class:			DocFileOutput
//
// Description:	Loops through all the events and calls OutputEvent on each
//						(which will usually be a derived classes' version of it).
//						This function also filters out the events based on the typeFlag
//
// Parameters:		ClassDef in_class -- The class whose events we will loop through
//
// Returns:			None
//
//================================================================
void DocFileOutput::OutputEvents(ClassDef *in_class)
{
	ResponseDef<Class> *r;
	int			ev, i, num;
	Event       **events;
	
	num = Event::NumEventCommands();
	
	events = new Event *[num];
	memset( events, 0, sizeof( Event * ) * num );
	
	// gather event responses for this class
	r = in_class->responses;
	if ( r )
	{
		for( i = 0; r[i].event != NULL; i++ )
		{
			ev = ( int )*r[i].event;
			if ( r[i].response )
			{
				events[ev] = r[i].event;
			}
		}
	}
	
	for( i = 1; i < num; i++ )
	{
		int index;
		
		index = Event::MapSortedEventIndex( i );
		if ( events[index] )
		{
			// Filtering
			
			if ( events[index]->GetFlags() != 0 )
			{
				// Event is not default
				
				if ( ( events[index]->GetFlags() & EV_TIKIONLY ) && typeFlag == EVENT_SCRIPT_ONLY && !( events[index]->GetFlags() & EV_SCRIPTONLY ) )
					continue;
				
				if ( ( events[index]->GetFlags() & EV_SCRIPTONLY ) && typeFlag == EVENT_TIKI_ONLY && !( events[index]->GetFlags() & EV_TIKIONLY ) )
					continue;
				
				if ( ( events[index]->GetFlags() & EV_CODEONLY ) && ( typeFlag == EVENT_TIKI_ONLY || typeFlag == EVENT_SCRIPT_ONLY ) )
					continue;
				
				if ( ( events[index]->GetFlags() & EV_CHEAT ) && ( typeFlag == EVENT_TIKI_ONLY ) && !( events[index]->GetFlags() & EV_TIKIONLY ) )
					continue;
				
				if ( ( events[index]->GetFlags() & EV_CHEAT ) && ( typeFlag == EVENT_SCRIPT_ONLY ) && !( events[index]->GetFlags() & EV_SCRIPTONLY ) )
					continue;
				
				if ( ( events[index]->GetFlags() & EV_CONSOLE ) && ( typeFlag == EVENT_TIKI_ONLY || typeFlag == EVENT_SCRIPT_ONLY ) )
					continue;
			}
			
			OutputEvent( events[index] );
		}
	}
	
	delete[] events;
}

//================================================================
// Name:				OutputEvent
// Class:			DocFileOutput
//
// Description:	This function is normally overriden by a subclass.
//						The subclass's OutputEvent will call this function
//						when its done with its own version.
//
// Parameters:		Event *ev -- The event to output
//
// Returns:			None
//
//================================================================
void DocFileOutput::OutputEvent(Event *ev)
{
	OutputArguments(ev);
	eventCount++;
}

//================================================================
// Name:				OutputArguments
// Class:			DocFileOutput
//
// Description:	Loops through all the args and calls OutputArgument on each
//						(which will usually be a derived classes' version of it).
//
// Parameters:		Event *ev -- The event whose arguments we will loop through
//
// Returns:			None
//
//================================================================
void DocFileOutput::OutputArguments(Event *ev)
{
	int i;
	for( i = 1; i <= ev->getNumArgDefs(); i++ )
	{
		EventArgDef *evarg = ev->getArgDef(i);
		OutputArgument(evarg);
	}
}

//================================================================
// Name:				OutputArgument
// Class:			DocFileOutput
//
// Description:	This function is normally overriden by a subclass.
//						The subclass's OutputArgument will call this function
//						when its done with its own version.
//				
//
// Parameters:		None
//
// Returns:			None
//
//================================================================
void DocFileOutput::OutputArgument(EventArgDef *evarg)
{
	// Function does nothing.  This is the last level of nesting, and there
	// is nothing else to go print from here.
}

//================================================================
// Name:				Write
// Class:			DocFileOutput
//	
// Description:	Writes the file to disk
//
// Parameters:		char *filename -- the filename to create
//
// Returns:			None
//
//================================================================
void DocFileOutput::Write(const char *filename, ClassDef *classlist, int ptypeFlag)
{
	char realname[255];
	sprintf(realname,"%s.%s",filename,GetExtension());
	fileptr = fopen(realname,"w");
	if ( !fileptr )
		return;
	
	// Store the type flag privately so we don't have to pass it around
	typeFlag = ptypeFlag;
	
	// Start the writing process
	OutputClasses(classlist);
	
	fclose(fileptr);
}


// ************************************************************************
// *                                                                      *
// *                                                                      *
// *							HTMLDocFileOutput Class                           *
// *                                                                      *
// *                                                                      *
// ************************************************************************




//================================================================
// Name:				HTMLDocFileOutput	
// Class:			HTMLDocFileOutput
//
// Description:	Constructor
//
// Parameters:		None
//
// Returns:			None
//
//================================================================
HTMLDocFileOutput::HTMLDocFileOutput()
{
	
}

//================================================================
// Name:				HTMLDocFileOutput	
// Class:			~HTMLDocFileOutput
//
// Description:	Destructor
//
// Parameters:		None
//
// Returns:			None
//
//================================================================
HTMLDocFileOutput::~HTMLDocFileOutput()
{
	
}

//================================================================
// Name:				OutputClasses
// Class:			HTMLDocFileOutput
//
// Description:	Override of the base class version.  We do this
//						so we can print header and footer information.
//
// Parameters:		None
//
// Returns:			None
//
//================================================================
void HTMLDocFileOutput::OutputClasses(ClassDef *classlist)
{
	str class_title;
#if defined( GAME_DLL )
	class_title = "Game Module";
#elif defined( CGAME_DLL )
	class_title = "Client Game Module";
#else
	class_title = "Client Module";
#endif
	
	// Header Info
	fprintf(fileptr, "<HTML>\n");
	fprintf(fileptr, "<HEAD>\n");
	fprintf(fileptr, "<Title>%s Classes</Title>\n", class_title.c_str() );
	fprintf(fileptr, "</HEAD>\n");
	fprintf(fileptr, "<BODY>\n");
	fprintf(fileptr, "<H1>\n");
	fprintf(fileptr, "<center>%s Classes</center>\n", class_title.c_str() );
	fprintf(fileptr, "</H1>\n");
	
#if defined( GAME_DLL )
	fprintf(fileptr, "<h2>" );
	fprintf(fileptr, "<a href=\"#Actor\">Actor</a>, " );
	fprintf(fileptr, "<a href=\"#Animate\">Animate</a>, " );
	fprintf(fileptr, "<a href=\"#Entity\">Entity</a>, " );
	fprintf(fileptr, "<a href=\"#ScriptSlave\">ScriptSlave</a>, " );
	fprintf(fileptr, "<a href=\"#Sentient\">Sentient</a>, " );
	fprintf(fileptr, "<a href=\"#Trigger\">Trigger</a>, " );
	fprintf(fileptr, "<a href=\"#World\">World</a>" );
	fprintf(fileptr, "</h2>" );
#endif
	
	// Print the body
	DocFileOutput::OutputClasses(classlist);
	
	// Footer
	fprintf(fileptr, "<H2>\n");
	fprintf(fileptr, "%d %s Classes.<BR>%d Events.\n", classCount, class_title.c_str(), eventCount );
	fprintf(fileptr, "</H2>\n");
	fprintf(fileptr, "</BODY>\n");
	fprintf(fileptr, "</HTML>\n");
}

//================================================================
// Name:				OutputClass
// Class:			HTMLDocFileOutput
//
// Description:	Write the class output for this type of file
//
// Parameters:		ClassDef *in_class -- Class to write out
//
// Returns:			None
//
//================================================================
void HTMLDocFileOutput::OutputClass(ClassDef *in_class)
{
	ClassDef *savedClass;
	savedClass = in_class;
	
	fprintf(fileptr, "\n");
	if ( in_class->classID[ 0 ] )
	{
		fprintf(fileptr, "<h2> <a name=\"%s\">%s (<i>%s</i>)</a>", in_class->classname, in_class->classname, in_class->classID );
	}
	else
	{
		fprintf(fileptr, "<h2> <a name=\"%s\">%s</a>", in_class->classname, in_class->classname );
	}
	
	// print out lineage
	for( in_class = in_class->super; in_class != NULL; in_class = in_class->super )
	{
		fprintf(fileptr, " -> <a href=\"#%s\">%s</a>", in_class->classname, in_class->classname );
	}
	fprintf(fileptr, "</h2>\n");
	fprintf(fileptr, "<BLOCKQUOTE>\n");
	
	// Events
	DocFileOutput::OutputClass(savedClass);
	   
	fprintf(fileptr, "</BLOCKQUOTE>\n");
}

//================================================================
// Name:				OutputEvent
// Class:			HTMLDocFileOutput
//
// Description:	Write the event output for this type of file
//
// Parameters:		Event *ev -- Event to write out
//
// Returns:			None
//
//================================================================
void HTMLDocFileOutput::OutputEvent(Event *ev)
{
	int numargs;
	const char *text;
	
	fprintf(fileptr, "\n<P><tt><B>%s</B>", ev->getName() );
	
	numargs = ev->getNumArgDefs();
	
	if ( numargs )
	{
		fprintf(fileptr, "( <i>" );
		DocFileOutput::OutputEvent(ev);
		fprintf(fileptr, " </i>)</tt><BR>\n" );
	}
	else
	{
		// No arguments, do not call base class OutputEvent
		fprintf(fileptr, "</tt><BR>\n" );
	}
	
	text = ev->GetDocumentation();
	
	// Build a new documentation string, replaces the newlines with <BR>\n
	if ( text )
	{
		char new_doc[1024];
		int old_index;
		int new_index = 0;
		
		for ( old_index = 0 ; old_index < strlen ( text ) ; old_index++ )
		{
			if ( text[old_index] == '\n' )
			{
				new_doc[new_index 	] = '<';
				new_doc[new_index + 1] = 'B';
				new_doc[new_index + 2] = 'R';
				new_doc[new_index + 3] = '>';
				new_doc[new_index + 4] = '\n';
				new_index += 5;
			}
			else
			{
				new_doc[new_index] = text[old_index];
				new_index++;
			}
		}
		
		new_doc[new_index] = 0;
		
		fprintf(fileptr, "<ul>%s</ul>\n", new_doc );
	}
}

//================================================================
// Name:				OutputArgument
// Class:			HTMLDocFileOutput
//
// Description:	Write the argument output for this type of file
//
// Parameters:		EventArgDef *evarg -- EventArgs to write out
//
// Returns:			None
//
//================================================================
void HTMLDocFileOutput::OutputArgument(EventArgDef *evarg)
{
	if ( evarg->isOptional() )
	{
		fprintf(fileptr, "[ " );
	}
	
	switch( evarg->getType() )
	{
	case IS_ENTITY:
		fprintf(fileptr, "Entity " );
		break;
	case IS_VECTOR:
		fprintf(fileptr, "Vector " );
		break;
	case IS_INTEGER:
		fprintf(fileptr, "Integer " );
		break;
	case IS_FLOAT:
		fprintf(fileptr, "Float " );
		break;
	case IS_STRING:
		fprintf(fileptr, "String " );
		break;
	case IS_BOOLEAN:
		fprintf(fileptr, "Boolean " );
		break;
	}
	fprintf(fileptr, "%s", evarg->getName() );
	
	// print the range of the argument
	OutputRange(evarg);
	
	if ( evarg->isOptional() )
	{
		fprintf(fileptr, " ]" );
	}
	
	DocFileOutput::OutputArgument(evarg);
}

//================================================================
// Name:				OutputRange
// Class:			HTMLDocFileOutput
//
// Description:	Writes the range of the event arg passed if any
//
// Parameters:		EventArgDef *evarg -- Argument to check for a range
//
// Returns:			None
//
//================================================================
void HTMLDocFileOutput::OutputRange(EventArgDef *evarg)
{
	qboolean integer, single;
	int numRanges, i;
	
	single = false;
	integer = true;
	numRanges = 1;
	switch( evarg->getType() )
	{
	case IS_VECTOR:
		integer = false;
		numRanges = 3;
		break;
	case IS_FLOAT:
		integer = false;
		break;
	case IS_STRING:
		single = true;
		break;
	}
	for( i = 0; i < numRanges; i++ )
	{
		if ( single )
		{
			if ( !evarg->GetMinRangeDefault(i) )
            {
				if ( integer )
				{
					fprintf(fileptr, "<%d>", ( int )evarg->GetMinRange(i) );
				}
				else
				{
					fprintf(fileptr, "<%.2f>", evarg->GetMinRange(i) );
				}
            }
		}
		else
		{
			// both non-default
			if ( !evarg->GetMinRangeDefault(i) && !evarg->GetMaxRangeDefault(i) )
            {
				if ( integer )
				{
					fprintf(fileptr, "<%d...%d>", ( int )evarg->GetMinRange(i), ( int )evarg->GetMaxRange(i) );
				}
				else
				{
					fprintf(fileptr, "<%.2f...%.2f>", evarg->GetMinRange(i), evarg->GetMaxRange(i) );
				}
            }
			// max default
			else if ( !evarg->GetMinRangeDefault(i) && evarg->GetMaxRangeDefault(i) )
            {
				if ( integer )
				{
					fprintf(fileptr, "<%d...max_integer>", ( int )evarg->GetMinRange(i) );
				}
				else
				{
					fprintf(fileptr, "<%.2f...max_float>", evarg->GetMinRange(i) );
				}
            }
			// min default
			else if ( evarg->GetMinRangeDefault(i) && !evarg->GetMaxRangeDefault(i) )
            {
				if ( integer )
				{
					fprintf(fileptr, "<min_integer...%d>", ( int )evarg->GetMaxRange(i) );
				}
				else
				{
					fprintf(fileptr, "<min_float...%.2f>", evarg->GetMaxRange(i) );
				}
            }
		}
	}
}



// ************************************************************************
// *                                                                      *
// *                                                                      *
// *							ToolDocFileOutput Class                           *
// *                                                                      *
// *                                                                      *
// ************************************************************************




//================================================================
// Name:				ToolDocFileOutput	
// Class:			ToolDocFileOutput
//
// Description:	Constructor
//
// Parameters:		None
//
// Returns:			None
//
//================================================================
ToolDocFileOutput::ToolDocFileOutput()
{
	randFlag = false;
	colorFlag = false;
}

//================================================================
// Name:				ToolDocFileOutput	
// Class:			~ToolDocFileOutput
//
// Description:	Destructor
//
// Parameters:		None
//
// Returns:			None
//
//================================================================
ToolDocFileOutput::~ToolDocFileOutput()
{
	
}

//================================================================
// Name:				OutputClass
// Class:			ToolDocFileOutput
//
// Description:	Write the class output for this type of file
//
// Parameters:		ClassDef *in_class -- Class to write out
//
// Returns:			None
//
//================================================================
void ToolDocFileOutput::OutputClass(ClassDef *in_class)
{
	ClassDef *savedClass;
	savedClass = in_class;
	
	fprintf(fileptr, "\n");
	fprintf(fileptr, "%s\n", in_class->classname );
	fprintf(fileptr, "{\n");
	
	// Events
	DocFileOutput::OutputClass(savedClass);
	if ( in_class->super != NULL )
		fprintf(fileptr, "\n\tincludes %s\n",in_class->super->classname);
	
	fprintf(fileptr, "}\n");
}

//================================================================
// Name:				OutputEvent
// Class:			ToolDocFileOutput
//
// Description:	Write the event output for this type of file
//
// Parameters:		Event *ev -- Event to write out
//
// Returns:			None
//
//================================================================
void ToolDocFileOutput::OutputEvent(Event *ev)
{
	int numargs;
	const char *text;
	int i;
	
	fprintf(fileptr, "\n");
	fprintf(fileptr, "\t%s\n", ev->getName() );
	fprintf(fileptr, "\t{\n");
	
	numargs = ev->getNumArgDefs();
	
	if ( numargs )
	{
		DocFileOutput::OutputEvent(ev);
	}
	
	fprintf(fileptr, "\n\t\thelp\t\t\"");
	
	text = ev->GetDocumentation();
	for ( i=0; i<strlen(text); i++ )
	{
		if ( text[i] == '\n' )
			fprintf(fileptr, "\n\t\t\t\t");
		else
			fprintf(fileptr, "%c", text[i]);
	}
	
	fprintf(fileptr, "\"\n");
	fprintf(fileptr, "\t}\n");
	
	text = ev->GetDocumentation();
}

//================================================================
// Name:				OutputArgument
// Class:			ToolDocFileOutput
//
// Description:	Write the argument output for this type of file
//
// Parameters:		EventArgDef *evarg -- EventArgs to write out
//
// Returns:			None
//
//================================================================
void ToolDocFileOutput::OutputArgument(EventArgDef *evarg)
{
	// Check for Randoms.  If there is one, print out the "random" keyword
	// and set the random flag, so next next time this function is called,
	// it is assumed to be the random parameter's name.
	if ( !strcmp(evarg->getName(), "[randomtype]") )
	{
		fprintf(fileptr, "\t\trandom");
		randFlag = true; // Set the random flag
		return;
	}
	
	// If the random flag is set, we assume the previous call to this function
	// was a [randomtype] parameter.  We now output the name of the random parameter,
	// which is assumed to be a float. (All randoms ARE floats, correct?)
	if ( randFlag ) 
	{
		fprintf(fileptr, "\t\t%s\t\"%s\"\n",evarg->getName(), evarg->getName());
		randFlag = false;
		return;
	}
	
	// If it's a vector that's supposed to specify a color, we directly print it here
	if ( strstr(evarg->getName(), "color_") && evarg->getType() == IS_VECTOR )
	{
		fprintf(fileptr, "\t\trgb\t\t%s\t\"%s\"\n",evarg->getName(), evarg->getName());
		return;
	}
	
	// If the event takes an RGB color (three floats), we must do special casing to 
	// output a single color parameter.
	// If we find color_red, we ASSUME it's the start of an RGB set.
	if ( strstr(evarg->getName(), "color_red") && evarg->getType() != IS_VECTOR )
	{
		char tmpstr[25], *sptr;
		strcpy(tmpstr,evarg->getName());
		sptr = strtok(tmpstr,"_"); // color
		sptr = strtok(NULL,"_"); // red
		sptr = strtok(NULL,"_"); // potential name or NULL
		
		colorFlag = true;
		if ( sptr == NULL )
			fprintf(fileptr, "\t\trgb\t\tcolor\t\"color\"\n");
		else
			fprintf(fileptr, "\t\trgb\t\t%s\t\"%s\"\n", sptr, sptr);
		return;
	}
	
	// If we find color_blue, we ASSUME is the end of an RGB set
	if ( colorFlag && strstr(evarg->getName(), "color_blue") )
	{
		colorFlag = false;
		return;
	}
	
	// If the colorFlag is still set by the time we get here, we are in
	// the process of ignoring parameters until the color is done.
	if ( colorFlag )
		return;
	
	// If we reach this point it is assumed that it is not one of the special case parameters
	// listed above.
	if ( evarg->isOptional() )
		fprintf(fileptr, "\t\t|" );
	else
		fprintf(fileptr, "\t\t");
	
	switch( evarg->getType() )
	{
	case IS_ENTITY:
		fprintf(fileptr, "string\t\t" );
		break;
	case IS_VECTOR:
		fprintf(fileptr, "xyz\t\t" );
		break;
	case IS_INTEGER:
		fprintf(fileptr, "int\t\t" );
		break;
	case IS_FLOAT:
		fprintf(fileptr, "float\t\t" );
		break;
	case IS_STRING:
		fprintf(fileptr, "string\t\t" );
		break;
	case IS_BOOLEAN:
		fprintf(fileptr, "boolean\t\t" );
		break;
	}
	fprintf(fileptr, "%s\t", evarg->getName() );
	fprintf(fileptr, "\"%s\"\t", evarg->getName() );
	
	// print the range of the argument
	OutputRange(evarg);
	fprintf(fileptr, "\n");
	
	DocFileOutput::OutputArgument(evarg);
}

//================================================================
// Name:				OutputRange
// Class:			ToolDocFileOutput
//
// Description:	Writes the range of the event arg passed if any
//
// Parameters:		EventArgDef *evarg -- Argument to check for a range
//
// Returns:			None
//
//================================================================
void ToolDocFileOutput::OutputRange(EventArgDef *evarg)
{
	int i;
	
	// Event type is a vector
	if ( evarg->getType() == IS_VECTOR )
	{
		for ( i=0; i<3; i++ )
		{
			if ( evarg->GetMinRangeDefault(i) || evarg->GetMaxRangeDefault(i) )
				return;
		}
		
		fprintf(fileptr, "%.2f %.2f %.2f %.2f %.2f %.2f\n", 
			evarg->GetMinRange(0), evarg->GetMinRange(1), evarg->GetMinRange(2), 
			evarg->GetMaxRange(0), evarg->GetMaxRange(1), evarg->GetMaxRange(2) );
		
		return;
	}
	
	// Event type is a string
	if ( evarg->getType() == IS_STRING )
	{
		if ( !evarg->GetMinRangeDefault(0) )
		{
			fprintf(fileptr, "%d", ( int )evarg->GetMinRange(0) );
		}
		
		return;
	}
	
	// Default checks
	if ( !evarg->GetMinRangeDefault(0) && !evarg->GetMaxRangeDefault(0) )
	{
		if ( evarg->getType() == IS_FLOAT )
			fprintf(fileptr, "%.2f %.2f", evarg->GetMinRange(0), evarg->GetMaxRange(0) );
		else
			fprintf(fileptr, "%d %d", ( int )evarg->GetMinRange(0), ( int )evarg->GetMaxRange(0) );
	}
}

//================================================================
// Name:				PrintSubClasses (private)
// Class:			ToolDocFileOutput
//
// Description:	Recursive function that prints all the passed classes
//						subclasses.
//
// Parameters:		ClassDef *in_class -- the class to print the subclasses of
//
// Returns:			None
//
//================================================================
void ToolDocFileOutput::PrintSubClasses(ClassDef *in_class, ClassDef *classlist)
{
	ClassDef *c;
	OutputClass(in_class);
	for( c = classlist->next; c != classlist; c = c->next )
	{
		if ( c->super == in_class )
			PrintSubClasses(c, classlist);
	}
}

//================================================================
// Name:				OutputClasses
// Class:			ToolDocFileOutput
//
// Description:	Override of the base class version.  This is a special
//						fuctions that loops through the classes in a specific way.
//						For each root node, we recursively print all it's children.
//						This way, all classes' super classes are printed first
//
// Parameters:		ClassDef *classlist -- The list of classes to loop through
//
// Returns:			None
//
//================================================================
void ToolDocFileOutput::OutputClasses(ClassDef *classlist)
{
	ClassDef *c;
	
	// Make a container of all the root class names
	for( c = classlist->next; c != classlist; c = c->next )
	{
		if ( c->super == NULL )
			PrintSubClasses(c, classlist);
	}
}
