/*  xgui.C   */
/*  Copyright 1989 Mountain Math Software  */
/*  All Rights Reserved					*/
#include "ObjProGen/cpyrght_exe.h"
#include <Dispatch/dispatcher.h>
#include <ObjProDSP/version.h>
#include <Dispatch/iohandler.h>
#include <errno.h>
#include <signal.h>
#include <stream.h>
#include <fstream.h>
#include <string.h>
#include <ctype.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <InterViews/session.h>
#include <InterViews/cursor.h>
#include <X11/cursorfont.h>
#include "shared.h"
#include "xdrv.h"
#include <InterViews/leave-scope.h>
#include <Dispatch/leave-scope.h>
#include "helpwin.h"
#include "ObjProDSP/arthtyp.h"

#include "menu.h"
#include "slist.h"
#include "dsp_app.h"


// #include "getopt.h"
#include "sysintfc.h"
#include "debug.h"
#include "mpacket.h"

// #include "maninit.h"
// #include "winmgr.h"
#include "plotdatg.h"
// #include "guimouse.h"
#include "remcom.h"
#include "grphio.h"
#include "dogrpmen.h"

#include "usrprompt.h"
// #include "prognm.h"

// #include "textwin.h" 
	/* for degugging only */

#include <stdio.h>
#include "dynmnu.h"
#include "help.h"
#include "dyntextg.h"
#include "intfccomg.h"
#include "guistate.h"
#include "lcrmexe.h"
#include "txtfls.h"
// #include "winpres.h"
#include "mkstr.h"
#include "xgui.h"
#include "cgidbg.h"
#include "playback.h"

DspProcessState * DspState = 0;
void LocalCommCleanUp() ;

const char * DebugOutFile = "cgi.messages";

SharedSegment * ReadSeg ;
SharedSegment * WriteSeg ;
static RootMenuView * TheWindow ;


static char * ActDefault = ".opdinit" ;


static LockProcessing = 1;
// void TestAlloc(const char *msg);
static void RemoveFiles()
{
	static int FilesRemoved = 0 ;
	// TheLog << "Removing files, FilesRemoved = " << FilesRemoved << "\n" ;
	if (FilesRemoved) return ;
	// LogOut << "deleting text controller\n" ;
	delete DspApplication::dynamic_text_controller();
	// LogOut << "deleting ThePlotsManager\n" ;
	delete ThePlotsManager ;
	FilesRemoved = 1 ;
	// LogOut << "Exit RemoveFiles\n" ;
}

static void FinalCleanUp()
{
	// LogOut << "FinalCleanUp\n" ;
	LocalCommCleanUp() ;
	delete WriteSeg;
	delete ReadSeg;
	/* delete TheWindow ; */
	exit(0);
}

void EndOfFile()
{
   TheLog << "End of file\n";
    DbgError("EndOfFile","called");
}


void ExitCleanUp()
{
	int child_id = DspApplication::child_id() ;
	if (child_id) {
		int did_kill = kill(child_id,SIGTERM);
		if (did_kill) {
			TheLog << "kill of " << child_id << " failed.\n" ;
			if (errno < sys_nerr) TheLog << sys_errlist[errno] ;
			else TheLog << "Unknown error " << errno << "\n" ;
		}
	}
	// else LogOut << "Null child_id, no kill.\n" ;
	RemoveFiles();
	FinalCleanUp();
}
DspProcessState::DspProcessState(int gui, int dsp):
	the_init_action_file(0)
{
	GuiProcessId=gui;
	DspProcessId = dsp;
	ReadingState=ActiveReadRequest = QueuedMenuCommands = 0;
	PreviousBusyState = IsBusy();
}


void DspProcessState::init_action_file(const char * name)
{
	if (name) if (*name) {
		for (const char * pt = name ; *pt ; pt++) 
			if (!isgraph(*pt)) break ;
		if (!*pt) {
			the_init_action_file = name ;
			DspApplication::action_read_on();
			return ;
		}
	}
	the_init_action_file = 0 ;
}

ivCursor * DspProcessState::GetCursorType()
{
	if (!DspApplication::root_window()) return hourglass ;
	if (DspApplication::root_window()->reading_action_file() ||
		DspApplication::waiting_on_dsp()) 
		return new ivCursor(XC_leftbutton);
	if (!IsBusy()) return defaultCursor ;
	if (DspApplication::root_window()->is_frozen()) return new ivCursor(XC_dot);
	return hourglass ;
/*
 *	if (TheWindowsManager) if (TheWindowsManager->IsFrozen()) return
 *		CursorPalmHand ;
 *	return CursorHourGlass ;
 */
}

