/*  texmenu.C   */
/*  Copyright 1991 Mountain Math Software  */
/*  All Rights Reserved                    */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "menustr.h"
#include "domenus.h"
#include "linlist.h"
#include "debug.h"
#include "outtok.h"
#include "texmenu.h"
#include "mkstr.h"
#include "parammen.h"
#include "texutil.h"
#include "classrel.h"

const char * MainCgiMenu = "AllCgiMenus" ;
TeXMenus * TheTeXMenus = 0 ;

ObjectDescript::ObjectDescript(const char * name, void * obj,
	const MenuDef * parent, ObjectType type, const MenuDef * child):
	Name(name),
	Obj(obj), 
	Parent(parent),
	Type(type),
	Child(child),
	OutputFlag(0),
	PrintDynamic(0),
	DoNotPrint(0),
	Ref(0)
{
}

/*
 * char * ReplaceUnderScoreWithColon(const char * In)
 * {
 *	char * Out = Concatenate(In);
 *	for (char * Pt = Out; *Pt;Pt++) if (*Pt == '_') *Pt = ':' ;
 *	return Out ;
 * }
 */
/*
 * void ObjectDescript::SetParent(const ObjectDescript ** Universe)
 * {
 * }
 */

void ObjectDescript::SetRef(int Entry)
{
	// char * NoUnderScore = 0 ;
	char buf[32] ;
 	switch(Type) {
case MenuObjectType:
		// NoUnderScore = ReplaceUnderScoreWithColon(Name);
		// Ref = Concatenate("Men",dec(Entry),NoUnderScore);
		sprintf(buf,"%d",Entry);
		Ref = Concatenate("M",buf);
		break ;
case MenuCommandObjectType:
case CommandObjectType:
/*
 *		NoUnderScore = ReplaceUnderScoreWithColon(
 *			GetCommand()->GetAction()->GetName());
 *		Ref = Concatenate("Cmd",dec(Entry),NoUnderScore);
 */
		sprintf(buf,"%d",Entry);
		Ref = Concatenate("C",buf);
		break ;
	}
	// delete NoUnderScore ;
}

int ObjectDescript::IsThis(const char * name) const
{
	return !strcmp(name,Name);
}

void ObjectDescript::CheckIsChild() const 
{
	if (Type == MenuCommandObjectType) return ;
	DbgError("ObjectDescript::CheckIsChild","fail");
}
 

void ObjectDescript::CheckIsMenu() const
{
	if (Type != MenuObjectType)
		DbgError("ObjectDescript::CheckIsMenu","fail");
}
 
void ObjectDescript::CheckIsCommand() const
{
	if (Type == MenuObjectType)
		DbgError("ObjectDescript::CheckIsCommand", "fail");
}


const char * ObjectDescript::GetParentRef() const
{
	if (GetParent()) return  GetParent()->GetRef();
	return 0 ;
}

const char * ObjectDescript::GetChildRef() const
{
	if (GetChild()) return GetChild()->GetRef();
	return 0 ;
}


TeXMenus::TeXMenus(MenuDefList & the_menus,
	DynamicMenusToPrint * DynPrintList,
	const ForceSectionLevel * fixed_levels):
	TheMenus(the_menus),
	AllCommands(0),
	AllMenus(0),
	TempMenuIterator(0),
	TempMenu(0),
	MainMenuName(0),
	TempItemIterator(0),
	DynamicPrintList(DynPrintList),
	FixedSectionLevels(fixed_levels)
{
	cerr << "Extracting Commands\n" ;
	ExtractCommands();
	cerr << "Extracting Menus\n" ;
	ExtractMenus();
}


