/*  remmen.c   */
/*  Copyright 1989 Mountain Math Software  */
/*  All Rights Reserved                    */
#include "portable.h"
#include "remmen.h"
#include "intfc.h"
#include "usercom.h"
#include "outtok.h"
#include "cgidbg.h"
#include "user.h"
#include "yacintfc.h"
#include "mpacket.h"
#include "editnet.h"
#include "shared.h"
#include "remcom.h"
#include "dfnode.h"
#include "buffer.h"
#include "net.h"
#include "tmparth.h"


static InteractiveEntity * GetNodeEntity(const char * NodeName,
	const char * Operation)
{
	InteractiveEntity * TheEntity = TheNodes->Find(NodeName);

	if (!TheEntity) {
		*Output + OutputCppHelp << "There is no DSP node class `"
			<< NodeName << "' in this version of ObjectProDSP with `"
			<< ArithTypeName << "' arithmetic.\n" ;
		*Output << Operation << " operation aborted.\n" ;
		// LogOut << "GetNodeEntity exiting (no entity) for " <<
		//	Operation << "\n" ;
		return  0;
	}
	return TheEntity ;
}

static void CreateNodeInteractiveEntityBase(const char * EntityNode,
int default_flag)
{
/*
 *	LogOut << "CreateNodeInteractiveEntityBase(" << EntityNode <<
 *		", " << default_flag << ")\n" ;
 */
	InteractiveEntity * TheEntity = GetNodeEntity(EntityNode,"Create");
	if (!TheEntity) return ;
	OutTokens Out(OutputPrompt,0,""," ","",78);
	UserEntity * ent =  0;
	if (default_flag) ent = TheEntity->InteractiveCreateDefault(Out);
	else ent = TheEntity->InteractiveCreate(Out);
	int error = State.IsError();
	State.ClearError();
	if (!ent) return ;
	if (error) return ;
	if (TheEntity->IsClassMember("Network")) {
		((Network *)ent)->GraphDisplay();
		return ;
	}
	if (!TheEntity->IsClassMember("Node")) {
		// LogOut << "Checking if " << ent->GetName() << " is a BufferDescript\n" ;
		if (TheEntity->IsClassMember("BufferDescript")) {
			// LogOut << "Found it\n" ;
			BufferDescript * bd = (BufferDescript *) ent ;
			bd->assign_to_net_graph();
		}
		// else LogOut << "It is not\n" ;
		return ;
	}
	DfNode *nod = (DfNode*) ent ;
	nod->add_to_net_graph();
}

void CreateNodeInteractiveEntity(const char * EntityNode)
{
	State.DoingThis(0);
	 CreateNodeInteractiveEntityBase(EntityNode,0);
}

void CreateDefaultNodeInteractiveEntity(const char * EntityNode)
{
	State.DoingThis(0);
	CreateNodeInteractiveEntityBase(EntityNode,1);
}

void DeleteNodeInteractiveEntity(const char * EntityNode,
	const char * NodeName)
{
	// LogMsg("DeleteNodeInteractiveEntity:",EntityNode);
	InteractiveEntity * TheEntity = GetNodeEntity(EntityNode,"Delete");
	if (!TheEntity) return ;
	UserEntity * AnEntity = TheEntity->GetObject(NodeName);
	if (!AnEntity) {
		*Output + OutputCppHelp << "There is no object `" << NodeName <<
			"' in class `" << EntityNode << "' to delete.\n" ;
		return ;
	}
	if (!AnEntity->CheckSafeDelete()) {
		*Output + OutputCppHelp << "Object `" << NodeName <<
			"' may be in use or be an initial default value.\n"  <<
			"It cannot be deleted.\n" ;

		return ;
	}
/*
 *	LogOut << "DeleteNodeInteractiveEntity: about to delete - " <<
 *		AnEntity->GetName() << "\n" ;
 */
	delete AnEntity ;
	State.ClearError();
}

UserEntity * GetObjectInstance(InteractiveEntity * TheEntity,
	const char * InstanceName)
{
	UserEntity * Instance ;
	EntityListIterator Next(*(TheEntity->GetInstances()));
	while (Instance = Next()) if (!strcmp(Instance->GetName(),InstanceName))
		return Instance ;

	*Output + OutputCppHelp << "There is no object `" << InstanceName
		<< "' in the object class `" <<
		TheEntity->GetClassName() << "'\n" ;
	return 0;
}