void DspProcessState::CheckChangeBusy()
{
	// LogOut << "DspProcessState::CheckChangeBusy\n" ;
	int NewBusy = IsBusy();
	// LogOut << "NewBusy = " << NewBusy << ", Prev = " << PreviousBusyState << "\n" ;
	if (NewBusy == PreviousBusyState) return ;
	PreviousBusyState = NewBusy ;
	DspApplication::root_window()->new_cursor();
	if (!NewBusy) DspApplication::check_rebuild();
}

void DspProcessState::MenuCommandSend()
{
	QueuedMenuCommands++;
	CheckChangeBusy();
}

void DspProcessState::ReadStateBusy()
{
	ReadingState=1;
	CheckChangeBusy();
}

void DspProcessState::ClearReadStateBusy()
{
	ReadingState=0;
	CheckChangeBusy();
}

void DspProcessState::ReadRequestActive()
{
	DspApplication::root_window()->read_request_active();
	ActiveReadRequest=1 ;
	CheckChangeBusy();
	if (the_init_action_file) {
		const char * nm = the_init_action_file ;
		the_init_action_file = 0 ;
		int do_playback = 1 ;
		if (!strcmp(nm,ActDefault)) {
			// supress error if we cannot read the default action file
			ifstream file(nm);
    		if (!file.good()) do_playback = 0 ;
		}
		DspApplication::action_read_off();
		if (do_playback)
			ManagedKeyboards::manager()->playback(nm);
	}
	if (the_queued_cpp_lines.Size()) {
		char * to_send = the_queued_cpp_lines.Get();
		write_cpp(to_send) ;
		delete to_send ;
		return ;
	}
}

void DspProcessState::ReadRequestInactive()
{
	ActiveReadRequest=0;
	CheckChangeBusy();
}

void DspProcessState::MenuCommandComplete()
{
	if (QueuedMenuCommands < 1) {
		// LogOut << "DspProcessState:MenuCommandComplete count error\n";
		QueuedMenuCommands = 1 ;
	}
	DspApplication::root_window()->process_help_strings();
	QueuedMenuCommands-- ;
	CheckChangeBusy();
}

static const char * how_to_kill()
{
	return
	"Select `state', `other' and `exit' to exit without saving the state.\n" ;
}

static void info_window(const char * msg, int pause = 4)
{
	const char * msgs[2] ;
	msgs[0] = msg ;
	msgs[1] = 0 ;
	DspApplication::warn_info_window(1.5*4*72.0,72.,msgs);
	for (int i = 0; i< 1000;i++) DspApplication::event_check();
	if (pause) {
		sleep(pause);
		for (int i = 0; i< 1000;i++) DspApplication::event_check();
	}
}

int CheckIfDead(int Killing=0)
{
	if (errno == ESRCH) {
		char * msg = Concatenate(
			"The DSP process appears to be dead.\n",how_to_kill());
		info_window(msg);			
		return 1 ;
	}
	return 0;
}

int DspProcessState::WakenDsp()
{
	return SignalSleep("signaling the DSP process to awake");
}

int DspProcessState::MakeDspSleepForever()
{
	return SignalSleep("signaling the DSP process to sleep");
}

int DspProcessState::SignalSleep(const char * What)
{
	int Return = kill(DspProcessId,SIGUSR2);
	if (Return) {
		if (!CheckIfDead()) {
			char * to_delete = 0 ;
			::info_window(to_delete = TroubleSignaling(What),0) ;
			delete to_delete ;
		}
		return 0 ;
	}
	return 1 ;
}




void DspProcessState::AbortDspExecution()
{
	int DidAbort = 0 ;
	DspApplication::root_window()->thaw();
	// TheWindowsManager->UnfreezeScreen();
	for (int Try =0; Try<3;Try++) {
		ReadSeg->CheckPacketRead();
		ReadSeg->CheckPacketRead();
		if (!IsBusy()) break ;
		int Return = kill(DspProcessId,SIGUSR1);
		if (Return) {
			if (CheckIfDead()) return ;
			TroubleAbort();
			return ;
		}
		DidAbort = 1 ;
		PacketHeader ReturnHead(PacketGraphicsStringSend,InputPrompt,0);
		WriteSeg->WritePacket(ReturnHead);
		// sttampt to clear any outstanding prompt
		ReadSeg->CheckPacketRead();
		if (!IsBusy()) break ;
	}
	if (IsBusy()) {
		char * to_delete = 0 ;
		::info_window(to_delete = Concatenate(
			"There seems to be a problem in aborting DSP execution.\n",
				how_to_kill()));
		delete to_delete ;
	}
	else if (DidAbort) ::info_window("DSP execution aborted.",0);
}


