/*  intfc.c   */
/*  Copyright 1989 Mountain Math Software  */
/*  All Rights Reserved                    */
#include <stream.h>
#include <string.h>
#include <ctype.h>

#include "outtok.h"
#include "usercom.h"
#include "baseio.h"

#include "intfc.h"
#include "user.h"
#include "array.h"
#include "cgidbg.h"

InteractiveEntityList * TheNodes;
InteractiveEntityList * TheCmpdNodes;
InteractiveEntityList * TheNets;
InteractiveEntityList * TheBuffers;
InteractiveEntityList * TheSchedulers;
InteractiveEntityList * TheProcedures;
InteractiveEntityList * TheMiscellaneousClasses ;

InteractiveGlobal * AllEntityLists = 0;

ValueType * InteractiveGlobal::find_obj(const char * Name) const
{
	ValueType * Return ;
	for (UserBasicObjects ** basic = AllBasicObjs; *basic; basic++)
		if (Return = (*basic)->FindObj(Name)) return Return ;
	return 0 ;
}

int InteractiveGlobal::IsPrimaryEntity(const char * Name) const
{
	for (InteractiveEntityList ** Ptr = AllEntities; *Ptr; Ptr++) 
		if (!strcmp(Name,(*Ptr)->GetBaseClassName())) return 1 ;
	return 0 ;
}

InteractiveEntity::InteractiveEntity(const char * Name, EntityList * InitList,
	CreateEntity Cre, InteractiveType IntType, const char *header,
	ValueType ** members, const char * BaseEntityName):HeaderFile(header)
{
	// LogOut << "InteractiveEntity_ctor(" << Name << ")\n" ;
	EntityInstances=InitList;
	if (!AllEntityLists) InteractiveInit();
	// LogOut << "After InteractiveInit\n" ;
	EntityClassName=Name;
	DoCreate = Cre;
	Parameters = 0;
	ThisValue = ValueType(DecDspPP,0,DoDeclEntity,this);
	// LogOut << "InteractiveEntity_ctor got ThisValue\n" ;
	BaseClass = AllEntityLists->GetInteractiveEntityList(IntType);
	// LogOut << "InteractiveEntity_ctor got BaseClass\n" ;
	Members = members ;
	BaseEntity = 0;
	BrotherEntity = 0;
	DerivedEntity = 0;
	if (BaseEntityName) {

		// LogOut << "BaseEntityName is: `" << BaseEntityName << "'\n" ;
		// LogOut << "Constructing entity `" << Name << "'\n";
 
		BaseEntity =
			AllEntityLists->GetInteractiveEntity(BaseEntityName);
		if (!BaseEntity) if(AllEntityLists->
			IsPrimaryEntity(BaseEntityName)) return; 
		else {

 			TheLog << "BaseEntityName is: `" << BaseEntityName <<
				"'\n" ;
			TheLog << "Constructing entity `" << Name << "'\n";
			DbgError("InteractiveEntity::ctor", "no such entity");
		}
		BaseEntity->SetDerivedEntity(this);
	}
}

void InteractiveEntity::SetDerivedEntity(InteractiveEntity * derived)
{
	if (!DerivedEntity) {
		DerivedEntity = derived ;
		return ;
	}
	DerivedEntity->SetBrotherEntity(derived);
}



void InteractiveEntity::SetBrotherEntity(InteractiveEntity * brother)
{
	if (!BrotherEntity) {
		BrotherEntity = brother ;
		return ;
	}
	BrotherEntity->SetBrotherEntity(brother);
}


int32 InteractiveEntity::ListSize()
{
	return EntityInstances->Size();
}

ValueType * InteractiveEntity::FindObj(const char * Name)
{
	EntityListIterator Next(*EntityInstances) ;
	UserEntity * Ent ;
	while (Ent=Next()) if (!strcmp(Name,Ent->GetName())) 
		return Ent->GetValue() ;
	return 0;
}

UserEntity * InteractiveEntity::GetObject(const char * Name)
{
	ValueType * Value = FindObj(Name);
	if (!Value) return 0;
	if (Value->Type != DecEnt) TheLog << "*************** " <<
		"bad type from FindObjValue for: `" << Name << "'.\n" ;
	return Value->Value.ValEnt ;
}

UserEntity * InteractiveEntity::GetEntity(OutTokens& Out)
{
	for (;;) {
		Describe(Out,ListEntityMembers) ;
		Out.NewLine() ;	
		const char * Name = GetName("object name or RETURN");
		if (!strlen(Name)) {
			delete (char *) Name ;
			return 0;
		}
		EntityListIterator Next(*EntityInstances) ;
		UserEntity * Entity ;
		while (Entity = Next()) if (!strcmp(Name,Entity->GetName())) {
			delete (char *) Name ;
			return Entity ;
		}
		Out.NextFillOut("There is no node");
		Out.NextFillOut(Name);
		Out.NextFillOut("in class");
		Out.NextFillOut(EntityClassName);
		Out.NextConcat(".");
	}
}



