/*  yacintfc.c   */
/*  Copyright 1989 Mountain Math Software  */
/*  All Rights Reserved                    */
#include <stdlib.h>
#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 "intfccomd.h"
#include "dsp.h"
#include "mkstr.h"
#include "outtokf.h"
#include "ObjProGui/remcom.h"

CommandState State ;

const int CommandState::warn_limit = 4 ;

CommandState::CommandState ():
	X_windows(0),
	VersionsSaved(4),
	the_log_file(0),
	Exiting(0),
	warn_count(0),
	InNetEdit(0)
{
	StateSavedFlag = 1;
	ExitCommandFlag=1;
	SemanticErrorFlag= 0;
	Period = 20;
	CountForPeriod = 0;
	InParse = 0 ;
	InParseStart = 0 ;
	InParseWaitRead = 0 ;
	OverwriteFlag = 0;
	Interactive = 0 ;
	SaveFileName = "dsppp" ;
	TheFile = 0 ;
	TheOverflowAction = OverflowAbort ;
}

void CommandState::SavePeriod()
{
	*Output + OutputPrompt <<
	"The save period is the number of actions between automatic state\n";
	*Output << "saving. With a period of zero the state is not saved automatically.\n";
	*Output << "The current state saving peirod is " << Period <<".\n" ;
	int32 temp ;
	int flag = GetIntValue("new state saving period",temp,InputPrompt) ;
	if (flag <= 0) return ;
	if (temp > 16383) temp = 16383 ;
	Period = temp ;
}


void CommandState::DisplaySaveFileName(OutputType Type, const char * nm)
{
	const char * name = nm ;
	if (!name) name = GetFileName();
	if (is_version_name(name)) {
		*Output + Type << "DSP++ objects are saved to file `"
			<< GetFileName() << "'.\n" ;
		*Output << "The " << GetVersions() <<
			" latest versions are retained.\n" ;
		return ;
	}
	if (!nm) {
		*Output + Type << "The current save file name is `" << GetFileName()
			<<"'.\n" ;
	*Output << "This contains a `.' and is not a legal version name.\n" ;
	*Output <<"Files will be save to a machine generated name of the form `"
		<< "stat.XXXXX'.\n" ;
		return ;
	}
	*Output + Type << "`" << name <<
		"' contains a `.' and is not a legal version name.\n" ;
}

void CommandState::SetSaveFileName()
{
	DisplaySaveFileName(OutputPrompt);
	const char * Temp ;
	for (;;) {
		if (GetStringValue("new file name", &Temp,InputPrompt)) {
			if (Temp[0] == '\03') return ;
			if (!is_version_name(Temp)) {
				DisplaySaveFileName(OutputPrompt,Temp);
				continue ;
			}
			SetFileName(Temp);
			break ;
		}
		return ;
	}
	int32 Number ;
	int flag = GetIntValue("new number (up to 10) of versions to keep",Number,
        InputPrompt);
	if (flag <= 0) return ;
	if (Number > 0) {
		if (Number > 10) Number = 10 ;
		VersionsSaved = Number ;
	}
		
}

void CommandState::ListMachWord()
{
	AllEntityLists->CppList("MachWord");
}

void CommandState::ListAccMachWord()
{
	AllEntityLists->CppList("AccMachWord");
}

void CommandState::ListCxMachWord()
{
	AllEntityLists->CppList("CxMachWord");
}

void CommandState::ListCxAccMachWord()
{
	AllEntityLists->CppList("CxAccMachWord");
}


void CommandState::ListInt()
{
	AllEntityLists->CppList("int");
}

void CommandState::ListDouble()
{
	AllEntityLists->CppList("double");
}

void CommandState::ListComplex()
{
	AllEntityLists->CppList("complex");
}

void CommandState::ListObject()
{
	AllEntityLists->EntityList(ListSingleEntity);
}

void CommandState::ListObjects()
{
	AllEntityLists->EntityList(ListEntityMembers);
}

void CommandState::ListClasses()
{
	AllEntityLists->EntityList(ListEntityClasses);
}

void CommandState::ListBaseClasses()
{
	AllEntityLists->EntityList(ListGlobalClasses);
}


void CommandState::Aborting()
{
	if (IsVerbose()) *Output + OutputCppHelp <<
		"Aborting statement execution.\n";
}

static int EndOfFileCount = 0;
void EndOfFile()
{
	*Output + OutputCppHelp << "End of file on input.\n";
	if (EndOfFileCount++ > 4) exit(4);
	State.Exit() ;
}
	