void DspProcessState::KillAndExit()
{
	int Return = kill(DspProcessId,SIGTERM);
	if (Return) {
		if (CheckIfDead(1)) {
			sleep(4);
			ExitCleanUp() ;
		}
		TroubleKill();
	}
	sleep(4);
	Return = kill(DspProcessId,0);
	if (Return == -1 && errno == ESRCH) {
		::info_window("DSP process killed with cleanup.");
		ExitCleanUp();
	}
	Return = kill(DspProcessId,SIGKILL);
	if (Return) {
		TroubleKill();
	}
	sleep(4);
	Return = kill(DspProcessId,0);
	if (Return == -1 && errno == ESRCH) {
		::info_window("DSP aborted with no clean up.");
		ExitCleanUp();
	}
	::info_window("DSP process will not die!") ;
	ExitCleanUp();
}

void DspProcessState::TroubleAbort()
{
	char * to_delete = TroubleSignaling("aborting the DSP process");
	::info_window(to_delete) ;
	delete to_delete ;
}

char * DspProcessState::TroubleSignaling(const char * What)
{
	char * msg = 0 ;
	SystemErrorMessage(0,&msg);
	char * ret = Concatenate("There is a problem in ",What,msg,"\n");
	delete msg ;
	return ret ;
}

void DspProcessState::TroubleKill()
{
	char * to_delete = 0 ;
	::info_window(to_delete = TroubleSignaling("killing the DSP process"));
	delete to_delete ;
	ExitCleanUp();
}

void DspProcessState::write_cpp(const char * temp)
{
	PacketHeader ReturnHead(PacketGraphicsStringSend,
		InputCppEntry,strlen(temp)+1);
	WriteSeg->WritePacket(ReturnHead,temp);
	ReadRequestInactive();
}

void DspProcessState::write_cpp_line(const char * str)
{
	if (ActiveReadRequest) write_cpp(str);
	else the_queued_cpp_lines.Append(Concatenate(str));
}

static void DummyAbortDspAndSaveExit(const char * String,InputType, void *)
{
	if(strcmp(String,"yes")) return ;
	DspState->AbortAndSaveExit();
}

void DspProcessState::AbortAndSaveExit()
{
	AbortDspExecution();
	if (!IsBusy()) DoSaveExit();
}

static const char * ExecutingPrmpt =
"The DSP process is executing\nType `yes' to abort or RETURN to cancel request:\n";

void DspProcessState::DoSaveExit()
{
	DspApplication::root_window()->thaw();
	// TheWindowsManager->UnfreezeScreen();
	for(int Try = 0;1;Try++) {
		if (!IsBusy()) {
			DoSaveExit_Rem_Call_Struct.Execute();
			SharedMemoryExitState = 1 ;
			return ;
		}
		if (Try) {
			UserPrompt * ThePrompt = new UserPrompt(ExecutingPrmpt,
			DummyAbortDspAndSaveExit,0,1,0);
			DspApplication::root_window()->InputPost(ThePrompt,"exiting DSP++");
			return ;
		}
		ReadSeg->CheckPacketRead();
		sleep(2);
		ReadSeg->CheckPacketRead();
	}
}

static int DummyAbortDspAndExitFlag = 0 ;

static void DummyAbortDspAndExit(const char * String,InputType, void *)
{
	if(strcmp(String,"yes")) return ;
	DummyAbortDspAndExitFlag = 1 ;
}

static void DummyKillDspAndExit(const char * String,InputType, void *)
{
	if(strcmp(String,"kill")) return ;
	if (!DspState->IsBusy()) DspState->DoExit();
	DspState->KillAndExit();
}