void UserParameters::ListValue(const char * Name, OutTokens& Out)
{
	for(int i = 0 ;Parameters[i].Name;i++)
		if (!strcmp(Parameters[i].Name,Name)) {
			Out.NextFillOut("This parameter is of type");
			Out.NextQuoteOut(Parameters[i].GetTypeName());
			Parameters[i].ListValue(Out) ;
			return ;
		}
	*Output + OutputCppHelp << "There is no parameter `" << Name <<
		"'.\n" ;
}


void UserParameters::ListValues(OutTokens& Out)
{
	int i = 0 ;
	while (Parameters[i].Name)
		Parameters[i++].ListValue(Out) ;
	
}

void UserParameters::List(OutTokens& Out,int Num)
{
	int i = 0 ;
	while (Parameters[i].Name)
		Parameters[i++].List(Out,Num) ;
	
}

void InteractiveEntity::Describe(OutTokens& Out, ListEntity Option)
{
	UserEntity * Entity ;
	switch(Option) {
case ListSingleEntity:
		Entity = GetEntity(Out) ;
		if (Entity) {
			Entity->Describe(Out, Option) ;
			return ;
		}
		return ;
case ListEntityMembers:
		Out.NextFillOut("The derived classes from base class") ;
		Out.NextFillOut(EntityClassName);
		Out.NextFillOut("are:");
		Out.NewLine();
		if (!EntityInstances) DbgError("InteractiveEntity::List",
			"NULL EntityInstances" ) ;
		EntityInstances->Describe(Out, Option);
		Out.NewLine() ;
		Out.NewLine();
		Out.NextFillOut("Following is a description of derived class");
		Out.NextFillOut(EntityClassName);
		Out.NextConcat(":") ;
		Out.NewLine();
		DoCreate(Out,EntityReqDescribeFull,*this) ;
		Out.NewLine();
		Out.NewLine();
		Out.NextFillOut("The parameters for");
		Out.NextFillOut(EntityClassName);
		Out.NextFillOut("are:");
		Out.NewLine();
		Parameters->List(Out,EntityInstances->Size()) ;
		return ;
case ListEntityClasses:
		Out.NextFillOut(EntityClassName) ;
case ListGlobalClasses:
case ListSetParameterValues:
		return ;
	}
}


InteractiveEntity * InteractiveEntityList::Find(const char * Name)
{
	// LogOut << "Searching list `" << Name << "'\n" ;
	InteractiveEntityIterator TheNext(*this) ;
	InteractiveEntity * IntEntity ;
	while (IntEntity = TheNext()) {
/*
 *		LogOut << "InteractiveEntityList::Find(" << Name <<
 *			") - checking `" << IntEntity->GetClassName() << "'\n";
 */
		if (!strcmp(Name, IntEntity->GetClassName())) return IntEntity ;
	}
	return 0;
}

InteractiveEntity * InteractiveEntityList::GetInteractiveEntity(OutTokens& Out)
{
	for (;;) {
		Describe(Out,ListEntityClasses);
		const char * Name = GetName(
			"derived class name or RETURN");
		if (!strlen(Name)) {delete (char *) Name; return 0;}
		InteractiveEntity * IntEntity ;
		if (!(IntEntity = Find(Name))) {
			*Output + OutputHelp << "There is no derived class `" <<
				Name << "'.\n" ;
			IntEntity = 0;
		}
		delete (char *) Name ;
		if (IntEntity) return IntEntity ;
	}
}

void InteractiveEntityList::Describe(OutTokens& Out, ListEntity Option)
{
	InteractiveEntity * IntEntity ;

	switch(Option) {
case ListSingleEntity:
case ListEntityMembers:
		{
			InteractiveEntity*IntEntity=GetInteractiveEntity(Out);
			if (IntEntity) {
				IntEntity->Describe(Out, Option) ;
				Out.NewLine() ;
			}
			return ;
		}
case ListEntityClasses:
		{
		Out.NextFillOut("The derived classes are:");
		Out.NewLine() ;
		{
			InteractiveEntityIterator Next(*this) ;
			while (IntEntity =Next()) IntEntity->Describe(Out,Option) ;
		}
		Out.NewLine() ;
case ListSetParameterValues:
case ListGlobalClasses:
		break ;
		}
	}
}

void InteractiveEntityList::Create()
{
	OutTokens Out(OutputCppHelp) ;
	InteractiveEntity * IntEntity = GetInteractiveEntity(Out);
	if (IntEntity) IntEntity->Create(Out) ;
}

void InteractiveEntityList::Delete()
{
	OutTokens Out(OutputCppHelp) ;
	InteractiveEntity * IntEntity = GetInteractiveEntity(Out);
	IntEntity->Delete(Out) ;
}

UserEntity * InteractiveEntity::DoRequest(OutTokens& Out,EntityReq Req)
{
	return DoCreate(Out,Req,*this) ;
}

UserEntity * InteractiveEntity::Create(OutTokens& Out)
{
	UserEntity * Entity = DoCreate(Out,EntityReqCreate,*this) ;
	if (!EntityInstances) DbgError("InteractiveEntity::Create","NO List");
	return Entity ;
}

