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

#include "outtok.h"
#include "usercom.h"
#include "portable.h"

// #include "menu.h"

#include "yacintfc.h"
/* #include "y.tab.h"  included in lexhead.h */
#include "lexhead.h"
#include "baseio.h"
#include "intfc.h"
#include "user.h"
#include "cgidbg.h"
#include "typemap.h"
#include "mkstr.h"

void NetEditCommand()
{
	State.SetNetEdit();
}
struct ValueType * InsureValueExists(struct ValueType* Op)
{
	if (NoExecute()) return 0 ;
	if (!Op->CheckValueDefined()) {
		State.Error("reference to undefined variable");
		return 0;
	}
	ValueType * Ret = new ValueType(Op);
	// Make copy so we don't change current value
	return Ret ;
}

struct ValueType * DoDeclare(struct ValueType* Name) 
{
	if (NoExecute()) return 0 ;
	ValueType * RetVal = DoDeclareLval(Name) ;
	if (!RetVal) return 0 ;
	if (!RetVal->CheckValueDefined()) {
		State.Error("reference to undefined value");
		return 0;
	}
	return new ValueType(RetVal) ;
	// must retrun copy -- not the actual value
	// just as CheckDeclared does
}


struct ValueType * DoDeclareLval(struct ValueType* Name) 
{
	if (NoExecute()) return 0 ;
	for (;;) {
		OutputType channel = OutputPrompt ;
		if (State.IsInteractive()) channel = OutputCppHelp ;
		*Output + channel << "`" << Name->Value.ValName <<
			"' is not declared.\n" ;
		const char * TheType = CondGetName(
			"type to declare it or RETURN",
			"reference to undeclared variable");
		if (!TheType) return 0;
		ValueType * RetVal = CheckDeclarator(TheType) ;
		if (RetVal) {
			RetVal = Declare(RetVal,Name);
			if (!RetVal) DbgError("DoDeclare","Declare error");
			delete (char *) TheType ;
			return RetVal ;
		}
		*Output + channel <<  "`" << TheType <<
			"' is not a valid type.\n" ; 
		delete (char *) TheType ;
	}
}


static void ParamError(const char * msg)
{
	DbgError("ParameterList Routines",msg);
}

struct ValueType *DoParameterList(struct ValueType* List,struct ValueType* Next)
{
	if (NoExecute()) return 0 ;
	if (!List) ParamError("Null list");
	if (!List->Type == DecParam) ParamError("Bad type");
	if (!List->Value.ValParam) ParamError("Null list of list");
	if (!Next) ParamError("Null next");
/*
 *	LogOut <<"DoParameterList:: Appending " << dec(Next->Value.ValInt) <<
 *		".\nBefore append list is:" ;
 *	ParameterListIterator ext(*(List->Value.ValParam)) ;
 *	ValueType * Temp ;
 *	while (Temp = ext()) LogOut << dec(Temp->Value.ValInt) << ".\n" ;
 */
	List->Value.ValParam->Append(Next) ;
	return List ; 
}

struct ValueType * DoParameter(struct ValueType* Expression)
{
	if (NoExecute()) return 0 ;
	if (!Expression) ParamError("Null Expression");
	ParameterList * List = new ParameterList() ;
	List->Append(Expression) ;
	ValueType * RetVal = new ValueType(DecParam,List);
	return RetVal ;
}

struct ValueType * CheckLegal(struct ValueType* Name)
{
	if (NoExecute()) return 0 ;
	if (Name->Type != DecName) DbgError("CheckLegal","not a name");
	const char * TheName = Name->Value.ValName ;
	while (CheckReserved(TheName)) {
		OutputType channel = OutputPrompt ;
        if (State.IsInteractive()) channel = OutputCppHelp ;
		*Output + channel << "`" << TheName <<
			"' is a C++ reserved word.\n";
		delete Name ;
		Name = 0 ;
		delete (char *) TheName ;
		TheName = CondGetName("a new name or RETURN", "Illegal name");
		if (!TheName) return 0;
	}
	if (!Name) return MakeStringValue(TheName) ;
	return Name ;
}