void CommandState::Exit()
{
	// LogOut << "CommandState::Exit\n" ;
	if (IsStateSaved()) ExitAndCleanUp();
	// LogOut << "CommandState::Exit after ExitAndCleanUp\n" ;
	for (;;) {
		*Output + OutputPrompt <<
			"\nThe current state has not been saved.\n" ;
		*Output << "Enter `exit' to exit without saving.\n" ;
		*Output << "Enter `save' to save state and then exit.\n" ;
		const char * Resp=GetName("`no' to resume execution");
		EndOfFileCount= 0;
		if (!strcmp(Resp,"no")) { delete (char *) Resp; return ; }
		if (!strcmp(Resp,"exit")) ExitAndCleanUp() ;
		if (strcmp(Resp,"save")) { delete (char *) Resp; continue; }
		Save() ;
		ExitAndCleanUp();
	}
}
	

void CommandState::SetInParseStart()
{
	InParseStart = 1;
	InParse = 1 ;
}

void CommandState::SetInParseRead()
{
	if (InParseStart) InParse = 0 ;
	InParseWaitRead = 1 ;
	DspExecState->ActiveParseRead();
}

void CommandState::SetInParse()
{
	InParse = 1;
	InParseStart = 0;
	InParseWaitRead = 0 ;
	DspExecState->ClearActiveParseRead();
}

void CommandState::ClearInParse()
{
	InParseStart = InParse = 0;
}

static void user_abort()
{
	State.Error("State save aborted by user");
}

void CommandState::SaveAs()
{
	const char * file_name = 0 ;
	char * to_del = 0 ;
	OutTokFile * Out = 0 ;
	for (;;) {
		// prompt for input
		delete to_del ;
		to_del = 0 ;
		file_name = GetGraphicsBuf(InputPrompt,
                "Enter file to save state to or RETURN to abort:\n") ;
		if (!*file_name || *file_name == 3) {
			user_abort();
			delete to_del ;
			return ;
		}
		// check if file exists
		FILE * rd = fopen(file_name,"r") ;
		// prompt for overwrite
		if (rd) {
			file_name = to_del = Concatenate(file_name) ;
			// save current name

			fclose(rd);
			for (;;) {
				PromptOut << "`" << file_name << "' exists.\n" ;
				const char * yes_or_no = GetGraphicsBuf(InputPrompt,
					"Enter `overwrite' to overwrite or RETURN to abort:");
				if (!*yes_or_no || *yes_or_no == 3) {
					user_abort();
					delete to_del ;
					return ;
				}
				if (!strcmp("overwrite",yes_or_no)) break ;
			}
		}	
		Out = OutTokFile::open_tok_file(file_name," ",60);
		if (Out) break ;
		ClearError();
		PromptOut << "Cannot create `" << file_name << "'.\n" ;
		char * msg ;
		SystemErrorMessage(1,&msg);
		PromptOut << msg << "\n" ;
	} 
	if (Out) {
		AllEntityLists->save_state_kernel(*Out);
		OutTokFile::delete_tok_file(Out) ;
	} else DbgError("CommandState::SaveAs","null out");
	if (State.IsError()) HelpOut << "State NOT saved" ;
	else {
		 HelpOut << "State saved to `" << file_name << "'.\n" ;
		SetStateSaved() ;
	}
	delete to_del ;
}


void CommandState::Save()
{
	// LogOut << "CommandState::Save\n" ;
	CountForPeriod = 0 ;
	AllEntityLists->SaveState(SaveFileName);
	SetStateSaved() ;
	// LogOut << "CommandState::Save exit\n" ;
}

int CommandState::IsInParseContinue()
{
	return (InParse || InParseWaitRead) && !InParseStart;
}

int CommandState::IsInParseBeginWaitRead()
{
	return (!InParse && InParseWaitRead && InParseStart);
}

void CommandState::Warning(const char * a, const char * b,
	const char * c, const char *  d, const char * e, const char * f,
	const char * g, const char * h)
{
	if (warn_count++ >= warn_limit) return ;
	*Output + OutputCppHelp << "Warning: " << a;
	if (b) *Output << b ;
	if (c) *Output << c ;
	if (d) *Output << d ;
	if (e) *Output << e ;
	if (f) *Output << f ;
	if (g) *Output << g ;
	if (h) *Output << h ;
	if (LineCount > 0) *Output << " at line " << LineCount ;
	*Output << ".\n" ;
}

void CommandState::clear_warn(int list_flag)
{
	if (list_flag) if (warn_count >= warn_limit) {
		int add = warn_count - warn_limit + 1 ;
		*Output + OutputCppHelp <<
			(add == 1 ? "There was " : "There were ")
			<< add <<
			(add == 1 ? " additional warning" : " additional warnings") ;
		if (LineCount > 0) *Output << " at line " << LineCount ;
    	*Output << ".\n" ;
	}
	if (warn_count) if (State.IsVerbose()) *Output + OutputCppHelp <<
"Rerun with trace enabled (select `setup', `debug' and `trace' in the menu\n"
		<<
"data base) to get all warnings and a trace of node execution in log file\n"
		<< "`dsp.messages'.\n" ;
	warn_count = 0 ;
}