static int CommandNameSort(const void * a, const void * b)
{
	const ObjectDescript ** A = (const ObjectDescript **) a ;
	const ObjectDescript ** B = (const ObjectDescript **) b ;
	if (!A) if (!B) return 0 ; else return -1 ;
	if (!B) return 1 ;

	const MenuItem * CmdA = (*A)->GetCommand();
	const MenuItem * CmdB = (*B)->GetCommand();
	if (!CmdA) if(!CmdB) return 0 ; else return -1 ;
	if (!CmdB) return 1 ;

	const char * Aa = CmdA->GetCommand();
	const char * Bb = CmdB->GetCommand();
	if (!Aa) if (!Bb) return 0; else return -1 ;
	if (!Bb) return 1 ;
	int Return = TeXstrcmp(Aa,Bb);
	if (Return) return Return ;

	Aa = CmdA->GetMenuString();
	Bb = CmdB->GetMenuString();
	if (!Aa) if (!Bb) return 0; else return -1 ;
	if (!Bb) return 1 ;
	return TeXstrcmp(Aa,Bb);
}


static int MenuNameSort(const void * a, const void * b)
{
	const ObjectDescript ** A = (const ObjectDescript **) a ;
	const ObjectDescript ** B = (const ObjectDescript **) b ;
	if (!A) if (!B) return 0 ; else return -1 ;
	if (!B) return 1 ;
	const char * Aa = (*A)->GetName();
	const char * Bb = (*B)->GetName();
	if (Aa[0] != Bb[0]) {
		if (Aa[0] == '#' ) return 1 ;
		if (Bb[0] == '#' ) return -1 ;
	}
	if (!Aa) if (!Bb) return 0; else return -1 ;
	if (!Bb) return 1 ;
	return TeXstrcmp(Aa,Bb);
}

void TeXMenus::CreateObjectList(ObjectDescript**& ObjList,
	GetNextObject Next, CompareRoutine Compare)
{
	ObjectDescript ** Temp = 0 ;
	ObjectDescript * NextObj ;
	while (NextObj = (ObjectDescript *) (this->*Next)())
		Temp = (ObjectDescript **) AddToList( NextObj, (void **) Temp);

	qsort((char *) Temp,ListLength((const void **) Temp),
		sizeof(*Temp),Compare);


	for (int i = 0 ; Temp[i]; i++) {
 		Temp[i]->SetRef(i);
		// Temp[i]->SetParent(Temp); DONE EARLIER
	}	
	ObjList = Temp ;
}

void TeXMenus::ClearMenuIterators()
{
	delete TempMenuIterator ;
	TempMenuIterator = 0 ;
	delete TempItemIterator ;
	TempItemIterator = 0 ;
	TempMenu = 0 ;
}

ObjectDescript * TeXMenus::GetNextMenuObject()
{
	if (!GetNextMenu()) return 0 ;
	ObjectDescript * Return = new ObjectDescript(TempMenu->Name,
		(void*)TempMenu, TheMenuDefs.FindParentMenu(TempMenu->Name),
		ObjectDescript::MenuObjectType);

	TempMenu->SetMenuObject(Return);
	return Return ;
}

ObjectDescript * TeXMenus::GetNextCommandObject()
{
	MenuItem * NextItem = GetNextItem() ;
	if (!NextItem) return 0 ;

	ObjectDescript::ObjectType Type = ObjectDescript::CommandObjectType ;
	const MenuDef * Parent = TempMenu ;
	const MenuDef * Child = 0 ;

	if (NextItem->IsMenu()) {
		Type = ObjectDescript::MenuCommandObjectType ;
		Child = TheMenuDefs.FindMenu(NextItem->GetRefName()) ;
	}
	ObjectDescript * Return = new ObjectDescript(NextItem->GetCommand(),
		(void *) NextItem, Parent, Type, Child) ;
	
	NextItem->SetCommandObject(Return);
	return Return ;
}
	
MenuItem * TeXMenus::GetNextItem()
{
	MenuItem * NextItem = 0 ;
	while (!NextItem) {
		if (!TempItemIterator) GetItemIterator();
		if (!TempItemIterator) return 0 ;
		NextItem = (*TempItemIterator)();
		if (!NextItem) TempItemIterator = 0 ;
	}
	return NextItem ;
}


