/*  classrel.C   */
/*  Copyright 1991 Mountain Math Software  */
/*  All Rights Reserved                    */
#include <stream.h>
#include <string.h>
#include "outtok.h"
#include "classrel.h"
#include "debug.h"
#include "menuprsy.h"
#include "menustr.h"
#include "linlist.h"
#include "texutil.h"


ClassRelationList TheClassRelations;

void ClassRelation::SetTree(ClassRelation * base)
{
	// cerr << "SetTree(" << base->Derived << ")\n" ;
	if (BaseClass) cerr << "Two instances of base class `" <<
		Base << "' for `" << Derived << "'.\n" ;
	BaseClass = base ;
}

void ClassRelation::SetMembersExec(const MenuDef * menu)
{
	if (TheMemberFunctionExecuteTree) {
		cerr << "Warning: two member execute function trees for `" <<
			Derived << "'" ;
		OutWhereEnd();
		return ;
	}
	TheMemberFunctionExecuteTree = menu ;
}

void ClassRelation::SetMembers(const MenuDef * menu)
{
	if (TheMemberFunctionTree) {
		cerr << "Warning: two member function trees for `" <<
			Derived << "'" ;
		OutWhereEnd();
		return ;
	}
	TheMemberFunctionTree = menu ;
}

ClassRelation::ClassRelation(const char * derived, const char * base):
	Derived(derived),
	Base(base),
	BaseClass(0),
	TheMemberFunctionTree(0),
	TheMemberFunctionExecuteTree(0),
	HasMembersDirect(0),
	HasMembersDerived(0),
	BaseTablePrinted(0),
	DerivedFromMe(0),
	BrotherDerivedFrom(0)
{
}

void ClassRelation::SetBrother(ClassRelation * der)
{
/*
 *	cerr << Derived << "->SetBrother(" << der->Derived <<
 *		")\n" ;
 */
	if (!BrotherDerivedFrom) {
		BrotherDerivedFrom = der ;
		return ;
	}
	if (TeXstrcmp(BrotherDerivedFrom->Derived,der->Derived) > 0) {
		ClassRelation * temp = BrotherDerivedFrom ;
		BrotherDerivedFrom = der ;
		der = temp ;
	}
	BrotherDerivedFrom->SetBrother(der);
}

void ClassRelation::SetDerivedFromMe(ClassRelation * der)
{
	// cerr << "SetDerivedFromMe(" << der->Derived << ")\n" ;
	if (!DerivedFromMe) {
		DerivedFromMe = der ;
		return ;
	}
	if (TeXstrcmp(DerivedFromMe->Derived,der->Derived) > 0) {
		ClassRelation * Temp = DerivedFromMe ;
		DerivedFromMe = der ;
		der = Temp ;
	}
	DerivedFromMe->SetBrother(der);
}
	
	

void ClassRelation::Dump(OutTokens& Out) const
{
	Out.NextOut(Base);
	Out.NextOut(":");
	Out.NextOut(Derived);
	Out.NextOut("member tree");
	if (BaseClass) Out.NextOut(BaseClass->GetBase());
	else Out.NextOut("BASE CLASS VOID");
	if (TheMemberFunctionTree)
		Out.NextOut(TheMemberFunctionTree->GetName());
	else Out.NextOut("NO MEMBERS DESC");
	if (TheMemberFunctionExecuteTree)
		Out.NextOut(TheMemberFunctionExecuteTree->GetName());
	else Out.NextOut("NO MEMBERS EXE");
	Out.NextOut((int) HasMembersDirect);
	Out.NextOut((int) HasMembersDerived);
	Out.NewLine();
}

void ClassRelationList::ClassHasMembers(const char * Name)
{
	if (!Name) return ;
	if (DerivedSet) DbgError("ClassHasMembers","DerivedSet is set");
	ClassRelationListIterator Next(*this);
	ClassRelation * Check;
	while (Check = Next()) if (!strcmp(Check->Derived,Name)) {
		Check->HasMembersDirect = 1;
		return ;
	}
	DbgError("ClassHasMembers","no such class");
}


void ClassHasMembers(const char * Name)
{
	TheClassRelations.ClassHasMembers(GetNodeNameFromAction(Name));
}

void ClassRelationList::FoundMenuDef(const MenuDef& menu)
{
	if (!TheCurrentClass) return ;
	if (menu.IsMemberFunctionSelector()) TheCurrentClass->SetMembers(&menu);
	if (menu.IsMemberFunctionExecSelector())
		TheCurrentClass->SetMembersExec(&menu);
}


int ClassRelationList::DoesClassHaveMembers(const char *Name)
{
	if (!DerivedSet) SetDerivedMembers();
	ClassRelationListIterator Next(*this);
	ClassRelation * Check;
	while (Check = Next()) if (!strcmp(Check->Derived,Name)) {
		return Check->HasMembersDerived ;
	}
	DbgError("DoesClassHaveMembers","no such class");
	return 0 ;
}