void CommandState::Error(const char * a, const char * b ,
	const char * c, const char *  d, const char * e, const char * f,
	const char * g, const char * h)
{
	SetError();
	*Output + OutputCppHelp << "Error: " << a;
	if (b) *Output << b ;
	if (c) *Output << c ;
	if (d) *Output << d ;
	if (e) *Output << e ;
	if (f) *Output << f ;
	if (g) *Output << g ;
	if (h) *Output << h ;
	if (LineCount > 0) *Output << " at line " << LineCount ;
	*Output << ".\n" ;
/*
 *	LogOut << "Error: " << a;
 *	if (b) LogOut << b ;
 *	if (c) LogOut << c ;
 *	if (d) LogOut << d ;
 *	if (e) LogOut << e ;
 *	if (f) LogOut << f ;
 *	if (g) LogOut << g ;
 *	if (h) LogOut << h ;
 *	LogOut << ".\n" ;
 */
}

void CommandState::DoingThis(const char * a, const char * b,
	const char * c, const char *  d)
{
/*
 *	if (a) LogOut << a;
 *	if (b) LogOut << b ;
 *	if (c) LogOut << c ;
 *	if (d) LogOut << d ;
 *	LogOut << "\n" ;
 */

	ClearStateSaved() ;
	if (IsInteractive()) {
		if (Period) CountForPeriod++;
		if (CountForPeriod >= Period) {
			// LogOut << "Saving\n" ;
			Save();
			// LogOut << "Saved\n" ;
		}
	}
	if (!a) return ;
	if (IsVerbose()) {
		const char * last = a ;
		*Output +OutputCppHelp << a;
		if (b) {*Output << b ; last = b ;}
		if (c) {*Output << c ; last = c ;}
		if (d) {*Output << d ; last = d ;}
		if (*(last + strlen(last) -1) != '.') *Output << "." ;
		*Output << "\n" ;
	}
}

void CommandState::ReadFile(const char * Name, int overwrite_flag,int return_id)
{
/*
 *	LogOut << "ReadFile(\"" <<  Name << "\", " << overwrite_flag <<
 *		", " << return_id << ")\n" ;
 */
	if (!IsInParseBeginWaitRead()) {
		InterfaceControl.SendReturnPacket(return_id,ParseReadFileReturn,
			ParseFileBadState);
		// LogOut << "ReadFile return - bad state\n" ;
		return ;
	}	
	if (Name) if (*Name) {
		const char * orig_name = Name ;
		PreviousErrorFlag = 0;
		LineCount = 0 ;
		char * delete_name = 0 ;
		for (;;) {
			char * prev_delete_name = delete_name ;
			TheFile = fopen(Name,"r");
			if (TheFile) break ;
			if (Name = delete_name = top_version_name(Name)) continue ;
			*Output + OutputCppHelp << "Cannot open file `" <<
				orig_name ;
			if (prev_delete_name) *Output << "' or version file `" <<
				prev_delete_name ;
			*Output << "'.\n" ;
			InterfaceControl.SendReturnPacket(
				return_id,ParseReadFileReturn,ParseFileBadRead);
			delete delete_name ;
			delete_name = 0 ;
			return;
		}
		delete delete_name ;
		delete_name = 0 ;
		if (overwrite_flag) SetOverwrite() ;
		ClearInteractive();
		InterfaceControl.SendReturnPacketSaveId(return_id,
			ParseReadFileReturn, ParseFileOpened);
		ReturnId = return_id ;
		return ;
	}
	DbgError("CommandState::ReadFile","bad file name");
}

const char * CommandState::ReadLocalFile(InputType type)
{
	if (!TheFile) return 0;
	if (type != InputCppEntry) return 0;
	if (IsPreviousError()) {
		InterfaceControl.SendReturnPacket(ReturnId,ParseReadFileReturn,
			-LineCount);
		CloseFile();
		return 0;
	}
	const BufSize = 256;
	static char Buffer1[BufSize];
	const char * Read1 = fgets(Buffer1,BufSize,TheFile);
	if (Read1) {
		// LogOut <<  Buffer1 << "Above is line: " << LineCount << "\n" ;
		LineCount++;
		return Read1 ;
	}
	CloseFile();
	InterfaceControl.SendReturnPacket(ReturnId,ParseReadFileReturn,
		ParseFileOk);
	return ";\n"  ;
}

void CommandState::SaveInit(const char * Name)
{
	if (Name) if (*Name) {
		// LogOut << "SaveFileName is `" << SaveFileName << "'\n" ;
		SaveFileName = strcpy(new char[strlen(Name)+1], Name);
		return ;
	}
	SaveFileName = 0 ;
}

void CommandState::CloseFile()
{
	LineCount = 0 ;
	fclose(TheFile);
	TheFile = 0;
	ClearOverwrite();
	SetInteractive();
}

void ParameterList::Dump(OutTokens& Out, ValueTypeList*)
{
	Out.NextFillOut("ParameterList Dump not in");
}

ParameterList::ParameterList()
{
	Name=0;
}

