/*  dyntextd.c   */
/*  Copyright 1989 Mountain Math Software  */
/*  All Rights Reserved                    */
#include <string.h>
#include "slist.h"
#include "dyntextd.h"
#include "shared.h"
#include "remcom.h"
#include "winlim.h"
#include "cgidbg.h"
#include "newaloc.h"

DspDynamicTextControl * TheDynamicTextController = 0;


void GetWindowHandle(int& ToSet, const char * Name, const char * Caption)
{
	if (!TheDynamicTextController) TheDynamicTextController =
		new DspDynamicTextControl ;
	TheDynamicTextController->GetWindowHandle(ToSet,Name,Caption);
}

struct WindowMap {
	int UserId;
	int WindowId;
	int * ToSet ;
	WindowMap(int id, int * set) {UserId = id; ToSet = set; WindowId=0;}
};


class WindowMapList: public SingleList {
public:
	ErrCode Insert(WindowMap *nt) {return SingleList::Insert(nt);}
	ErrCode Append(WindowMap *nt) {return SingleList::Append(nt);}
	WindowMap * Get()   {return (WindowMap *) SingleList::Get();}
	WindowMap * Pop() {return (WindowMap *) SingleList::Pop();}
	WindowMap * GetNFromTop(int N) ;
	WindowMap * GetNthEntry(int N) ;
	WindowMapList(){;}
	int Size(){return SingleList::Size();}
	WindowMap * FindEntry(int UserId);
	int IsOpen(int UserId);
} ;


int WindowMapList::IsOpen(int UserId)
{
	// LogOut << "::IsOpen(" << UserId << ")\n" ;
	WindowMap * Map = FindEntry(UserId);
	if (!Map) return 0 ;
	return Map->WindowId != 0 ;
}

class WindowMapListIterator: public SingleListIterator {
public:
	WindowMapListIterator(WindowMapList& df):
		SingleListIterator((SingleList&) df){}
	WindowMap * operator()()
		{return (WindowMap *) Next();}
};

WindowMap * WindowMapList::FindEntry(int UserId)
{
	// LogOut << "FindEntry(" << UserId << ")\n" ;
	WindowMapListIterator Next(*this);
	WindowMap * Map ;
	while (Map = Next()) {
/*
 *		LogOut << "Checking " << Map->UserId << ", " << Map->WindowId
 *			<< "\n" ;
 */
		if (Map->UserId == UserId) return Map;
	}
	return 0;
}

class IntPtrList: public SingleList {
public:
	ErrCode Insert(int *nt) {return SingleList::Insert(nt);}
	ErrCode Append(int *nt) {return SingleList::Append(nt);}
	int * Get()   {return (int *) SingleList::Get();}
	int * Pop() {return (int *) SingleList::Pop();}
	int * GetNFromTop(int N) ;
	int * GetNthEntry(int N) ;
	IntPtrList(){;}
	int Size(){return SingleList::Size();}
	int InList(int Value);
} ;

class IntPtrListIterator: public SingleListIterator {
public:
	IntPtrListIterator(IntPtrList& df):
		SingleListIterator((SingleList&) df){}
	int * operator()()
		{return (int *) Next();}
};


int IntPtrList::InList(int Value)
{
	IntPtrListIterator Next(*this);
	int * Test ;
	while (Test = Next()) if (*Test == Value) return 1;
	return 0;
}

int RemoveValue(IntPtrList **Lst,int Value)
{
	IntPtrListIterator Next(**Lst);
	int * Test;
	while(Test = Next()) if (*Test == Value) break ;
	if (*Test != Value) return 0;
	IntPtrList * NewList = new IntPtrList ;
	while (Test = (*Lst)->Get()) if (*Test != Value) NewList->Append(Test);
	delete *Lst ;
	*Lst = NewList ;
	return 1;
}
		

DspDynamicTextControl::DspDynamicTextControl() 
{
	TheHandleRequests = new IntPtrList ;
	TheWindowMap = new WindowMapList ;
	ActiveWindowOpenRequest = 0;

	// Check on system constants for GetHandle routine
	if (WindowLineLength + WindowNameLength + 1 > MaxPacketSize)
		DbgError("GetWindowHandle","inconsitent constants");
}


void DspDynamicTextControl::OpenWindowAndWait(int DisplayHandle, int * ToSet)
{
	// LogOut << "OpenWindowAndWait(" << DisplayHandle << ")\n" ;
	OpenWindow(DisplayHandle,ToSet);
	WaitWindowOpen(DisplayHandle);
}

void DspDynamicTextControl::TextServer(class PacketHeader& Head,
	const char * Data)
{
	int WindowAction = Head.GetPlotId() ;
	int UserId = Head.GetPlotChannel();
/*
 *	LogOut << "DspDynamicTextControl WinAct = " << WindowAction <<
 *		", UserId = " << UserId << "\n" ;
 */
	ActiveWindowOpenRequest = 0 ;
	WindowMap * Map = 0 ;
	int * HandlePlace = 0 ;
	switch (WindowAction) {
case TextControlSendHandle:
		HandlePlace = TheHandleRequests->Get();
		if (!HandlePlace) DbgError("DspDynamicTextControl::TextServer",
			"null list");
		*HandlePlace = UserId ;
		// LogOut << "The handle is " << UserId << "\n" ;
		return ;
case TextControlSendOpen:
		if ((Head.DataSize != sizeof(int)) || !Data)
			DbgError("TextServer", "bad size");
		// LogOut << "Window is " << *(int *) Data << "\n" ;

		Map = TheWindowMap->FindEntry(UserId);
		if (!Map) DbgError("TextServer", "bad UserId for Open");
		Map->WindowId = *(int *) Data;
		if (!Map->ToSet) DbgError("TextServer","null ToSet");
		*(Map->ToSet) = Map->WindowId;
		Map->ToSet = 0;
/*
 *		LogOut << "Adding Window: User = " << Map->UserId <<
 *		 	", Window = " << Map->WindowId << "\n" ;
 */
		Output->AddWindow(Map->UserId);
		return ;
case TextControlNewSampleRate:
default:
		DbgError("DspDynamicTextControll::TextServer","invalid option");
	}
}