UserEntity * InteractiveEntity::InteractiveCreateDefault(OutTokens& Out)
{
	Parameters[0].GetDefaultName(this);
	Parameters->GetDefaultParameters(0,1);
	return DoCreate(Out,EntityReqCreate,*this) ;	// Do create
}

UserEntity * InteractiveEntity::InteractiveCreate(OutTokens& Out)
{
	if (!GetParameters(ListSize())) return 0 ; // Fetch parameters from user
	return DoCreate(Out,EntityReqCreate,*this) ;	// Do create
}

void InteractiveEntity::Delete(OutTokens& Out)
{
	DoCreate(Out,EntityReqDelete,*this) ;	// Do delete
}

void InteractiveEntity::Display()
{
	OutTokens Out(OutputHelp) ;
	DoCreate(Out,EntityReqDisplay,*this) ;
}

void InteractiveEntity::Dump(OutTokens& Out,ValueTypeList *Lst)
{
	Out.NextFillOut("Class:");
	Out.NextFillOut(EntityClassName) ;
	// Out.NextFillOut(", Parameters:");
	// Parameters->Dump(Out,Lst) ;
	Out.NextFillOut("ThisValue:") ;
	ThisValue.Dump(Out,Lst) ;
	if (Members) {
		Out.NextFillOut("Members:") ;
		Out.NewLine() ;
		ValueType ** Ptr = Members ;
		while (*Ptr) {
			Out.NextFillOut("Ck");
			Out.NewLine() ;
			(*(Ptr++))->Dump(Out,Lst) ;
		}
	}
	Out.NewLine() ;
}

void UserBasicObjects::Dump(OutTokens& Out,ValueTypeList*Lst)
{
	if (!this){ Out.NextOut("Basic Null"); return ; }
	if (Type > DecEnt) {Out.NextOut("Bad Type") ;return ; }
	Out.NextFillOut("Type:");
	Out.NextFillOut(TypeName) ;
	Out.NextFillOut(DecTypeToString(Type)) ;
	Out.NextFillOut("ThisType =");
	ThisType.Dump(Out,Lst) ;
}

int SimpleUserObjectList::CppList(OutTokens& Out)
{
	SimpleUserObjectIterator Next(*this) ;
	int OK =1 ;
	SimpleUserObject * Obj ;
	while (Obj = Next()) {
		int Error = Obj->CppList(Out) ;
		OK&=Error ;
	}
	return OK ;
}

void SimpleUserObjectList::Describe(OutTokens& Out,ListEntity Opt)
{
	SimpleUserObjectIterator Next(*this) ;
	SimpleUserObject * Obj ;
	while (Obj = Next()) Obj->Describe(Out,Opt) ;
}

int SimpleUserObject::Remove()
{
	return AllEntityLists->RemoveSimpleUserObject(this);
}

void SimpleUserObject::Delete()
{
	// LogOut << "SimpleUserObject::Delete\n" ;
	// LogOut << "Deleting :" << GetName() << "\n" ;
	// remove from list
	if (!Remove()) DbgError("SimpleUserObject::Delete","can't remove");
	delete Array;
	Array = 0 ;
	// delete this ;
	// DbgError("SimpleUserObject::Delete","not in yet");
}


int32 SimpleUserObject::GetArraySize()
{
	if (!Array) DbgError("SimpleUserObject::GetArraySize","not array");
	return Array->GetArraySize();
}

ArrayData * SimpleUserObject::GetArray()
{
	return Array;
}


void SimpleUserObject::SetArray(ArrayData * array)
{
	Array = array ;
}

ValueType * InteractiveEntity::GetMember(const char * FunctionName)
{
	if (Members) for (ValueType ** AMember = Members; *AMember; AMember++) {
		if ((*AMember)->Type == DecProcedure) {
			// must add tests for other types of members
			// as they are introduced
			Procedure * AProc = (*AMember)->Value.ValProcedure;
/*
 *			LogOut << "Checking procedure `" << AProc->GetName()
 *				<< "'.\n" ;
 */
			if (!strcmp(AProc->GetName(),FunctionName))
				return *AMember ;
		}
	}
	return 0;
}

Procedure * InteractiveEntity::GetMemberProcedure(const char * Name)
{
	// LogOut << "GetMemberProcedure(" << Name << ")\n" ;
	InteractiveEntity * TheEntity = this ;
	while (TheEntity) {
		ValueType * Member = TheEntity->GetMember(Name);
		if (Member) if (Member->Type == DecProcedure) {
			Procedure * AProc = Member->Value.ValProcedure;
			return AProc ;
		} else return 0;
		TheEntity = TheEntity->GetBaseEntity();
/*
 *		if (TheEntity)
 *			LogOut << "Checking class `" <<
 *				TheEntity->GetClassName() << "'.\n" ;
 */
	}
	return 0;
}
	
int InteractiveEntity::IsClassMember(const char * ClassName)
{
/*
 *	LogOut << "IsClassMember - " << ClassName << " :: " <<
 *		EntityClassName << "\n" ;
 */
	if (!strcmp(ClassName,EntityClassName)) return 1 ;
	if (BaseEntity) return BaseEntity->IsClassMember(ClassName);
	return 0 ;
}

