// KBuilder
// Maker Window Routines
        
#include <qpopmenu.h>
#include <qmlined.h>
#include <qfile.h>
#include <qfiledlg.h>
#include <qmsgbox.h>
#include <qaccel.h>
#include <qlistbox.h>
#include <qregexp.h>
#include <kfontdialog.h>

#include "Editor.h"
#include "Maker.h"
#include "Maker.moc"



/////////////////////////////////////////////////////
//
// con-/destructor(s)
//
Maker::Maker(QWidget *parent, const char *name, const char* path, 
			 const char* command)
	: KTopLevelWidget(name), 
	  Path(path),
	  Command("make")
{
	warning("command:%s", command);
	warning("path   :%s", path);
	if(!Path.isEmpty())
	{
		chdir(Path);
		warning("dir is changed to <%s>", (const char*)Path);
	}
	
	Process = 0;
 
    Font = QFont("Helvetica", 14, QFont::Normal);

    QString s = "Make Results";
    setCaption(s);
   
		// set up the menu bar:
    mainMenu = new KMenuBar(this, "MenuBar_1");
    setMenu(mainMenu);

    file = new QPopupMenu;
    idMake = file->insertItem("Run &Make Again\tF9", this, SLOT(runMakeSlot()));
    idKill = file->insertItem("&Kill Make\tCTRL+F9", this, SLOT(killMakeSlot()));
    file->insertSeparator();
    file->insertItem("&Save To File...", this, SLOT(saveAsFileSlot()));
    file->insertSeparator();
    file->insertItem("Select &Font...\tAlt+F", this, SLOT(selectFontSlot()));
    file->insertItem("(Se&t Maker Command...nyi)", this, SLOT(selectCommandSlot()));
    file->insertSeparator();
    file->insertItem("&Close\tF3", this, SLOT(closeWindowSlot()));
	file->setItemEnabled(idKill, false);
    mainMenu->insertItem("&File", file);

		// accelerators:
	QAccel* a = new QAccel(this);
	a->connectItem(a->insertItem(Key_F+CTRL), this, SLOT(selectFontSlot()));
	a->connectItem(a->insertItem(Key_F2), this, SLOT(saveAsFileSlot()));
	a->connectItem(a->insertItem(Key_F3), this, SLOT(closeWindowSlot()));
	a->connectItem(a->insertItem(Key_F9), this, SLOT(runMakeSlot()));

        	// add widget to list of editor windows
 	Makers.append(this);

	listbox = new QListBox(this);
	listbox->setFont(Font);
	setView(listbox);

		// connect slot to listbox:
	connect(listbox, SIGNAL(selected(const char*)), 
			this, SLOT(itemSelectedSlot(const char*)));
}

Maker::~Maker()
{
    Makers.remove(this);

		// if there is still a process running, cancel it:
	killMake();

	delete mainMenu;
    delete listbox;
}

QList<Maker> Maker::Makers;



/////////////////////////////////////////////////////
//
// events
//
void Maker::resizeEvent(QResizeEvent* ev)
{ 
/*
    QSize newSize(ev->size());
    QSize sMenu(newSize.rwidth(), MENUBAR_HEIGHT);
	QSize sList(newSize.rwidth(), newSize.rheight() - MENUBAR_HEIGHT);

    mainMenu->resize(sMenu); 
    listbox->resize(sList); 
*/
    KTopLevelWidget::resizeEvent(ev);
	printf("resize\n");
}



/////////////////////////////////////////////////////
//
// slots
//

void Maker::saveAsFileSlot()
{
	saveMessagesTo("");
}

void Maker::closeWindowSlot()
{
	close();
}

void Maker::selectFontSlot()
{
    if(KFontDialog::getFont(Font) == QDialog::Accepted)
		listbox->setFont(Font);
}

void Maker::selectCommandSlot()
{
}

