/*  dyntextg.c   */
/*  Copyright 1989 Mountain Math Software  */
/*  All Rights Reserved                    */
#include <string.h>
#include <stream.h>
#include <IV-look/kit.h>
#include <InterViews/layout.h>
#include <InterViews/style.h>
#include <unistd.h>
#include <stdio.h>

#include "slist.h"
#include "newaloc.h"
#include "dyntextg.h"
#include "shared.h"
#include "remcom.h"
#include "cgidbg.h"
#include "file_view.h"
#include "dsp_app.h"
#include "mkstr.h"
#include "usriotyp.h"


struct WindowMapElement {
	int UserIndex;
	int32 byte_count ;
	int32 line_count ;
	char * file_name ;
	FILE * the_file ;
	FileWindow * the_window ;
	const char * Name ;
	const char * Caption ;
	void append(FILE * file);
	void append(const char *);
	void create_text_window();
	WindowMapElement(int User, const char * nm, const char * caption):
		the_window(0),
		the_file(0),
		file_name(0),
		UserIndex(User),
		Name(nm),
		byte_count(0),
		line_count(0),
		Caption(caption){}
	virtual ~WindowMapElement() ;
	FileWindow * window() const {return the_window;}
};

WindowMapElement::~WindowMapElement()
{
	// LogOut << "deleting WindowMapElement\n" ;
	if (!the_file) return ;
	fclose(the_file);
	// LogOut << "deleting " << file_name << "\n" ;
	unlink(file_name);
	// LogOut << "deleting WindowMapElement\n" ;
	delete[] (void *) Name;
	delete[] (void *) Caption;
	// remove file from system here
	delete file_name;
}


class WindowMapList: public SingleList {
public:
	ErrCode Insert(WindowMapElement * nt) {return SingleList::Insert(nt);}
	ErrCode Append(WindowMapElement * nt) {return SingleList::Append(nt);}
	WindowMapElement * Get()  
		{return (WindowMapElement * ) SingleList::Get();}
	WindowMapElement * Pop()
		{return (WindowMapElement * ) SingleList::Pop();}
	WindowMapElement *  GetNFromTop(int N) ;
	WindowMapElement *  GetNthEntry(int N) ;
	WindowMapList(){;}
	int Size(){return SingleList::Size();}
	void Clear() {SingleList::Clear();}
	FileWindow * window(int UserIndex);
	WindowMapElement * element(OutputType typ) ;
	void raise_window(int window_id);
} ;


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

void WindowMapElement::append(const char * str)
{
	// LogOut << " WindowMapElement::append(\"" << str << "\")\n" ;
	for (const char * pt = str; *pt ; pt++,byte_count++)
		if (*pt == '\n') line_count++ ;
	fputs(str,the_file);

	// following minimizes the expensive updates of the displayed file
	// byte_count may be changed by recusrsive calls, save_byte_count will not
	for (int i = 0; i < 10; i++)
		 for (int j=0;j<100;j++) if (!DspApplication::check_packet_read()) break ;
	if (byte_count) {
		fflush(the_file);
		the_window->update_size(line_count,byte_count);
		byte_count = 0 ;
		line_count = 0 ;
	}
}

void WindowMapElement::append(FILE * file)
{
	// used for viewing an existing disk file
}

void WindowMapElement::create_text_window()
{
	file_name = DspApplication::make_file_name() ;
	the_file = fopen(file_name,"w");
	if (!the_file) DbgError("WindowMapElement::create_text_window",
		"cannot create output file");
/*
 *	LogOut << "WindowMapElement::create_text_window() created `" <<
 *		file_name << "'\n" ;
 */
	Style& style = * new Style(DspApplication::style()) ;
    style.attribute("name", Caption);
    style.attribute("iconName", Name);
	const Font * font = DspApplication::tty_font();
	const Color *color = DspApplication::white();
	the_window = new FileWindow(DspApplication::kit(),DspApplication::layout(),
		style,file_name,font,color,0,0);
}

WindowMapElement * WindowMapList::element(OutputType typ)
{
    WindowMapListIterator Next(*this) ;
    WindowMapElement * Elt ;
    while(Elt = Next()) if (Elt->UserIndex == typ) return Elt ;
    return 0 ;
}

void WindowMapList::raise_window(int window_id)
{
	// LogOut << "WindowMapList::raise_window(" << window_id << ")\n" ;
	WindowMapListIterator Next(*this) ;
    WindowMapElement * Elt ;
    while(Elt = Next()) {
		// LogOut << "Checking " << Elt->UserIndex << "\n" ;
		if (Elt->UserIndex == window_id) {
			Elt->the_window->raise_window() ;
			return ;
		}
	}
}

FileWindow * WindowMapList::window(int UserIndex)
{
	WindowMapListIterator Next(*this) ;
	WindowMapElement * Elt ;
	while(Elt = Next()) if (Elt->UserIndex == UserIndex)
		return Elt->window();
	return 0 ;
}

GuiDynamicTextControl::GuiDynamicTextControl() 
{
	TheMaps = new WindowMapList ;
	NextFreeUserIndex = OutputEndOfOutputTypes ;
	TheFile = 0 ;
	NewWindowId = 0 ;
}

GuiDynamicTextControl::~GuiDynamicTextControl() 
{
	// LogOut << "delete GuiDynamicTextControl\n" ;
	// TheMaps->Clear();
	WindowMapElement * mp ;
	while (mp = TheMaps->Get()) delete mp ;
	delete TheMaps;
}

