#include <stream.h>
#include "txtwin.h"
#include <IV-look/kit.h>
#include <IV-look/field.h>
#include <InterViews/background.h>
#include <InterViews/layout.h>
#include <InterViews/session.h>
#include <InterViews/style.h>
#include <InterViews/window.h>
#include <InterViews/label.h>
#include <InterViews/input.h>
#include <InterViews/event.h>
#include <InterViews/hit.h>
#include <InterViews/window.h>
#include <InterViews/input.h>
#include <InterViews/patch.h>
#include <InterViews/glyph.h>
#include <InterViews/polyglyph.h>
#include <InterViews/resource.h>

#include <OS/string.h>


#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include "mkstr.h"
#include "call_back.h"
#include "xdrv.h"
#include "file_view.h"
#include <OS/leave-scope.h>
#include <InterViews/leave-scope.h>
#include "dsp_app.h"
#include "cgidbg.h"

ScrollFieldEditor::ScrollFieldEditor(const osString& sample, ivWidgetKit* k,
	ivStyle* s, TxtWindow& w, FocusSelector * sel):
		ivFieldEditor(sample,k,s,0),
		win(w),
		init(0),
		focus_selector(sel)
{
}

void ScrollFieldEditor::process_keystroke(const ivEvent& event)
{
	RootMenuView * root = DspApplication::root_window();
	if (root) root->keystroke(event);
}



InputType ScrollFieldEditor::type() const
{
	return win.type();
}

void ScrollFieldEditor::keystroke(const ivEvent& event)
{
	int EndEdit = 0 ;
	const size = 1024 ;
	char buf[size];
	unsigned chars = event.mapkey(buf,size-1);
	for (int i = 0 ; i < chars ; i++) {
		if (buf[i] == 0x1B) {
			DspApplication::root_window()->focus_buttons();
			return ;
		}
		// LogOut << buf[i] ;
		if (buf[i] == '\r') EndEdit = 1 ;
		buf[i] = ' ' ;
	}
	// LogOut << "\n" ;
	ivFieldEditor::keystroke(event);
	
	if (!EndEdit) return ;

	// make sure any pop up windows related to DSP++ statements are placed
	//	relative to the main window
	if (type() == InputCppEntry)
		DspApplication::root_window()->set_active(DspApplication::root_window());

	win.record(text()->string());
	win.scroll(text()->string(),1);
}

void ScrollFieldEditor::do_init()
{
	if (init) return ;
	init = 1 ;
	field(DspApplication::spacer());
	if (focus_selector) focus_selector->edit_init();
}

void ScrollFieldEditor::press(const ivEvent& e)
{
	const osString * st = text() ;
	if (st) if (init)
	  for (const char * pt = st->string(); *pt; pt++) if (*pt != ' ') {
		ivFieldEditor::press(e);
		return ;
	}
}

void ScrollFieldEditor::scroll_patch_redraw()
{
	win.scroll_patch_redraw();
}

void ScrollFieldEditor::release(const ivEvent& e)
{
	int s_init = init ;
	if (!init) do_init();
	if (focus_selector) focus_selector->request_focus(*this);
	// if (s_init) ivFieldEditor::release(e);
}


TxtWindow::TxtWindow(const char * name, ivSession * s,const char *BaseString,
	int size, InputCallback& call_back, FocusSelector * sel):
	callback(call_back),
	session(s),
	history_window(0),
	history_file(history_file_name=DspApplication::make_file_name()),
	window_name(name)
{
	// LogOut << "TxtWindow::TxtWindow, spacer = `" << BaseString << "'.\n" ;
	if (size < 2) size = 2 ;
	if (size > 1000) size = 1000 ;

    ivWidgetKit& kit = *ivWidgetKit::instance();
    const ivLayoutKit& layout = *ivLayoutKit::instance();

	vbox = layout.vbox(4);
	ivStyle * style = session->style();
	osString * str = new osString(BaseString);
	// LogOut << "str = `" << str->string() << "'\n" ;
	vbox->append(new ivLabel(*str,kit.font(),kit.foreground()));
	ivRequisition Temp ;
	vbox->request(Temp);
	text_width = Temp.x_requirement().natural();
	// LogOut << "TxtWindow width is " << text_width << "\n" ;
	index_at_top = vbox->count() -1 ;

	for (int i = 0 ; i < size - 2; i++) 
		vbox->append(new ivLabel(*str,kit.font(),kit.foreground()));

	index_at_bottom = vbox->count() - 1  ;	
	highest_written = index_at_bottom  ;
	// LogOut << "highest_written = " << highest_written << "\n" ;
	// LogOut << "replace bottom " << index_at_bottom << "\n" ;

	const char * beveled = "beveled" ;
	kit.begin_style("FieldEditor");
	ivStyle* kit_style = kit.style();
	kit_style->attribute("background","white");
	vbox->append(editor = new ScrollFieldEditor(*str, &kit,style,*this, sel));
	// editor->field(DspApplication::spacer());
	// editor->select(0);
	kit.end_style();
	scroll_patch = new ivPatch(vbox);
}