MenuItemListIterator * TeXMenus::GetItemIterator()
{
	for (;;) {
		if (!TempMenuIterator || !TempItemIterator || !TempMenu)
			GetNextMenu();
		if (!TempMenu) return TempItemIterator = 0 ;
		if (!TempMenu->Items) {
			TempMenu = 0 ;
			continue ;
		}
		TempItemIterator=new MenuItemListIterator(*(TempMenu->Items));
		return TempItemIterator ;
	}
}

const MenuDef * TeXMenus::GetNextMenu()
{
	if (!TempMenuIterator) TempMenuIterator =
		new MenuDefListIterator(TheMenus) ;
	TempItemIterator = 0 ;
	return TempMenu = (*TempMenuIterator)();
}

void DynamicMenusToPrint::SetRef(const char * ref)
{
	Ref = ref;
}

void DynamicMenusToPrint::BadUserName(const char * found) const
{
	cerr << "Expected command name `" << UserName  <<
		"' in menu `" << MenuName << "'.\n" ;
	cerr << "Found command name `" << found <<
		"'.\n" ;
	cerr << "CHECK THE DYNAMIC MENU PRINT LIST.\n" ;
}

int TeXMenus::HeadPrintDynamicTree(const char * MenuName) const
{
	for (const DynamicMenusToPrint * Check = DynamicPrintList;
		Check->MenuName ; Check++)
			if (!strcmp(Check->MenuName,MenuName)) return 1 ;
	return 0 ;
}

int TeXMenus::IsDynamicPrintMenu(MenuDef * menu)
{
	if (!DynamicPrintList) return 1 ;
	int FirstFound = 1 ;
	for (DynamicMenusToPrint * Check = DynamicPrintList;
		Check->MenuName ; Check++)
			if (!strcmp(Check->MenuName,menu->Name)) {

			const MenuItem * Parent = menu->GetParentItem();
			if (strcmp(Check->UserName,Parent->GetCommand()))
				Check->BadUserName(Parent->GetCommand()) ;
			// ((DynamicMenusToPrint *)Check)->SetRef(menu->GetRef());
			Check->Ref = menu->GetRef();
			FirstFound = 0 ;
			return 1 ;
		}
	return 0 ;
}


void TeXMenus::SetDynamicPrintMenus(ObjectDescript ** menus)
{
	// Print Everything
	for ( ObjectDescript ** Obj = menus; *Obj; Obj++) {
		MenuDef * menu = (*Obj)->GetMenu();

		int IsDynamic = IsDynamicPrintMenu(menu);
/*
 *		if (IsDynamic) cerr << "Found dynamic tree base " <<
 *			menu->Name << ".\n" ;
 */

		(*Obj)->SetPrintDynamic(IsDynamic);
	}

	for ( Obj = menus; *Obj; Obj++)
		if ((*Obj)->IsPrintDynamic())
			(*Obj)->GetMenu()->SetChildrenPrintDynamic(0);

	for ( Obj = menus; *Obj; Obj++) {
		const MenuDef * Menu = (*Obj)->GetMenu();
		if ((Menu->IsDynamicMenu() || Menu->Type.IsMultiUse()) &&
			!(*Obj)->IsPrintDynamic())
				((MenuDef *)Menu)->SetDoNotPrint();
	}
}

void TeXMenus::ExtractCommands()
{
	ClearMenuIterators();
	ObjectDescript ** TempCommands ;
	CreateObjectList(TempCommands, &TeXMenus::GetNextCommandObject,
		CommandNameSort); 
	cerr<< "Commands found = "<<ListLength((const void **)TempCommands)<<"\n" ;
	AllCommands = (const ObjectDescript **) TempCommands ;
	ClearMenuIterators();
}