void ClassRelationList::SetDerivedMembers()
{
	if (DerivedSet) return ;
	ClassRelationListIterator Next(*this);
	ClassRelation * Check;
	int ChangeOccured = 1 ;
	while (ChangeOccured) {
		ChangeOccured = 0;	
		while (Check = Next()) {
/*
 *			cout << "Checking:" << Check->Base << ", "
 *				<< Check->Derived << ", MembersDirect = " <<
 *				Check->HasMembersDirect << "\n" ;
 */
			if (Check->HasMembersDirect) Check->HasMembersDerived=1;
			if (Check->HasMembersDerived) {
				ClassRelationListIterator InNext(*this);
				ClassRelation * InCheck;
				while (InCheck = InNext()) {

/*					cout << "Checking against:" <<
 *						InCheck->Base << ", " <<
 *						InCheck->Derived << "\n" ;
 */

					if (!strcmp(InCheck->Base, Check->
					Derived)) if (!InCheck->
					HasMembersDerived) {
						ChangeOccured = 1;
						InCheck->HasMembersDerived=1;
					} // end update InCheck
				} // end inner loop
			} // end test to do inner loop
		} // end outer loop
	} // end of loop until no change occurs
	
	DerivedSet = 1 ;
}


void ClassRelationList::MakeClassTree(OutTokens& Out, ClassRelation* rel)
{
/*
 *	cerr << "MakeClassTreeList(, " << rel->Derived << ") enter\n" ;
 *	cerr << "MakeClassTreeList(, " << rel->Base << ") enter\n" ;
 */
	const char * Derived = rel->Derived ;

	ClassRelation * check ;
	ClassRelationListIterator Next(*this);
	while (check = Next()) {
/*
 *		Out.NextOut("Checking");
 *		Out.NextOut(check->Derived);
 *		Out.NextOut(rel->Base);
 *		Out.NewLine();
 */
		if (!strcmp(check->Derived,rel->Base)) {
			rel->SetTree(check);
			check->SetDerivedFromMe(rel);
		}
	}
	if (!rel->BaseClass) {
		Out.NextOut("% Base class ");
		Out.NextOut(rel->Base);
		Out.NextOut(" for ");
		Out.NextOut(rel->Derived);
		Out.NextOut(" not found.") ;
		Out.NewLine();
	}
	// cerr << "MakeClassTree(, " << rel->Derived <<") exit\n" ;
}

void ClassRelation::WriteItem(OutTokens& Out, int& ItemOut)
{
	// cerr << "Writing " << Derived << "\n" ;
	if (ItemOut&2) Out.NextConcat(",");
	ItemOut |= 2 ;
	Out.NextOutToken("{\\tt");
	Out.NextConcatToken(Derived);
	Out.NextOutToken("}");
}
	
int ClassRelation::WriteClassTreeItem(OutTokens& Out, int i, int& ItemOut)
{
	// cerr << "WriteClassTreeItem(, " << i << ", " << ItemOut <<")\n" ;
	if (!i) {
		if (!ItemOut&1) {
			Out.FlushLine();
			Out.NewLine();
			Out.NextOut("\\item");
		}
		ItemOut |= 1 ;
		WriteItem(Out, ItemOut);	
		if (BrotherDerivedFrom)
			BrotherDerivedFrom->WriteClassTreeItem(Out,i,ItemOut);
		// cerr << Derived << " returning  1.\n" ;
		return 1 ;
	}
	int Return = 0 ;
	if (BrotherDerivedFrom) Return =
		BrotherDerivedFrom->WriteClassTreeItem(Out,i,ItemOut);
	int Temp = 0;
	if (DerivedFromMe) Temp =
		DerivedFromMe->WriteClassTreeItem(Out,--i,ItemOut);
	int Ret = Temp || Return ;
	// cerr << Derived << " returning  " << Ret << ".\n" ;
	return Ret ;
}

void ClassRelation::WriteClassTreeList(OutTokens& Out) 
{
	int NewOutput = 1 ;
	for (int i = 0 ; NewOutput ; i++) {
		// cerr << "WriteClassTreeList i = " << i << "\n" ;
		int ItemOut = 0 ;	
		NewOutput = WriteClassTreeItem(Out,i,ItemOut);
	}
}

int ClassRelation::WriteClassTree(OutTokens& Out) 
{
	if (BaseTablePrinted) return 0 ;
	if (BaseClass) if (!BaseClass->BaseTablePrinted) return 1 ;
	BaseTablePrinted=1;
	if (!DerivedFromMe) return 0;
	if (!TheMemberFunctionTree) return 0 ;
	Out.NextConcatToken("\\subsection{{\\tt ");
	Out.NextConcatToken(Derived);
	Out.NextOutToken("} class hierarchy}");
	Out.FlushLine();
	Out.TeXIndexEntry(Derived);
	Out.FlushLine();
	Out.NewLine();
	Out.NextFillOut(
		"Following is a list of the classes derived from {\\tt");
	Out.NextConcatToken(Derived);
	Out.NextOutToken("}.");
	Out.NextFillOut("These classes share the member functions");	
	Out.NextConcatToken("listed in Section~\\PageRef{");
	Out.NextConcatToken(TheMemberFunctionTree->GetRef()) ;
	Out.NextOutToken("}");
	Out.NextConcatToken("and Section~\\PageRef{");
	if (TheMemberFunctionExecuteTree)
		Out.NextConcatToken(TheMemberFunctionExecuteTree->GetRef());
	else Out.NextConcatToken("No_member_function_execute_tree");
	Out.NextOutToken("}.");
	Out.NextFillOut("The derived class at each level are listed.");
	Out.NextFillOut("Each of these that is a base class has its");
	Out.NextFillOut("derived classes listed in a later section.");

	Out.FlushLine();
	Out.NewLine();
	Out.NextOut("\\begin{enumerate}");
	Out.FlushLine();
	Out.NewLine();
	DerivedFromMe->WriteClassTreeList(Out);
	Out.FlushLine();
	Out.NextOut("\\end{enumerate}");
	Out.FlushLine();
	Out.NewLine();
	return 1 ;
}