void DspProcessState::AbortAndExit()
{
	AbortDspExecution();
	ReadSeg->CheckPacketRead();
	if (IsBusy()) for (int Try = 0 ; Try < 3; Try++) {
		ReadSeg->CheckPacketRead();
		sleep(4);
		ReadSeg->CheckPacketRead();
		if (!IsBusy()) {
			DoExit();
			return ;
		}
		StringList temp ;
		temp.Append(Concatenate(
			"The DSP process is not responding to an abort.  "));
		temp.Append(Concatenate(
				"You can attempt to kill the process and exit.  "));
		temp.Append(Concatenate(
				"In this case the state cannot be saved.  "));
		temp.Append(Concatenate(
				"Type `kill' to abort the DSP process or RETURN."));
		UserPrompt * ThePrompt = new UserPrompt(0,
			DummyKillDspAndExit,0,1,0);
		DspApplication::root_window()->InputPost(ThePrompt,"killing DSP++",
			&temp);
		return ;
	}
}

void DspProcessState::DoExit()
{
	DspApplication::root_window()->thaw();
	// TheWindowsManager->UnfreezeScreen();
	for(int Try = 0;1;Try++) {
		if (!IsBusy()) {
			DoExit_Rem_Call_Struct.Execute();
			SharedMemoryExitState = 1 ;
			return ;
		}
		if (Try) {
			UserPrompt * ThePrompt = new UserPrompt(ExecutingPrmpt,
			DummyAbortDspAndExit,0,1,0);
			DspApplication::root_window()->InputPost(ThePrompt,"exiting DSP++");
			if (DummyAbortDspAndExitFlag) DspState->AbortAndExit();
			DummyAbortDspAndExitFlag = 0 ;
			return ;
		}
		ReadSeg->CheckPacketRead();
		sleep(2);
		ReadSeg->CheckPacketRead();
	}
}

int DspProcessState::IsBusy()
{
/*
 *	LogOut << "Rs = " << ReadingState << ", AR = " << ActiveReadRequest
 *		<< ", QC = " << QueuedMenuCommands << "\n" ;
 */
	// return ReadingState ;
	return ReadingState || !ActiveReadRequest || QueuedMenuCommands;
}

int DspProcessState::BusyAbort(const char * TryingWhat)
{
	// LogOut << "BusyAbort: `" << TryingWhat << "'\n" ;
	if (!IsBusy()) return 0 ;
	// LogOut << "The DSP process is busy\n" ;
	*Output + OutputHelp << "The DSP process is busy " ;
	if (ReadingState) *Output << "reading a state file" ;
	else if (!ActiveReadRequest) *Output << "processing a DSP++ statement" ;
	else if (QueuedMenuCommands) *Output << "executing a menu command" ;
	else DbgError("DspProcessState::BusyAbort","not busy");
	*Output <<".\nYou must wait for this to complete or abort it before trying to\n";
	// TheWindowsManager->ClearSuspendRedraw(OutputHelp);
	*Output << TryingWhat << ".\n" ;
	return 1 ;
}

static void interface_init()
{
	ThePlotsManager = new PlotManager ;
	TheDirectories = new DirectoriesDspPP ;
	TheExamples = new ExamplesDspPP ;
	TheCurrentMenus = &AllCgiMenus ;
	TheCurrentMenus->Init();
}

static int read_file_desc = 0 ;
static int write_file_desc = 0 ;
// Routine to exchange messges to insure process communicaition is working
static void Test(int action,PacketHeader * Head=0, const char * data=0)
{
	// Send and recieve test messages
	// Include current process ID to insure we are getting the message
	// we send
	// LogOut << "gui:Test(" << action << ",...)\n" ;

	static char BufSend[64] ;
	static int Leng ;
	const MyId = 1 ;

	switch (action) {
case 0:
		{
			int id = getpid();
			strcpy(BufSend,hex(id)) ;
			Leng = strlen(BufSend) + 1;
			PacketHeader SendHead(PacketTestMessage,MyId,Leng) ;
			WriteSeg->WritePacket(SendHead,BufSend) ;
		}
		break ;
case 1:
		if (Head->Identifier == MyId) {
			if (strcmp(BufSend,data) || Leng != Head->DataSize) {
				TheLog << "Message sent :: " << BufSend <<"\n";
				TheLog << "Message rec :: " << data <<"\n";
				DbgError("Test",
				"Failed to receive correct init test");
			}
			LockProcessing = 0;
		} else WriteSeg->WritePacket(*Head,data);
		
	}
	
	
}