TxtWindow::~TxtWindow()
{
	history_file.close();
	unlink(history_file_name);
}

InputType TxtWindow::type() const
{
	return callback.get_type();
}

void TxtWindow::history()
{
	if (history_window) {
		history_window->raise();
		return ;
	}
	history_file.flush();
	ivStyle& style = * new ivStyle(DspApplication::style()) ;
    style.attribute("name", window_name);
    style.attribute("iconName", window_name);
    history_window = new FileWindow(DspApplication::kit(),
		DspApplication::layout(), style,history_file_name,
		DspApplication::font(),DspApplication::kit().background(),this);

}

void TxtWindow::record(const char *str)
{
	callback.record(str);
}


void TxtWindow::edit()
{
	// editor->edit(*editor->text(),0,0);
	editor->select(0,0);
}

void TxtWindow::scroll_patch_redraw()
{
	scroll_patch->redraw();
}

void TxtWindow::scroll(const char * str, int new_field)
{
	static int max_length = -1 ;
	if (max_length < 0) max_length = DspApplication::spacer_length();

	if (!str) return ;
	if (!*str) return ;
	// LogOut << "scroll(" << str << ", " << new_field << ")\n" ;
	char * delete_str = Concatenate(str) ;
	char * last_blank = delete_str ;
	for (char * ck = delete_str; *ck; ck++) {
		if (!isascii(*ck)) *ck = ' ' ;
		if (!isprint(*ck)) *ck = ' ' ;
		if (isgraph(*ck)) last_blank = ck+1 ;
	}
	if (last_blank < ck) *last_blank = '\0' ;
	int length = strlen(delete_str);
	char * ptr = delete_str ;
	for (;;) {
		if (length > max_length) {
			char temp = ptr[max_length] ;
			ptr[max_length] = '\0' ;
			do_scroll(ptr,new_field);
			ptr[max_length] = temp ;
			length -= max_length ;
			ptr += max_length ;
			continue ;
		}
		do_scroll(ptr,new_field);
		break ;
	}
	delete delete_str ;
}

void TxtWindow::do_scroll(const char * str, int new_field)
{
	history_file << str << "\n" ;
	int32 byte_count = strlen(str) + 1 ;
	if (history_window) {
		history_file.flush();
		history_window->update_size(1,byte_count);
	}
	const char * long_str = str ;
	// LogOut << "scrolling `" << long_str << "'\n" ;
	int length = strlen(DspApplication::spacer()) ;
	char * buf = 0 ;
	int str_length = strlen(long_str);
	if (length > str_length) {
		buf = new char[length+1];
		buf[length] = '\0' ;
		strcpy(buf,long_str);
		for (int i = str_length;i < length;i++) buf[i]=' ' ;
		long_str = buf ;
	}
	// LogOut << "scrolling `" << long_str << "'\n" ;
    ivWidgetKit& kit = *ivWidgetKit::instance();

	for (ivGlyphIndex i = highest_written ; i < index_at_bottom ; i++) {
		vbox->replace(i,vbox->component(i+1));
	}
	ivLabel * new_label = new ivLabel(long_str,kit.font(),
		kit.foreground());
/*
 *	LogOut << "index_at_top = " << index_at_top << ", index_at_bottom = " <<
 *		index_at_bottom << "\n" ;
 */
	vbox->replace(index_at_bottom,new_label);
	// LogOut << "highest_written = " << highest_written << "\n" ;
	if (highest_written > index_at_top) highest_written-- ;
	// LogOut << "highest_written = " << highest_written << "\n" ;
	// LogOut << "ck5" << long_str << "\n" ;
	if (new_field) {
		editor->field(DspApplication::spacer());
		editor->select(0);
	}
	scroll_patch_redraw();
	ivResource::flush();
	if (new_field) callback.WriteLine(long_str,this);
	delete buf ;
}