WindowMapElement * GuiDynamicTextControl::GetMapElement(int Id)
{
	WindowMapListIterator Next(*TheMaps);
	WindowMapElement * Elt ;
	while (Elt = Next()) if (Elt->UserIndex == Id) return Elt ;
	return 0;
}

void GuiDynamicTextControl::TextWindowCreated(int UserIndex)
{
	WindowMapElement * Elt = GetMapElement(UserIndex);
	if (!Elt) DbgError("GuiDynamicTextControl::TextWindowCreated",
		"no such window");
	if (TheFile) {
/*
 *		 LogOut <<
 *			"GuiDynamicTextControl::TextWindowCreated - TheFile\n";
 */
		Elt->append(TheFile);
		fclose(TheFile);
		TheFile = 0 ;
		NewWindowId = 0 ;
		return ;
	}
	PacketHeader Head = PlotPacketHeader(PacketWindowTextControl,
		TextControlSendOpen,UserIndex, sizeof(UserIndex));
	WriteSeg->WritePacket(Head,(char *) &UserIndex);
}

void GuiDynamicTextControl::append(OutputType type,
	const char *str,OutputType)
{
/*
 *	LogOut << "GuiDynamicTextControl::append(" << type << ",\"" <<
 *		str << "\",)\n" ;
 */
	WindowMapElement * elt = TheMaps->element(type);
	if (!elt) DbgError("GuiDynamicTextControl::append","bad channel");
	elt->append(str);
}

const char * GuiDynamicTextControl::CheckNotOpened(int Id)
{
	WindowMapElement * Elt = GetMapElement(Id);
	if (!Elt) DbgError("GuiDynamicTextcontrol::CheckNotOpened",
		"no such Id");
	if (Elt->the_window) DbgError("GuiDynamicTextcontrol::CheckNotOpened",
		"already opened");
	return Elt->Name ;
}

int GuiDynamicTextControl::NewTextWindow(const char *Name,
	const char * Caption)
{
	if (!Caption) Caption = Name ;
	TheMaps->Append( new WindowMapElement(NextFreeUserIndex,Name, Caption));
/*
 *	LogOut << "new WindowMapElement(" << NextFreeUserIndex << ", \"" << Name
 *		<< "\", \"" << Caption << "\")\n" ;
 */
	return NextFreeUserIndex++;
}

void GuiDynamicTextControl::TextServer(class PacketHeader& Head,
	const char *Data)
{
	int WindowAction = Head.GetPlotId() ;
	int WindowId = Head.GetPlotChannel();
	int Size = Head.DataSize;

/*
 *	LogOut << "TextServer - WindowAction = " << WindowAction <<
 *		", WindowId = " << WindowId << ", Size = " <<
 *		Head.DataSize << "\n" ;
 */

 
	switch (WindowAction) {
case TextControlGetWindow:
		{
			int Leng = 0;
			if (Data) Leng = strlen(Data);
			// LogOut << "Leng = " << Leng << "\n" ;
			char * Name = strcpy(new char[Leng+1],Data);
			char * Caption ;
			if (Size > Leng+1) {
				// LogOut << "FoundCaption\n" ;
				int Leng2 = Size - Leng - 1 ;
				Caption = strncpy(
					new char[Leng2+1],Data+Leng+1,Leng2);
				Caption[Leng2] = '\0' ;
				// LogOut << "Caption is" << Caption << "\n" ;
			} else {
				Caption = strcpy(new char[Leng+1],Data);
			}
			WindowId = NewTextWindow(Name,Caption);
			PacketHeader OutHead =
				PlotPacketHeader(PacketWindowTextControl,
				TextControlSendHandle,WindowId);
			WriteSeg->WritePacket(OutHead);
		}
		return ;
case TextControlOpenWindow:
		CheckNotOpened(WindowId);
		WindowMapElement * Elt = GetMapElement(WindowId);
/*
 *		LogOut << "CreateTextWindow(" << Elt->Name << ", " <<
 *			Elt->Caption << ", " << WindowId << ", this)\n" ;
 */
		Elt->create_text_window();
		TextWindowCreated(WindowId);
		return ;
case TextControlNewSampleRate:
		FileWindow * Win = TheMaps->window(WindowId);
		if (!Win) DbgError("DynamicTextControl::TextServer",
			"bad window id");
		double Temp ;
		if (Size != sizeof(Temp)) DbgError(
			"DynamicTextControl::TextServer","bad size for double");
		MoveNBytes((char *) &Temp,Data,Size);
		// Win->NewSampleRate(Temp);
		break ;
case TextControlRaiseWindow:
		// LogOut << "TextControlRaiseWindow, Id = " << WindowId << "\n" ;
		if (!TheMaps) break ;
		TheMaps->raise_window(WindowId);
		break ;
default:
		DbgError("DynamicTextControl::TextServer","invalid option");
	}
}


void GuiDynamicTextControl::OpenTextWindow(const char * TextName)
{
	char * Name = strcpy(new char[strlen(TextName)+1],TextName);
	if (Name) if (*Name) {
		TheFile = fopen(Name,"r");
		if (!TheFile) {
			*Output + OutputHelp << "Cannot open file `" <<
				Name << "'.\n" ;
			return;
		}
	}
	int WindowId = NewTextWindow(Name);
	// TheWindowsManager->CreateTextWindow(Name,Name,WindowId,this);
}