struct ValueType * DoProcedure(struct ValueType*Proc,struct ValueType*Param)
{
	if (NoExecute()) return 0 ;
	if (!Proc || !Param) DbgError("DoProcedure","Null parameter");
	if (Param->Type!=DecParam)DbgError("DoProcedure","parmeters invalid");
	for (;;) {
		const char * ProcName = 0;
		if (Proc) if (Proc->Type == DecProcedure) break ;
		// LogOut << "In DoProcedure\n" ;
		OutputType channel = OutputPrompt ;
        if (State.IsInteractive()) channel = OutputCppHelp ;
		*Output + channel << "`" << NameOfObj(Proc)
			<< "' is not a procedure.\n";
		ProcName = CondGetName( "a procedure name or RETURN",
			"invalid procedure");
		if (!ProcName) return 0 ;
		Proc = CheckDeclared(ProcName) ;
	}
	Procedure * TheProc = Proc->Value.ValProcedure ;
	UserParameters * TheParams = TheProc->GetParameters() ;
	// LogOut << "In DoProcedure 2\n" ;
	Param->Value.ValParam->SetName(NameOfObj(Proc)) ;
	if (State.IsError()) return 0;
	TheParams->SetValues(Param) ;
	if (State.IsError()) return 0;
	// LogOut << "DoProcedure, Proc->Declared.Entity = 0x" <<
	//	hex((int)Proc->Declared.Entity) << "\n" ;
	State.DoingThis("Calling procedure ",TheProc->GetName());
/*
 *	LogForm("TheProc = 0x%x", (long) TheProc);
 *	LogForm("Proc = 0x%x", (long) Proc);
 *	LogForm("TheProc->Call = 0x%x, Proc->Declared.Entity = 0x%x",
 *		(long) TheProc->GetCall(), (long) Proc->Declared.Entity); 
 */
	OutTokens Dummy(OutputCppHelp) ;
	return MakeReturnValue(
		TheProc->DoCall(Dummy,EntityReqCall,Proc->Declared.Entity),
		TheProc->GetTypeName());
}