Procedure * GetMemberFunction(InteractiveEntity * TheEntity,
	const char * FunctionName)
{
	Procedure * Member = TheEntity->GetMemberProcedure(FunctionName);
/*
 *	for (ValueType ** AMember = Members; *AMember; AMember++) {
 *		if ((*AMember)->Type == DecProcedure) {
 *			Procedure * AProc = (*AMember)->Value.ValProcedure;
 *			if (!strcmp(AProc->GetName(),FunctionName))
 *				return AProc;
 *		}
 *	}
 */
	if (!Member) *Output + OutputCppHelp << "Object `" <<
		TheEntity->GetClassName() <<
		"' does not have a member function\n`" <<
		FunctionName << "'.\n" ;
	return Member ;
}

static void ExecuteInteractiveMemberFunction(InteractiveEntity * TheEntity,
	const char * NodeName, const char * ParameterSetFunction)
{
	// LogOut << "ExecuteInteractiveMemberFunction\n" ;
	if (!TheEntity) return ;
	EntityList * Instances = TheEntity->GetInstances();
	EntityListIterator Next(*Instances);

	UserEntity * Instance = GetObjectInstance(TheEntity,NodeName);
	if (!Instance) return ;

	Procedure * AProc = GetMemberFunction(TheEntity, ParameterSetFunction);
	if (!AProc) return ;
	UserParameters * Parameters = AProc->GetParameters() ;
	OneParameter * Params = Parameters->GetAllParameters();
	// Parameters->GetDefaultParameters(Instance,0);
	for (int i = 0;Params[i].Name;i++) {
		// LogOut << "getting parameter " << i << "\n" ;
		if (!Params[i].GetParameter(i,0,0,Instance)) return ;
	}

	OutTokens Out(OutputCppHelp,0,""," ","",78);
	AProc->DoCall(Out,EntityReqCall,Instance);
	State.ClearError();
}

void DescribeParam(const char * NodeName, const char * ParameterName)
{
	InteractiveEntity * TheEntity = GetNodeEntity(NodeName,
		"Describe parameter");
	if (!TheEntity) return ;
	OneParameter * TheParameter =
		TheEntity->GetOneParameter(ParameterName);
	OutTokens Out(OutputHelp,0,""," ","",78);
	TheParameter->List(Out,TheEntity->ListSize()) ;
}

static void DescribeInteractiveNode(EntityList * NodeList,
	const char * NodeName)
{
	// LogMsg("DescribeInteractiveNode, node name:", NodeName);
	EntityListIterator Next(*NodeList) ;
	UserEntity * Ent ; 
	OutTokens Out(OutputHelp,0,""," ","",78);
	while(Ent = Next()) if (!strcmp(Ent->GetName(),NodeName)) {
		// LogMsg("Describing single entity");
		Out.NextFillOut("The following description is for object");
		Out.NextQuoteOut(NodeName);
		Out.NextConcat(".");
		Out.NewLine();
		Ent->Describe(Out,ListSingleEntity);
		return ;
	}
	*Output + OutputCppHelp << "Node `" << NodeName << "' not found.\n" ;
}

void DescribeNodeInstance(const char * NodeClass, const char *NodeName)
{
	InteractiveEntity * Ent = GetNodeEntity(NodeClass, "Describe instance");
	if (Ent) DescribeInteractiveNode(Ent->GetInstances(), NodeName);
}

static void DescribeInteractiveNodeParameterInstance(
	InteractiveEntity * TheEntity,
	const char * Data, const char * ParamName)
{
	// LogMsg("DescribeInteractiveNodeParameter, node name, ParamName:",
	//	Data,ParamName);


	OutTokens Out(OutputHelp,0,""," ","",78);
	Out.NextFillOut("The following parameter description is for");
	Out.NextQuoteOut(TheEntity->GetClassName());
	Out.NextFillOut("object");
	Out.NextQuoteOut(Data);
	Out.NextConcat(".");
	Out.NewLine();
	EntityList * NodeList = TheEntity->GetInstances();
	EntityListIterator Next(*NodeList) ;
	UserEntity * Ent ; 
	while(Ent = Next()) if (!strcmp(Ent->GetName(),Data)) {
		// LogMsg("Setting Entity parameters");
		Ent->Describe(Out,ListSetParameterValues);
		// Out is not used in above call
		break ;
	}
	if (!Ent) {
		*Output + OutputCppHelp << "Node `" << Data << "' not found.\n" ;
		return ;
	}

	OneParameter * TheParameter =
		TheEntity->GetOneParameter(ParamName);
	if (!TheParameter) {
		*Output + OutputCppHelp << "Parameter " <<
			ParamName << " of node " << Data << "not found.\n" ;
		return ;
	}
	TheParameter->ListValue(Out) ;
}