void com_setup(char **argv)
{
	char * Check = getenv("arg_val");
	if (Check) {
		// cerr << "Check = `" << Check << "'\n" ;
		int Count = 0 ;
		for (char * pt = Check; *pt; pt++) if (*pt == ' ') Count++;
		char ** List = new char * [Count+1];
		char * prev = Check ;
		int Index = 0 ;
		for (pt = Check; 1 ; pt++) if (!*pt || *pt == ' ') {
			int Length = pt - prev ;
			List[Index] = new char[Length+1];
			strncpy(List[Index],prev,Length);
			List[Index++][Length] = '\0' ;
			// cerr << "List[" << Index-1 << "] = `" << List[Index-1] << "'\n" ;
			// LogOut << "List[" << Index-1 << "] = `" << List[Index-1] << "'\n" ;
			if (!*pt) break ;
			prev = pt+1 ;
		}
		List[Index] = 0 ;
		argv = List ;
	} 
	// LogOut << "com_setup\n" ;
	SetNewHandler();

	int32 ReadBufId ;
	int32 WriteBufId ;
	int32 ParentId ;
	int32 ChildId ;

	sscanf(Concatenate(argv[2]),"%x",&ReadBufId);
	sscanf(Concatenate(argv[1]),"%x",&WriteBufId);
	sscanf(Concatenate(argv[3]),"%x",&ParentId);
	sscanf(Concatenate(argv[4]),"%x",&ChildId);
	sscanf(Concatenate(argv[6]),"%x",&read_file_desc);
	sscanf(Concatenate(argv[9]),"%x",&write_file_desc);

/*
 *		LogOut << "GUI::Read ID = 0x"  << hex(ReadBufId) << "\n" ;
 *		LogOut << "GUI::Write ID = 0x"  << hex(WriteBufId) << "\n" ;
 *		LogOut << "GUI::Parent ID = 0x"  << hex(ParentId) << "\n" ;
 */

	// LogOut << "argv[4] = \"" << argv[4] << "\"\n" ;
	State.SaveInit(Concatenate(argv[5]));
	State.ActionInit(Concatenate(argv[10]));
#ifdef OPD_PIPES
	WriteSeg = new PipeCommunication(write_file_desc,1);
	ReadSeg = new PipeCommunication(read_file_desc);
	// cerr << "Created segments gui.\n" ;
#else
	WriteSeg = new SharedSegment(SharedWriteOnly ,WriteBufId);
	ReadSeg = new SharedSegment(SharedReadOnly ,ReadBufId);
	int do_f = fcntl(read_file_desc,F_SETFL,O_NONBLOCK);
    if (do_f) {
        cerr << "Cannot change mode of GUI synchronization pipe.\n" ;
        perror(argv[0]);
        exit(1);
    }
#endif
	/***************************************/
	Output = new OutCon(RedirectCGI) ;
	OutputAppend = new OutCon(RedirectCGI,1) ;
	for (int i= 0 ; i < InputEndOfInputTypes;i++) GraphicsStringAvailable[i]=0;
	/**************************** above must be before any CheckPacketRead **/
	Test(0);
	while (LockProcessing) {
		ReadSeg->ReadPacket();
	}
	DspState = new DspProcessState(ChildId,ParentId);
	interface_init();
}


/*
 * static int CheckAndSendResponse(InputType typ)
 * {
 *	if (GraphicsStringAvailable[typ]) {
 *		LogMsg("CheckAndSendResponse::Returned string",
 *			GraphicsString[typ]);
 * 
 *		WriteResponsePacket(GraphicsString[typ],typ,0);
 *		GraphicsStringAvailable[typ] = 0 ;
 *		return 1 ;
 *	}
 *	// LogMsg("CheckAndSendMessage::No string");
 *	return 0;
 * }
 */

static void ProcessControlPacket(PacketControlOptions Opt, int size, char*Data)
{
	switch(Opt) {
case PacketControlMenuCommandComplete:
		DspState->MenuCommandComplete();
		break ;
case PacketControlInformationComplete:
		DspApplication::root_window()->information_complete();
		break ;
case PacketControlExit:
		// LogOut << "DSP::Exit packet received\n";
		ExitCleanUp() ;
		// LogOut << "Returned from ExitCleanUp??\n" ;
		break ;
case PacketControlX_windows:
		if (size != 1) {
			TheLog << "size = " << size << "\n" ;
			DbgError("ProcessControlPacket","bad size");
		}
		State.set_arith_type((ArithType::ArithTypes) *Data);
		// LogOut << "Set arith type to " << (int) *Data << "\n" ;
		break;
default:
		TheLog << "*********DSP::Bad Process control Packet = " << Opt << "\n";
		break;
	}
}