void ClassRelationList::WriteClassTree(OutTokens& Out)
{
	ClassRelation * rel ;
	int DidOutput = 1 ;
	while (DidOutput) {
		DidOutput = 0 ;
		ClassRelationListIterator Next(*this);
		while (rel = Next()) {
			int Temp = rel->WriteClassTree(Out);
			DidOutput |= Temp ;
		}
	}
}

void ClassRelationList::MakeClassTree(OutTokens& Out)
{
	Out.NextFillOut("\\section{Class hierarchy}\\index{class hierarchy}");
	Out.FlushLine();
	Out.NextFillOut("\\label{Sec:ClassStruc}");
	Out.FlushLine();
	Out.NewLine();
	Out.NextFillOut("This section describes the \\Dpp{} class hierarchy");
	Out.NextFillOut("for user objects. C++ allow a set");
	Out.NextFillOut("of member functions to be available in all classes");
	Out.NextFillOut("derived form the base class in which the member");
	Out.NextFillOut("functions are defined.");

	ClassRelation * rel ;
	ClassRelationListIterator Next(*this);
	while (rel = Next()) MakeClassTree(Out,rel);
	WriteClassTree(Out);
}

const char * ClassRelationList::GetCurrentBaseClass() const 
{
	if (!TheCurrentClass) return 0 ;
	return TheCurrentClass->Base ;
}

const char * ClassRelationList::GetCurrentDerivedClass() const
{
	if (!TheCurrentClass) return 0 ;
	return TheCurrentClass->Derived ;
}

void ClassRelationList::TeXPrintClassHierarchy(OutTokens& Out)
{
	MakeClassTree(Out);
	// Dump(Out);
}

void ClassRelationList::Dump(OutTokens& Out)
{
	ClassRelation * rel ;
	ClassRelationListIterator Next(*this);
	while (rel = Next()) rel->Dump(Out);
}

const char * ClassRelationList::GetDerived() const
{
	if (!TheCurrentClass) return 0 ;
	return TheCurrentClass->GetDerived() ;
}


void ClassRelation::TeXOutDescribeRef(OutTokens& Out) const
{
	// cerr << "TeXOutDescribe for `" << GetDerived() << "'.\n" ;
	int AnyOut = 0;
	const ClassRelation * Bases = this ;
	int Count = 0 ;
	while (Bases = Bases->BaseClass)  {
/*
 *		cerr << "Checking `" << Bases->GetDerived() << "' " <<
 *			(Bases->TheMemberFunctionTree != 0) << "\n" ;
 */
		if (Bases->TheMemberFunctionTree) Count++ ;
	}
	// cerr << "Count = " << Count << "\n" ;
	if (!Count) return ;
	Bases = this ;
	int Index = 0 ;
	const MenuDef * MenuTree ;
	while (Bases = Bases->BaseClass) {
/*
 *		cerr << "Checking " << Base << " for " << Bases->Derived
 *			<< "\n" ;
 */
		if (MenuTree = Bases->TheMemberFunctionTree) {
			if (!Index++) Out.NextOut("See ");
			else if (Index==Count) Out.NextOut("and");
			else Out.NextConcat(",") ;
			MenuTree->OutRef(Out) ;
		}
	}
	Out.NextFillOut(
		"for additional base class member functions in this menu.");
}

void ClassRelation::TeXOutExecuteRef(OutTokens& Out) const
{
	int AnyOut = 0;
	const ClassRelation * Bases = this ;
	int Count = 0 ;
	while (Bases = Bases->BaseClass)
		if (Bases->TheMemberFunctionExecuteTree) Count++ ;
	if (!Count) return ;
	Bases = this ;
	int Index = 0 ;
	const MenuDef * MenuTree ;
	while (Bases = Bases->BaseClass) {
/*
 *		cerr << "Checking " << Base << " for " << Bases->Derived
 *			<< "\n" ;
 */
		if (MenuTree = Bases->TheMemberFunctionExecuteTree) {
			if (!Index++) Out.NextOut("See ");
			else if (Index==Count) Out.NextOut("and");
			Out.NextConcat(",") ;
			MenuTree->OutRef(Out) ;
		}
	}
	Out.NextFillOut(
		"for additional base class member functions in this menu.");
}