void TeXMenus::ExtractMenus()
{
	ClearMenuIterators();
	ObjectDescript ** TempMenus ;
	CreateObjectList(TempMenus, &TeXMenus::GetNextMenuObject,
		MenuNameSort); 
	cerr << "Menus found = " << ListLength((const void **) TempMenus) << "\n" ;

	SetDynamicPrintMenus(TempMenus);
	AllMenus = (const ObjectDescript **) TempMenus ;
	ClearMenuIterators();
}


void TeXMenus::TeXPrintMenuFile(ostream& out)
{
	// cerr << "TeXPrintMenuFile\n" ;
	MainMenuName = MainEntrys.FindMainMenu(MainCgiMenu);
	const MenuDef * TheMainMenu = 0 ;
	if (MainMenuName) TheMainMenu = TheMenuDefs.FindMenu(MainMenuName);
	if (!TheMainMenu) {
		cerr << "Cannot find main menu of type `" <<
			MainCgiMenu <<"'.\n" ;
		cerr << "No TeX menu descriptions genereated.\n" ;
		return ;
	}
	// cerr  << "MainMenuName = " << MainMenuName << "\n" ;
	TheMainMenu->PrintAllTeXMenus(out);
}

void TeXMenus::TeXPrintClassHierarchy(ostream& out)
{
	OutTokens Out(&out,0,""," ","",80,1000000);
	TheClassRelations.TeXPrintClassHierarchy(Out);
}

void TeXMenus::TeXPrintCommandRefFile(ostream& out)
{
	// cerr << "TeXPrintCommandRefFile\n" ;
	OutTokens Out(&out,0,""," ","",80,1000000);
	for ( const ObjectDescript ** Obj = AllCommands; *Obj ; Obj++) {
		const MenuItem * TheItem = (*Obj)->GetCommand();
		if (TheItem) TheItem->TeXPrintCommand(Out);
	}
}


const char * TeXMenus::GetTeXMenuRef(const char * Name)
{
	if (EmptyString(Name)) 0 ;
	const ObjectDescript * Obj = GetMenuObject(Name);
	if (!Obj) return 0 ;
	return Obj->GetRef();
}

const char * TeXMenus::GetTeXCommandRef(const char * Name)
{
	if (EmptyString(Name)) 0 ;
	const ObjectDescript * Obj = GetCommandObject(Name);
	if (!Obj) return 0 ;
	return Obj->GetRef();
}

const ObjectDescript * TeXMenus::GetObject(const char * Name,
	const ObjectDescript ** Lst) const
{
	if (EmptyString(Name)) return 0 ;
	for (const ObjectDescript ** Ck = Lst ; *Ck ; Ck++)
		if((*Ck)->IsThis(Name))
		return *Ck ;
	return 0 ;
}

const ObjectDescript * TeXMenus::GetMenuObject(const char * Name) const
{
	return GetObject(Name,AllMenus);
}

const ObjectDescript * TeXMenus::GetCommandObject(const char * Name) const
{
	return GetObject(Name,AllCommands);
}

int TeXMenus::GetFixedLevel(const char * MenuName) const  // -1 for none
{
	if (FixedSectionLevels)
		for (const ForceSectionLevel * find = FixedSectionLevels;
			find->MenuName; find++)
				if(!strcmp(find->MenuName,MenuName))
					return find->Level ;
	return -1 ;
}

const char * TeXMenus::GetDynamicMenuTreeExamples(ToGet DoWhat) const 
{
	static int Count = 0 ;
	switch(DoWhat) {
case TeXMenus::InitGet:
		Count = 0 ;
		break ;
case TeXMenus::NextGet:
		break ;
	}
	
	const DynamicMenusToPrint * NextPrint = DynamicPrintList + Count ;
	if (!NextPrint->MenuName) return 0 ;
	Count++ ;
	if (!NextPrint->Ref) {
		cerr << "No reference for`" << NextPrint->MenuName << "'.\n" ;
		return "No_reference_for_menu" ;
	}
	return NextPrint->Ref ;
}



