/*-*-c++-*-
 * $Id: cchildmanager.cpp,v 1.2 2002/04/19 15:24:17 felfert Exp $
 *
 * This file is part of qlcrash, a GUI for the dump-analysis tool lcrash.
 *
 * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
 *
 * Authors:
 * Michael Geselbracht (let@users.sourceforge.net)
 * Fritz Elfert (elfert@de.ibm.com)
 * Michael Holzheu (holzheu@de.ibm.com)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version. See the file COPYING for more
 * information.
 */
#include "osdep.h"
#include "cchildmanager.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "crashtypes.h"
#include "cconfigmanager.h"
#include "qlcrashdoc.h"
#include "resourceadapter.h"

#include <qlayout.h>
#include <qpushbutton.h>
#include <qlabel.h>
#include <qlistbox.h>
#include <qdialog.h>
#include <qmessagebox.h>
#include <qpixmap.h>
#include <qfileinfo.h>
#include <qapplication.h>

CChildManager::CChildManager(QObject *parent)
	: QObject(parent)
	, CChildManagerBase()
{
	activePlugin = 0;
	pluginsChecked = false;
	gotStderr = false;
	childDied = false;
	collectStdout = 0;
	collectStderr = 0;

	if (!parent->isA("QLcrashDoc"))
		qFatal("Parent of CChildManager must be a QLcrashDoc instance\n");
	doc = (QLcrashDoc *)parent;

	aPixmap = Resource::getBitmap(IDR_PNG3);
	cPixmap = Resource::getBitmap(IDR_PNG4);
	uPixmap = Resource::getBitmap(IDR_PNG5);
	setupDialog = new QDialog(0, "plugin_dialog", true);
	setupDialog->setCaption(stdCaption(tr("Plugin setup")));
	setupDialog->setIcon(Resource::getBitmap(IDR_PNG7));
	QGridLayout *gl = new QGridLayout(setupDialog, 2, 7, 5);
	gl->addWidget(new QLabel(tr("Availabe Plugins:"), setupDialog), 0, 0);
	pluginListBox = new QListBox(setupDialog);
	gl->addMultiCellWidget(pluginListBox, 1, 4, 0, 0);

	refreshButton  = new QPushButton(tr("Refresh List"), setupDialog);
	aboutButton    = new QPushButton(tr("About"), setupDialog);
	activateButton = new QPushButton(tr("Activate"), setupDialog);
	configButton   = new QPushButton(tr("Configure"), setupDialog);

	cancelButton   = new QPushButton(tr("Cancel"), setupDialog);
	okButton       = new QPushButton(tr("OK"), setupDialog);

	gl->addWidget(refreshButton,  1, 1, AlignTop);
	gl->addWidget(aboutButton,    2, 1, AlignTop);
	gl->addWidget(activateButton, 3, 1, AlignTop);
	gl->addWidget(configButton,   4, 1, AlignTop);

	QFrame *separator = new QFrame(setupDialog);
	separator->setLineWidth(1);
	separator->setMidLineWidth(0);
	separator->setFrameStyle(QFrame::HLine | QFrame::Sunken);
	separator->setMinimumSize(0, 2);
	gl->addMultiCellWidget(separator, 5, 5, 0, 1);

	QBoxLayout *bl = new QHBoxLayout();
	bl->addStretch(10);
	bl->addWidget(okButton);
	bl->addWidget(cancelButton);
	gl->addMultiCellLayout(bl, 6, 6, 0, 1);

	gl->setRowStretch(4, 10);

	connect(okButton, SIGNAL(clicked()), setupDialog, SLOT(accept()));
	connect(cancelButton, SIGNAL(clicked()), setupDialog, SLOT(reject()));
	connect(aboutButton, SIGNAL(clicked()), this, SLOT(slotShowAbout()));
	connect(refreshButton, SIGNAL(clicked()), this, SLOT(slotRefresh()));
	connect(activateButton, SIGNAL(clicked()), this, SLOT(slotActivate()));
	connect(configButton, SIGNAL(clicked()), this, SLOT(slotConfigure()));
	connect(pluginListBox, SIGNAL(clicked(QListBoxItem *)), this,
		SLOT(slotItemClicked(QListBoxItem *)));
}

CChildManager::~CChildManager()
{
}