void DspDynamicTextControl::WaitWindowOpen(int UserId)
{
	while (!CheckWindowOpen(UserId));
}

int DspDynamicTextControl::CheckWindowOpen(int UserId)
{
	// LogOut << "CheckWindowOpen(" << UserId << " enter\n" ;
	CheckForPacket();
	return TheWindowMap->IsOpen(UserId) ;
}

struct TextWinReq {
	PacketHeader Head ;
	const char * Name ;
	TextWinReq(PacketHeader hd, const char *nm){Head=hd; Name=nm;}
	void SendPacket() {WriteSeg->WritePacket(Head,Name);
		delete (char *) Name;}
};

class TextWinReqList: public SingleList {
public:
	ErrCode Insert(TextWinReq *nt) {return SingleList::Insert(nt);}
	ErrCode Append(TextWinReq *nt) {return SingleList::Append(nt);}
	TextWinReq * Get()   {return (TextWinReq *) SingleList::Get();}
	TextWinReq * Pop() {return (TextWinReq *) SingleList::Pop();}
	TextWinReq * GetNFromTop(int N) ;
	TextWinReq * GetNthEntry(int N) ;
	TextWinReqList(){;}
	int Size(){return SingleList::Size();}
} ;

class TextWinReqListIterator: public SingleListIterator {
public:
	TextWinReqListIterator(TextWinReqList& df):
		SingleListIterator((SingleList&) df){}
	TextWinReq * operator()()
		{return (TextWinReq *) Next();}
};

static TextWinReqList * TheQueuedTextWindows = 0 ;

static void NotifyWhenActive()
{
	TextWinReq * Req ;
	while (Req = TheQueuedTextWindows->Get()) {
		Req->SendPacket();
		delete Req ;
	}
}

static void AppendRequest(PacketHeader Head, const char * Name)
{
	if (!TheQueuedTextWindows) TheQueuedTextWindows = new TextWinReqList ;
	TheQueuedTextWindows->Append(new TextWinReq(Head,Name));
}

int DspDynamicTextControl::GetWindowId(int UserId)
{
	WindowMap * Map = TheWindowMap->FindEntry(UserId);
	if (!Map) DbgError("Text- GetWindow","bad UserId for GetWindowId");
	return Map->WindowId ;
}


void DspDynamicTextControl::GetWindowHandle(int& ToWrite, const char * Name,
	const char * Caption)
{
	// LogOut << "TextControl::GetHandle - Name = `" << Name << "\n" ;
	// if (Caption) LogOut << "Caption - `" << Caption << "'\n" ;
	char Buf[MaxPacketSize];
	for (char * Ptr = Buf ; Ptr < Buf+MaxPacketSize;Ptr++) *Ptr = '\0' ;
	strncpy(Buf,Name,WindowNameLength);
	int Leng = strlen(Name);
	if (Leng > WindowNameLength ) {
		Leng = WindowNameLength  ;
		Buf[Leng] = '\0' ;
	}
	int Leng2 = -1 ;
	if (Caption) if (*Caption) {
		// LogOut << "Copying caption\n" ;
		strncpy(Buf+Leng+1,Caption,WindowLineLength);
		Leng2 = strlen(Caption);
		if (Leng2 > WindowLineLength) Leng2 = WindowLineLength;
	}
	int Size = Leng+2+Leng2 ;
	Buf[Size-1] = '\0' ;
/*
 *	LogOut << "Leng = " << Leng << ", Leng2 = " << Leng2 <<
 *	 	", Size = " << Size << "\n" ;
 */
	while(ActiveWindowOpenRequest) CheckForPacket();
	TheHandleRequests->Append(&ToWrite);
	PacketHeader Head = PlotPacketHeader(PacketWindowTextControl,
			TextControlGetWindow,0,Size);
#ifdef OPD_PIPES
	if (SharedSegment::is_comm_active(NotifyWhenActive)) {
#else
	if (!TheCommControl) TheCommControl = new CommControl ;
	if (TheCommControl->IsCommActive(NotifyWhenActive)) {
#endif
		ActiveWindowOpenRequest = ToWrite ;
		WriteSeg->WritePacket(Head,Buf);
	} else {
		// LogOut << "Doing append request\n" ;
		char * Temp = new char[Size];
		MoveNBytes(Temp,Buf,Size);
		AppendRequest(Head,Temp);
	}
	// LogOut << "Exiting DspDynamicTextControl::GetWindowHandle\n" ;
}

void DspDynamicTextControl::CheckForPacket()
{
	ReadSeg->CheckPacketRead();
}

void DspDynamicTextControl::OpenWindow(int WindowHandle, int * ToSet)
{
	WindowMap * Map = new WindowMap(WindowHandle,ToSet);
	TheWindowMap->Append(Map);
	// LogOut << "OpenWindow enter\n" ;
	PacketHeader Head = PlotPacketHeader(PacketWindowTextControl,
		TextControlOpenWindow, WindowHandle);
	WriteSeg->WritePacket(Head);
	// LogOut << "OpenWindow exit\n" ;
}