static IsPrintString(const char * Str)
{
	for (const char * Ptr = Str; *Ptr; Ptr++) if (!isascii(*Ptr)) return 0;
		else if (!isprint(*Ptr)) if (*Ptr == '\n') continue; 
		else if (*Ptr == '\t') continue ; else if (*Ptr == '\r')
		continue;
		else return 0;
	return 1;
}




void ProcessPacket(PacketHeader& Head,const char * Data,
	PacketHeader * NextHead )
{
	TextWindow * TheHelpWindow = 0;
	// LogOut << "Type = " << (int) Head.ThePacketType << "\n" ;
	// LogOut << "Head.DataSize = " << (int) Head.DataSize << "\n" ;
	static char Buffer[MaxPacketSize+1];
	for (int i = 0 ; i < Head.DataSize;i++) Buffer[i] = Data[i];
	Buffer[Head.DataSize] = '\0' ;
/*
 *	if (Head.DataSize)
 *		LogOut << "ProcessPacket:: message is `" << Buffer << "'.\n" ;
 */
	if (LockProcessing) {
		if (Head.ThePacketType != PacketTestMessage)
			DbgError("GUI:ProcessPacket","Test message failure");
	} 

	switch (Head.ThePacketType) {
case PacketTestMessage:
		Test(1,&Head,Buffer) ;
		break ;
case PacketWindowText:
		if(!Head.DataSize) {
			TheLog << "PacketWindowText ******* NULL message\n" ;
			return ;
		}
/*
 *		LogOut << "Received remote message::\n";
 *		if (IsPrintString(Buffer)) LogOut << Buffer << "\n" ;
 *		else LogOut << "NOT PRINTABLE.\n" ;
 *		LogOut << "The window for this is :" << Head.Identifier  << "\n" ;
 *		if (NextHead) LogForm("NextHead = 0x%0x, Id = %d",
 *			(long) NextHead, NextHead->Identifier);
 */

		OutputType NextId = OutputNotInitialized;
		if (NextHead) if (NextHead->ThePacketType == PacketWindowText)
			NextId = (OutputType) NextHead->Identifier ;
		DspApplication::root_window()->
			RemoteServer((OutputType) Head.Identifier, Buffer,NextId);

		break ;
case PacketWindowPlotControl:
case PacketWindowPlotData:
		// LogForm("Received remote plot message for window %d",
		//	Head.Identifier);

		int NextPlotId = -1;
		if (NextHead) if (NextHead->ThePacketType == PacketWindowText)
			NextPlotId = NextHead->Identifier ;
		ThePlotsManager->PlotServer(Head,Buffer,NextPlotId);
		break ;
case PacketGetString:
		// LogOut << " PacketGetString\n" ;
		char * PromptString = Concatenate(Buffer) ;
		// if (PromptString) LogOut  << "\"" << PromptString << "\"\n" ;
		InputType Id = (InputType) Head.Identifier ;
		if (Id != InputPrompt) {
			if (Id == InputCppEntry) {
				// LogOut << "Setting ReadRequestActive\n" ;
				DspApplication::state()->ReadRequestActive();
				return ;
			}
			TheLog << "********************** PacketGetString type " << Id <<
				"\n" ;
			*Output + OutputHelp <<
				"********************** PacketGetString type " << Id << "\n" ;
			return ;
		}
		DspApplication::root_window()->remote_prompt(PromptString);
		delete PromptString ;
/*
 *		UserPrompt * Prompt = new UserPrompt(Id,PromptString,
 *			WriteResponsePacket);
 *		DspApplication::root_window()->InputPost(Prompt);
 */
		break ;
case PacketControl:
		ProcessControlPacket((PacketControlOptions) Head.Identifier,
			Head.DataSize,Buffer) ;
		break ;
case PacketDynamicMenuControl:		// control dynamic menus
		// LogMsg("Calling DynamicMenuServer");
		TheDynamicMenuServer.MenuServer(Head,Buffer) ;
		// LogMsg("Back from DynamicMenuServer");
		break ;
case PacketHelpControl:		// set help level
		HelpDo.HelpServer(Head,Buffer);
		break ;
case PacketWindowTextControl:	// set up a dynmaic text window
		DspApplication::dynamic_text_controller()->TextServer(Head,Buffer);
		break ;
case PacketInterfaceControl:
		InterfaceControl.Server(Head,Buffer);
		break ;
case PacketNetworkDescription:
		DspApplication::network_display(Head.Identifier,Head.DataSize,Data);
		break ;
case PacketNetworkEdit:
		// LogOut << "Head.DataSize = " << (int) Head.DataSize << "\n" ;
		DspApplication::network_edit(Head.Identifier,Head.DataSize,Data);
		break ;
case PacketRemoteCommand: 
default:
		TheLog << "**********Gui Bad packet = " << Head.ThePacketType << "\n" ;

	}
/*
 *	if (TheHelpWindow) LogOut << "ProcessPacket exit - Help Cursor = "
 *		<< TheHelpWindow->GetYCursor() << "\n" ;
 */
}