void
CChildManager::enableButtons(bool _on) {
	aboutButton->setEnabled(_on);
	if (_on) {
		int idx = pluginListBox->currentItem();
		if (plist.at(idx)->isConfigurable()) {
			configButton->setEnabled(true);
			if (plist.at(idx)->configured())
				activateButton->setEnabled(true);
			else
				activateButton->setEnabled(false);
		} else {
			activateButton->setEnabled(true);
			configButton->setEnabled(false);
		}
	} else {
		configButton->setEnabled(false);
		activateButton->setEnabled(_on);
	}
}

void
CChildManager::slotItemClicked(QListBoxItem *) {
	enableButtons(pluginListBox->currentItem() != -1);
}

void
CChildManager::slotActivate() {
	int idx = pluginListBox->currentItem();
	if (idx == -1)
		return;
	if (activePlugin) {
		disconnect(activePlugin, SIGNAL(sigChildDied()), this,
			SLOT(slotChildDied()));
		disconnect(activePlugin, SIGNAL(sigChildStarted()), this,
			SLOT(slotChildStarted()));
		disconnect(activePlugin, SIGNAL(sigBusy()), this, SLOT(slotBusy()));
		disconnect(activePlugin, SIGNAL(sigStdout(QString)), this,
			SLOT(slotStdout(QString)));
		disconnect(activePlugin, SIGNAL(sigStderr(QString)), this,
			SLOT(slotStderr(QString)));
		activePlugin = 0;
		for (unsigned int i = 0; i < pluginListBox->count(); i++)
			if (plist.at(i)->activated() && ((unsigned)idx != i)) {
				plist.at(i)->activate(false);

				pluginListBox->changeItem(cPixmap,
					 pluginListBox->text(i), i);
				break;
			}
	}
	plist.at(idx)->activate(true);
	pluginListBox->changeItem(aPixmap,
				  pluginListBox->text(idx), idx);
	activePlugin = plist.at(idx);
	connect(activePlugin, SIGNAL(sigChildDied()), this,
		SLOT(slotChildDied()));
	connect(activePlugin, SIGNAL(sigChildStarted()), this,
		SLOT(slotChildStarted()));
	connect(activePlugin, SIGNAL(sigBusy()), this, SLOT(slotBusy()));
	connect(activePlugin, SIGNAL(sigStdout(QString)), this,
		SLOT(slotStdout(QString)));
	connect(activePlugin, SIGNAL(sigStderr(QString)), this,
		SLOT(slotStderr(QString)));
}

void
CChildManager::slotBusy()
{
	emit sigBusy(true);
}

void
CChildManager::slotConfigure() {
	int idx = pluginListBox->currentItem();
	if (idx == -1)
		return;
	if (plist.at(idx)->configure(setupDialog) == QDialog::Accepted)
		pluginListBox->changeItem(cPixmap,
					  pluginListBox->text(idx), idx);
}

void
CChildManager::slotRefresh() {
	pluginListBox->clear();
	refreshPlugins(plist, Resource::getPluginDir());

	CChildPlugin *c;
	for (c = plist.first(); c != 0; c = plist.next())
		if (c->configured()) {
			if (c->activated())
				pluginListBox->insertItem(aPixmap, c->Name());
			else
				pluginListBox->insertItem(cPixmap, c->Name());
		} else
			pluginListBox->insertItem(uPixmap, c->Name());
	enableButtons(false);
	pluginListBox->clearSelection();
}

void
CChildManager::slotSetup() {
	slotRefresh();
	int res = setupDialog->exec();
	if (res == QDialog::Accepted) {
		CConfigManager *man = doc->configManager();
		if (activePlugin) {
			QFileInfo fi = getPluginLibrary(activePlugin);
			cfgMap map = activePlugin->getConfigValues();

			man->setItem(CFG_GRP_FILES, CFG_ATT_FILES_PLUGIN, fi.fileName());

			cfgMap::Iterator it;
			for (it = map.begin(); it != map.end(); it++)
				man->setItem(CFG_GRP_PLUGIN, it.key(), it.data());
		} else
			man->setItem(CFG_GRP_FILES, CFG_ATT_FILES_PLUGIN, "none");
	}
}