void Maker::itemSelectedSlot(const char* item)
{
		// how is it possible to make this compiler-independant?

	QRegExp r("[a-zA-Z0-9/\\.\\-#]+:[0-9]+:");    // later configurable

	int length, 
	    pos = r.match(item, 0, &length);

	if(pos == 0)
	{
		char* firstColon = strchr(item, ':');
		char* secondColon = strchr(firstColon + 1, ':');

		QString file(item, firstColon - item + 1);
		QString line(firstColon + 1, secondColon - firstColon);
	
		printf("file:<<%s>>, line <<%s>>\n", (const char*)file, (const char*)line);
		if(QFileInfo(file).exists())
		{
			Editor* e = Editor::findEditorWidget(file);
			if(e)
			{
				e->raise();
				e->setActiveWindow();
				e->show();
				e->setFocus();
			}
			else
			{
				e = new Editor(0, file, file);
				e->show();
			}
			e->gotoLine(atoi(line) - 1);
		}
		else 
			printf("file not found\n");
	}
	else
		printf("not a valid error/warning line!\n");

}

void Maker::runMakeSlot()
{
	if(Process)
	{
		QMessageBox::information(this, "Make Message", 
								 "There is still another\nmake process running.",
 								 "Cancel", 0, 0, 0, 2);
		return;
	}

	file->setItemEnabled(idMake, false);
	file->setItemEnabled(idKill, true);
	Process = new KProcess;

	connect(Process, SIGNAL(receivedStdout(KProcess*, char*, int)), this, 
			SLOT(receiveStdOutSlot(KProcess*, char*, int)));
	connect(Process, SIGNAL(receivedStderr(KProcess*, char*, int)), this, 
			SLOT(receiveStdErrSlot(KProcess*, char*, int)));
	connect(Process, SIGNAL(processExited(KProcess*)), this, 
			SLOT(processExitedSlot(KProcess*)));

	listbox->clear();
	insertLBItem("*********");
	insertLBItem(Path);
	insertLBItem(Command);

	insertLBItem("***** make started");

	Process->setExecutable(Command);
	Process->start(KProcess::NotifyOnExit, KProcess::All);

}

void Maker::killMakeSlot()
{
	insertLBItem("***** make killed");
	killMake(false);
}

void Maker::receiveStdOutSlot(KProcess*, char* str, int num)
{
	char* f = new char[num + 1];
	strncpy(f, str, num);
	f[num] = 0;
    insertLBItem(f);
	delete[] f;
}

void Maker::receiveStdErrSlot(KProcess*, char* str, int num)
{
    static QString msg;


        // get output from process:
	char* f = new char[num + 1];
	strncpy(f, str, num);
	f[num] = 0;

    if(f[num - 1] == '\n')
    {
        msg += f;
        insertLBItem(msg);
        msg = "";
    }
    else
        msg += f;

	delete[] f;
}

void Maker::processExitedSlot(KProcess*)
{
	killMake(false);
	insertLBItem("***** make terminated\n");
}



/////////////////////////////////////////////////////
//
// public functions
//

void Maker::startMake()
{
	runMakeSlot();
}

bool Maker::killMake(bool request)
{
	if(Process)
	{
		if(request)
		{
			if(QMessageBox::information(this, "Make Message", 
										"Kill currently running make proecss?",
 										"Yes", "No", 0, 0, 1) != 0)
				return false;
		}

		file->setItemEnabled(idMake, true);
		file->setItemEnabled(idKill, false);

		Process->kill();
		delete Process;
		Process = 0;
		return true;
	}
	else
		return false;
}

bool Maker::saveMessagesTo(const QString& fn)
{
	QString fname;
	if(fn.isEmpty())
	{
		fname = QFileDialog::getOpenFileName(0, "*", this);
		if(fname.isEmpty())	// user doesn't want to save
			return false;		
	}
	else
		fname = fn;


		// do saving to selected file...

	return true;
}



/////////////////////////////////////////////////////
//
// helper functions
//

void Maker::insertLBItem(const char* item)
{
	listbox->insertItem(item);
	listbox->setCurrentItem(listbox->count() - 1);
	listbox->centerCurrentItem();
}