struct ValueType * MemberRef(struct ValueType* Obj, struct ValueType* Member)
{
	if (NoExecute()) return 0 ;
	if (!Obj || !Member) DbgError("MemberRef","NULL pointer");
	for (;;)  { 	// Make sure Obj is a class
		OutputType channel = OutputPrompt ;
        if (State.IsInteractive()) channel = OutputCppHelp ;
		const char * name = 0;
		if (!Obj) *Output + channel <<  "`" << name <<
			"' is not declared.\n" ;
		else if (Obj->Type != DecEnt) {
			// LogOut << "In MemberRef\n" ;
			*Output + channel << NameOfObj(Obj) <<
			" is not declared as a class object.\n" ;
		} else break ;
		delete Obj ;
		name = CondGetName("a new name or RETURN",
			"member reference to non class object");
		if (!name) return 0;
		Obj = CheckLegal(MakeStringValue(name)) ;
	}
	ValueType * Declarator = AllEntityLists->GetType(NameOfObj(Obj)) ;
	if (!Declarator) DbgError("MemberRef","Can't get declarator");
	if (Declarator->Class != DoDeclEntity)
		DbgError("MemeberRef","bad Obj class");
	InteractiveEntity * ThisClass = Declarator->Declared.EntityClass;
	if (Member->Type != DecName) DbgError("MemberRef",
		"Member not a name" );
/*
 *	if (!ThisClass->GetMembers()) {
 *		State.Error("class ",ThisClass->GetClassName(),
 *			" has no members");
 *		delete Member ;
 *		return 0;
 *	}
 */
	ValueType ** TheMembers ;
	for (;;) {	// Make sure Member is a member of Obj
		InteractiveEntity * BaseClass = ThisClass ;
		while (BaseClass) {
			TheMembers = BaseClass->GetMembers() ;
			if (TheMembers) {
				while (*TheMembers) {
					if (!strcmp(Member->Value.ValName,
						NameOfObj(*TheMembers))) break ;
					else TheMembers++ ;
				}
				if (*TheMembers) break ;
			}
			BaseClass = BaseClass->GetBaseEntity();
		}
		if (!BaseClass) {
			OutputType channel = OutputPrompt ;
        	if (State.IsInteractive()) channel = OutputCppHelp ;
			*Output + channel << "`" << Member->Value.ValName << 
			"' is not a member of `" << ThisClass->GetClassName()
			<< "'." ;
			*Output + channel << " The members are:\n" ;
			OutTokens Out(channel) ; 
			BaseClass = ThisClass ;
			const char * Prefix = 0 ;
			int First = 1 ;
			while (BaseClass) {
				TheMembers = BaseClass->GetMembers() ;
				if (TheMembers) while (*TheMembers) {
					if (!First) {
						Out.NextConcat(",");
						Out.NextWrite(" ");
					}
					if (Prefix) {
						Out.NextFillOut(Prefix);
						Out.NextWrite("::");
					}
					Out.NextWrite(NameOfObj(
						*(TheMembers++)));
					First = 0 ;
				}
				BaseClass = BaseClass->GetBaseEntity();
				if (!BaseClass) break ;
				Prefix = BaseClass->GetClassName();
			}
			if (TheMembers) Out.NewLine();
			const char * NewName = CondGetName(
				"a valid member name or RETURN", "`",
				Member->Value.ValName, "' is not a member of `",
				ThisClass->GetClassName(),"'");
			if (!NewName) return 0;
			delete Member ;
			Member = CheckLegal(MakeStringValue(NewName)) ;
		} else break ;
	}
/*
 *	LogOut << "MemberRef, Obj->Value.ValEnt = 0x" <<
 *		hex((int) Obj->Value.ValEnt)  << "\n" ;
 */
	ValueType * RetVal = new ValueType(DecProcedure,
		(*TheMembers)->Value.ValProcedure,DeclEntity,
		Obj->Value.ValEnt);
	// return in RetVal:
        // Type			Value        Class	Declared
        // DecProcedure		->Procedure  DeclEntity ->Object procedure is
        //					a member of
	delete Obj ;
	delete Member ;
	return RetVal ;
}

struct ValueType * NameOfList(struct ValueType* Name,
	struct ValueType* List)
{
	// LogOut << "NameOfList\n" ;
	// Attach object name to parameter list
	// We cannot do anything else yet since we don't know what
	// the object is being declared as
	if (NoExecute()) return 0 ;
	if (!Name || !List) DbgError("NameOfList","Null ptr");
	if (Name->Type != DecName || List->Type != DecParam)
		DbgError("NameOfList","Bad type");
	// List->Value.ValParam->SetName(Concatenate(Name->Value.ValName)) ;
	List->Value.ValParam->SetName(Name->Value.ValName) ;
	delete Name ;
	return List ;
}


const char * CondGetName(const char * Prompt, const char * IfError,
	const char * Err1, const char * Err2, const char *Err3,
	const char * Err4, const char * Err5)
{
	const char * Ret =  0;
	if (State.IsInteractive()) Ret = GetName(Prompt);
	if (Ret) if (*Ret) if (*Ret != '\003') return Ret ;
	delete (char *) Ret ;
	State.Error(IfError,Err1,Err2,Err3,Err4,Err5);
	return 0 ;
}

const char * CondGetRawBufLine(const char * Prompt, const char * IfError,
	const char * Err1, const char * Err2)
{
	const char * Ret =  0;
	if (State.IsInteractive()) {
		if (Prompt) *Output + OutputPrompt << Prompt ; 
		Ret = GetRawBufLine(InputPrompt);
		if (Ret[0] == '\03') {
			State.Error("user aborted input");
			State.Error(IfError,Err1,Err2);
			return 0 ;
		}
	}
	if (Ret) if (*Ret) return Ret ;
	State.Error(IfError,Err1,Err2);
	return 0 ;
}

