/*-*-c++-*-
 * $Id: cchildmanagerbase.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"

#ifndef WIN32
#include <dlfcn.h>
#endif

#define __CCHILD_INTERNAL
#include "cchildimplementation.h"
#include "cchildmanagerbase.h"

#include <qdir.h>
#include <qdialog.h>
#include <qregexp.h>
#include <qapplication.h>


CChildPlugin::CChildPlugin()
 : CChildImplementation()
 , impl(0)
{
}

CChildPlugin::~CChildPlugin() {
	if (impl)
		Unload();
}

bool
CChildPlugin::Load() {
	plugin_header_t *ph;

	if (impl)
		return true;
	if (librarypath.isEmpty())
		return false;
#ifdef WIN32
	HINSTANCE lh;
	// LoadLibrary insists on backslashes ...
	QString tmp = librarypath;
	tmp.replace(QRegExp("/"), "\\");
	if (!(lh = LoadLibrary((LPCTSTR)tmp)))
		return false;
	ph = (plugin_header_t *)GetProcAddress(lh, PLUGIN_STRUCT_NAME_STR);
#else
	void *lh;

	if (!(lh = dlopen((const char *)librarypath, RTLD_NOW|RTLD_LOCAL)))
		return false;
	ph = (plugin_header_t *)dlsym(lh, PLUGIN_STRUCT_NAME_STR);
#endif
	if ((!ph) || (ph->magic != PLUGIN_MAGIC) ||
	    (!ph->factory) || (!(impl = ph->factory())) ) {
#ifdef WIN32
		FreeLibrary(lh);
#else
		dlclose(lh);
#endif
		return false;
	}
	libhandle = lh;
	connect(impl, SIGNAL(sigChildDied()), this, SIGNAL(sigChildDied()));
	connect(impl, SIGNAL(sigChildStarted()), this, SIGNAL(sigChildStarted()));
	connect(impl, SIGNAL(sigBusy()), this, SIGNAL(sigBusy()));
	connect(impl, SIGNAL(sigStdout(QString)), this,	SIGNAL(sigStdout(QString)));
	connect(impl, SIGNAL(sigStderr(QString)), this,	SIGNAL(sigStderr(QString)));
	return true;
}

bool
CChildPlugin::Unload() {
	disconnect(impl, SIGNAL(sigChildDied()), this, SIGNAL(sigChildDied()));
	disconnect(impl, SIGNAL(sigChildStarted()), this, SIGNAL(sigChildStarted()));
	disconnect(impl, SIGNAL(sigBusy()), this, SIGNAL(sigBusy()));
	disconnect(impl, SIGNAL(sigStdout(QString)), this,	SIGNAL(sigStdout(QString)));
	disconnect(impl, SIGNAL(sigStderr(QString)), this,	SIGNAL(sigStderr(QString)));
#ifdef WIN32
	FreeLibrary(libhandle);
#else
	dlclose(libhandle);
#endif
	impl = 0;
	return true;
}

QString
CChildPlugin::Name() {
	return name;
}

QString
CChildPlugin::Version() {
	return version;
}

QString
CChildPlugin::Description() {
	return description;
}

QString
CChildPlugin::Author() {
	return author;
}

QString
CChildPlugin::Copyright() {
	return copyright;
}

bool
CChildPlugin::isConfigurable() {
	return configurable;
}

bool
CChildPlugin::writeStdin(QString s) {
	if (!impl) {
		if (!Load())
			return false;
	}
	return impl->writeStdin(s);
}

bool
CChildPlugin::valid() {
	if (!impl) {
		if (!Load())
			return false;
	}
	return impl->valid();
}

void
CChildPlugin::forkChild() {
	if (!impl) {
		if (!Load())
			return;
	}
	impl->forkChild();
}

bool
CChildPlugin::running() {
	if (!impl) {
		if (!Load())
			return false;
	}
	return impl->running();
}

void
CChildPlugin::killChild(int sig) {
	if (!impl) {
		if (!Load())
			return;
	}
	impl->killChild(sig);
}

int
CChildPlugin::configure(QWidget *w) {
	if (!impl) {
		if (!Load())
			return QDialog::Rejected;
	}
	return impl->configure(w);
}

cfgMap
CChildPlugin::getConfigValues() {
	if (!impl) {
		if (!Load())
			return *(new cfgMap());
	}
	return impl->getConfigValues();
}

void
CChildPlugin::setConfigValues(cfgMap v) {
	if (!impl) {
		if (!Load())
			return;
	}
	impl->setConfigValues(v);
}

bool
CChildPlugin::configured() {
	if (!impl) {
		if (!Load())
			return false;
	}
	return impl->configured();
}


CChildManagerBase::CChildManagerBase()
{
}


CChildManagerBase::~CChildManagerBase()
{
}

QString
CChildManagerBase::getPluginLibrary(CChildPlugin *plugin) {
	return plugin->librarypath;
}

TPluginList *
CChildManagerBase::findPlugins(const QString& dirname)
{
	QDir d(dirname);

	//d.setFilter(QDir::Files|QDir::Readable|QDir::Executable);
	d.setNameFilter("*.so;*.dll");

	const QFileInfoList *list = d.entryInfoList();
	if (!list)
	    return new TPluginList();
	QFileInfoListIterator it(*list);
	QFileInfo *fi;

	TPluginList *plist = new TPluginList();

	while ((fi = it.current())) {
		plugin_header_t *ph;

#ifdef WIN32
		HINSTANCE lh;
		// LoadLibrary insists on backslashes ...
		QString tmp = fi->absFilePath();
		tmp.replace(QRegExp("/"), "\\");
		if (!(lh = LoadLibrary((LPCTSTR)tmp))) {
		    	++it;
			continue;
		}
		ph = (plugin_header_t *)GetProcAddress(lh, PLUGIN_STRUCT_NAME_STR);
#else
		void *lh;
		if (!(lh = dlopen(fi->absFilePath(), RTLD_NOW))) {
			fprintf(stderr, "%s: %s\n",
				(const char *)fi->absFilePath(), dlerror());
		    	++it;
			continue;
		}
		ph = (plugin_header_t *)dlsym(lh, PLUGIN_STRUCT_NAME_STR);
#endif
		if (ph && (ph->magic == PLUGIN_MAGIC)) {
			CChildPlugin *Plugin = new CChildPlugin();
			Plugin->name = ph->name;
			Plugin->version = ph->version;
			Plugin->author = ph->author;
			Plugin->description = ph->description;
			Plugin->copyright = ph->copyright;
			Plugin->configurable = ph->configurable;
			Plugin->librarypath = fi->absFilePath();
			plist->append(Plugin);
		}
#ifdef WIN32
		FreeLibrary(lh);
#else
		dlclose(lh);
#endif
		++it;
	}
	return plist;
}

void
CChildManagerBase::refreshPlugins(TPluginList &plist, const QString& dirname)
{
	QDir d(dirname);

#ifdef WIN32
	d.setFilter(QDir::Files|QDir::Readable);
	d.setNameFilter("*.dll");
#else
	d.setFilter(QDir::Files|QDir::Readable|QDir::Executable);
	d.setNameFilter("*.so");
#endif

	const QFileInfoList *list = d.entryInfoList();
	if (!list)
	    return;
	QFileInfoListIterator it(*list);
	QFileInfo *fi;

	while ((fi = it.current())) {
		plugin_header_t *ph;
		QString tmp = fi->absFilePath();
		bool found = false;

		CChildPlugin *c;
		for (c = plist.first(); c != 0; c = plist.next()) {
			if (c->librarypath == tmp)
				found = true;
		}
		if (!found) {
#ifdef WIN32
			HINSTANCE lh;
			// LoadLibrary insists on backslashes ...
			tmp.replace(QRegExp("/"), "\\");
			if (!(lh = LoadLibrary((LPCTSTR)tmp))) {
		    		++it;
				continue;
			}
			ph = (plugin_header_t *)GetProcAddress(lh, PLUGIN_STRUCT_NAME_STR);
#else
			void *lh;
			if (!(lh = dlopen(tmp, RTLD_NOW))) {
			    	fprintf(stderr, "%s: %s\n",(const char *)tmp, dlerror());
			    	++it;
				continue;
			}
			ph = (plugin_header_t *)dlsym(lh, PLUGIN_STRUCT_NAME_STR);
#endif
			if (ph && (ph->magic == PLUGIN_MAGIC)) {
				CChildPlugin *Plugin = new CChildPlugin;
				Plugin->name = ph->name;
				Plugin->version = ph->version;
				Plugin->author = ph->author;
				Plugin->description = ph->description;
				Plugin->copyright = ph->copyright;
				Plugin->configurable = ph->configurable;
				Plugin->librarypath = fi->absFilePath();
				plist.append(Plugin);
			}
#ifdef WIN32
			FreeLibrary(lh);
#else
			dlclose(lh);
#endif
		}
		++it;
	}
}

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