void
CChildManager::slotShowAbout() {
	int idx = pluginListBox->currentItem();
	if (idx == -1)
		return;
	CChildPlugin *p = plist.at(idx);
	QMessageBox::about(setupDialog,
		stdCaption(tr("About") + p->Name()),
		tr(
			"<QT><TABLE>"
			"<TR><TD><B>Name:</B></TD><TD>%1</TD></TR>"
			"<TR><TD><B>Version:</B></TD><TD>%2</TD></TR>"
			"<TR><TD><B>Description:</B></TD><TD>%3</TD></TR>"
			"<TR><TD><B>Author:</B></TD><TD>%4</TD></TR>"
			"</TABLE><P><B>Copyright:</B><BR/>%5</QT>"
			).arg(p->Name()).arg(p->Version()).arg(p->Description())
			.arg(p->Author()).arg(p->Copyright()
		)
	);
}

// Initial check for preloading a default plugin and setting it up
void
CChildManager::checkPlugins() {
	if (pluginsChecked)
		return;

	pluginsChecked = true;
	CConfigManager *man = doc->configManager();
	QString currentPlugin = man->item(CFG_GRP_FILES, CFG_ATT_FILES_PLUGIN, "none");
	if (currentPlugin.isEmpty() || currentPlugin == "none")
		return;
	refreshPlugins(plist, Resource::getPluginDir());
	CChildPlugin *c;
	for (c = plist.first(); c != 0; c = plist.next()) {
		QFileInfo fi = getPluginLibrary(c);
		if (fi.fileName() == currentPlugin) {
			activePlugin = c;
			cfgMap oldmap = activePlugin->getConfigValues();
			cfgMap newmap;

			cfgMap::Iterator mi;
			for (mi = oldmap.begin(); mi != oldmap.end(); mi++)
				newmap.insert(mi.key(), man->item(CFG_GRP_PLUGIN, mi.key(), mi.data()));
			activePlugin->setConfigValues(newmap);
			activePlugin->activate(true);
			connect(activePlugin, SIGNAL(sigChildDied()), this,
				SLOT(slotChildDied()));
			connect(activePlugin, SIGNAL(sigChildStarted()), this,
				SLOT(slotChildStarted()));
			connect(activePlugin, SIGNAL(sigBusy()), this, SLOT(slotBusy()));
			connect(activePlugin, SIGNAL(sigStdout(QString)), this,
				SLOT(slotStdout(QString)));
			connect(activePlugin, SIGNAL(sigStderr(QString)), this,
				SLOT(slotStderr(QString)));
			break;
		}
	}
}

void
CChildManager::slotChildDied() {
	childDied = true;
	emit sigChildDied();
}

void
CChildManager::slotChildStarted() {
	childDied = false;
	emit sigChildStarted();
}

void
CChildManager::slotStdout(QString s) {
	if (collectStdout) {
		*collectStdout += s;
		if (collectStdout->find(CMD_PROMPT) != -1) {
		    collectStdout = 0;
			emit sigBusy(false);
		}
	} else
		emit sigStdout(s);
}

void
CChildManager::slotStderr(QString s) {
	gotStderr = true;
	if (collectStderr)
		*collectStderr += s;
	else
		emit sigStderr(s);
}

// Child wrappers
bool
CChildManager::command(QString cmd, QString& result, int maxCycle) {
	QString eresult;

	result = "";
	if (activePlugin) {
		collectStdout = &result;
		collectStderr = &eresult;
		gotStderr = false;
		activePlugin->writeStdin(cmd.stripWhiteSpace() + "\n");
		while (collectStdout && !childDied)
			qApp->processEvents(100);
		collectStderr = 0;
		collectStdout = 0;
		if (gotStderr || childDied)
			result = eresult;
		return (!(gotStderr || childDied));
	}
	return false;
}

bool
CChildManager::valid() {
	checkPlugins();
	if (activePlugin)
		return activePlugin->valid();
	else
		return false;
}

void
CChildManager::forkChild() {
	checkPlugins();
	if (activePlugin)
		activePlugin->forkChild();
}

void
CChildManager::setArgs(const QStringList&) {
	checkPlugins();
}

void
CChildManager::killChild(int sig) {
	checkPlugins();
	if (activePlugin)
		activePlugin->killChild(sig);
}

void
CChildManager::setSignalOnTimeout(int sig) {
	checkPlugins();
}

bool
CChildManager::writeStdin(QString s) {
	checkPlugins();
	if (activePlugin)
		return activePlugin->writeStdin(s);
	else
		return false;
}

/*
 * Local variables:
 * c-basic-offset: 8
 * End:
 */