void DescribeGenericInteractiveEntity(class InteractiveEntity * Ent)
{
	OutTokens Out(OutputHelp,0,""," ","",78);
	Ent->DoRequest(Out,EntityReqDescribeFull);
}

void NodeDescribe(const char * TheNode)
{
	InteractiveEntity * Ent = GetNodeEntity(TheNode, "Describe node");
	if (Ent) DescribeGenericInteractiveEntity(Ent);
}

void DescribeParamInstance(const char * NodeClass, const char * NodeInstance,
	const char * Param)
{
	InteractiveEntity * Ent = GetNodeEntity(NodeClass,
		"Describe parameter instance");
	if (Ent) DescribeInteractiveNodeParameterInstance(Ent,NodeInstance,
		Param);

}

void ExecuteSetParameter(const char * ClassName, const char * ObjectName,
	const char * FunctionName)
{
	InteractiveEntity * Ent = GetNodeEntity(ClassName,
		"Set parameter");

	if (Ent) {
		char * Buf = new char[strlen(FunctionName)+4];
		strcpy(Buf,"Set");
		strcat(Buf,FunctionName);

		ExecuteInteractiveMemberFunction(Ent,ObjectName,Buf);
		State.ClearError();
		delete Buf ;
	}
}
static const char * StripTrailingName(const char * Base)
{
	// strip off everything in front of last blank character
	for (const char * ExecName = Base + strlen(Base) - 1;
		ExecName >= Base; ExecName--) if (*ExecName == ' ')
		return ExecName+1 ;
	return Base ;
}


void ExecuteMemberFunction(const char * ClassName, const char * ObjectName,
	const char * FunctionName)
{
	FunctionName = StripTrailingName(FunctionName);
	ObjectName = StripTrailingName(ObjectName);
	InteractiveEntity * Ent = GetNodeEntity(ClassName,
		"Execute member function");
	if (!Ent) return ;
	ExecuteInteractiveMemberFunction(Ent,ObjectName,FunctionName);
	State.ClearError();
}



void MemberFunctionDescribe(const char * ClassName, const char * MemberName)
{
	MemberName = StripTrailingName(MemberName);
	InteractiveEntity * TheEntity = GetNodeEntity(ClassName,
		"Describe member function");
	if (!TheEntity) return ;

	Procedure * AProc = GetMemberFunction(TheEntity, MemberName);
	if (!AProc) return ;
	OutTokens Out(OutputHelp,0,""," ","",78);
	AProc->DoCall(Out,EntityReqDescribeFull,0);
}


void DescribeMemberFunctionParameter(const char * ClassName,
	const char * MemberName, const char * Parameter)
{
	MemberName = StripTrailingName(MemberName);
	Parameter = StripTrailingName(Parameter);
	InteractiveEntity * TheEntity = GetNodeEntity(ClassName,
		"Describe member function parameter");
	if (!TheEntity) return ;

	Procedure * AProc = GetMemberFunction(TheEntity, MemberName);
	if (!AProc) return ;

	UserParameters * Parameters = AProc->GetParameters() ;
	OneParameter * Params = Parameters->GetAllParameters();
 	for (int i = 0;Params[i].Name;i++)
		if (!strcmp(Params[i].Name,Parameter)) {

		OutTokens Out(OutputHelp,0,""," ","",78);
		Params[i].List(Out,TheEntity->ListSize()) ;
		return ;
	}
	
	*Output + OutputHelp << "There is no parameter `" << Parameter <<
		"' in member function\n`" << MemberName << "' of object `"
		<< ClassName << "'.\n" ;
}