int CheckForEvents()
{
 	// if (TheWindowsManager) return TheWindowsManager->CheckForEvents();
 	return 1 ;
}


static ivPropertyData props[] = {
    { "*plot_color", "black" },
    { "*mark_color", "black" },
    { "*axis_color", "black" },
    { "*tick_color", "black" },
    { "*background", "wheat" },
    { 0 }
};



static ivOptionDesc options[] = {
    { "-plot", "*plot_color", OptionValueNext },
    { "-mark", "*mark_color", OptionValueNext },
    { "-axis", "*axis_color", OptionValueNext },
    { "-tick", "*tick_color", OptionValueNext },
    { 0 }
};


class DispatchPipeLink: public dpIOHandler {
public:
	DispatchPipeLink():dpIOHandler() {}
	virtual int inputReady(int fd);
};

int DispatchPipeLink::inputReady(int fd)
{
#ifdef OPD_PIPES
	if (DspApplication::root_window()->check_remote())
    	ReadSeg->CheckPacketRead();
#else
	const buf_size = 256 ;
	char buf[buf_size] ;
	while (read(fd,buf,buf_size) > 0)
		if (DspApplication::root_window()->check_remote())
			ReadSeg->CheckPacketRead();
#endif
	return 0 ;
}

static const char * arith_version()
{
	ArithType::ArithTypes type ;
	while((type = State.arith_type()) == ArithType::ArithTypeUndefined)
		ReadSeg->ReadPacket();
	switch (type) {
case ArithType::ArithDouble:
			return "double" ;
case ArithType::ArithInt16:
			return "int16" ;
case ArithType::ArithInt32:
			return "int32" ;
case ArithType::ArithFloat:
			return "float" ;
case ArithType::ArithTypeUndefined:
default:
		DbgError("arith_version","bad type");
	}
}


int main(int argc, char** argv)
{
	com_setup(argv);
	
	char * Temp = "ObjectProDSP" ;
	char * iv_arg[]  = {0,"-motif",0};
	int iv_argc = 2 ;
	// char * iv_arg[]  = {0,"-bg","white",0}; int iv_argc = 3 ;
	// char * iv_arg[]  = {0,"-monochrome",0}; int iv_argc = 2 ;
	iv_arg[0] = argv[0] ;
	// ivSession * session = new ivSession(Temp,argc,argv, options, props);
	ivSession * session = new ivSession(Temp,iv_argc,iv_arg, options, props);
	// ivSession * session = new ivSession(Temp,argc,argv, options, props);
	ivStyle * style = new ivStyle(ivSession::instance()->style());
	char * main_win_name = Concatenate(DspApplication::main_window_prefix,
		OBJ_PRO_DSP_VERSION, " for ", arith_version(), " arithmetic");
	style->attribute("name", main_win_name);
	style->attribute("iconName", Temp);
	TheWindow = new RootMenuView(style,*AllCgiMenus.GetMainMenu(),*session);
	DspApplication::set_root_window(*TheWindow);
	// link dispatch to read file descriptor
	dpDispatcher::instance().link(read_file_desc,dpDispatcher::ReadMask,
		new DispatchPipeLink);
	for (int i = 0 ; i < 10000;i++) while(TheWindow->event_check());
	GraphicsMode = 1;
	PacketHeader Head(PacketControl,PacketControlX_windows);
    	WriteSeg->WritePacket(Head);


	DspState->init_action_file(State.action_file());

	int Return = TheWindow->run();




	ExitCleanUp();
	return Return ;
}

