/*
 *
 * Copyright (C) 2002 George Staikos <staikos@kde.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include <qfile.h>

#include <kdebug.h>
#include <klibloader.h>
#include <kservice.h>
#include <kservicetype.h>
#include <kconfig.h>

#include "channelioformat.h"
#include "pluginfactory.h"
#include "qvmixerplugin.h"
#include "qvmiscplugin.h"
#include "qvosdplugin.h"
#include "qvsrcplugin.h"



int PluginFactory::_upid = 0;


PluginFactory::PluginFactory(QtVision *qtv) : _qtv(qtv) {
	_videoPlugins.setAutoDelete(true);
	_channelPlugins.setAutoDelete(true);
	_mixerPlugins.setAutoDelete(true);
	_miscPlugins.setAutoDelete(true);
	_osdPlugins.setAutoDelete(true);
	_cfg = 0;
	scanForPlugins();
}


PluginFactory::~PluginFactory() {
}



void PluginFactory::scanForPlugins() {
_cfg = new KConfig("qtvisionrc", true);   // hack: no other way to get at this?
				// It's ok since this gets called at startup
				// and we just use it to read from briefly.

_cfg->setGroup("Video Plugins");
_videoPlugins.clear();
KService::List vplugs = KServiceType::offers("QtVision Video Source");
doScan(vplugs, _videoPlugins, PluginDesc::VIDEO);

_cfg->setGroup("Channel Plugins");
_channelPlugins.clear();
KService::List cplugs = KServiceType::offers("QtVision Channel Format");
doScan(cplugs, _channelPlugins, PluginDesc::CHANNEL);

_cfg->setGroup("Mixer Plugins");
_mixerPlugins.clear();
KService::List mplugs = KServiceType::offers("QtVision Audio Mixer");
doScan(mplugs, _mixerPlugins, PluginDesc::MIXER);

_cfg->setGroup("Misc Plugins");
_osdPlugins.clear();
KService::List oplugs = KServiceType::offers("QtVision OSD");
doScan(oplugs, _osdPlugins, PluginDesc::OSD);
_miscPlugins.clear();
KService::List miplugs = KServiceType::offers("QtVision Misc");
doScan(miplugs, _miscPlugins, PluginDesc::MISC);

delete _cfg;
_cfg = 0;
}

void PluginFactory::doScan(KService::List& plugs, QPtrList<PluginDesc>& list,
                           PluginDesc::PluginType type) {
	for (KService::List::ConstIterator it = plugs.begin();
					    it != plugs.end();
						  	  ++it) {
		KService::Ptr service = *it;
		PluginDesc *x = new PluginDesc;
		x->id = _upid++;
		x->name = service->property("Name").toString();
		x->author = service->property("X-QV-Plugin-Author").toString();
		x->comment = service->property("Comment").toString();
		x->icon = service->property("Icon").toString();
		x->lib = service->property("X-QV-Plugin-Library").toString();
		x->factory = service->property("X-QV-Plugin-Factory").toString();
		x->service = service;
		x->configurable = service->property("X-QV-Configurable").toBool();
		x->type = type;
		if (x->factory.isEmpty())
			x->factory = x->lib;
		if (!x->factory.startsWith("create_"))
			x->factory = "create_" + x->factory;

		if (_cfg->hasKey(x->name+"-"+x->author))
			x->enabled = _cfg->readBoolEntry(x->name+"-"+x->author);
		else x->enabled = service->property("X-QV-Default-Enabled").toBool();

		list.append(x);
	}
}


QPtrList<PluginDesc>& PluginFactory::videoPlugins() {
	return _videoPlugins;
}


QPtrList<PluginDesc>& PluginFactory::channelPlugins() {
	return _channelPlugins;
}


QPtrList<PluginDesc>& PluginFactory::miscPlugins() {
	return _miscPlugins;
}


QPtrList<PluginDesc>& PluginFactory::mixerPlugins() {
	return _mixerPlugins;
}


QPtrList<PluginDesc>& PluginFactory::osdPlugins() {
	return _osdPlugins;
}

ChannelIOFormat* PluginFactory::getChannelPlugin(const PluginDesc *plugin) {
KLibLoader *loader = KLibLoader::self();
ChannelIOFormat* module = NULL;

if (!plugin || plugin->type != PluginDesc::CHANNEL)
	return NULL;

if (!plugin->enabled)
	return NULL;

KLibrary *lib = loader->library(QFile::encodeName(QString("qtvision_")+plugin->lib));

if (lib) {
	void *create = lib->symbol(QFile::encodeName(plugin->factory));
	if (create) {
		ChannelIOFormat* (*func)();
		func = (ChannelIOFormat* (*)()) create;
		module = func();
		if (module) {
			module->_qtv = _qtv;
			module->_description = *plugin;
			return module;
		}
	}
} else {
	kdDebug() << "Error loading library qtvision_" << plugin->lib << endl;
}
return NULL;
}


QVMiscPlugin* PluginFactory::getMiscPlugin(const PluginDesc *plugin, QWidget *w) {
KLibLoader *loader = KLibLoader::self();
QVMiscPlugin* module = NULL;

if (!plugin || plugin->type != PluginDesc::MISC)
	return NULL;

if (!plugin->enabled)
	return NULL;

KLibrary *lib = loader->library(QFile::encodeName(QString("qtvision_")+plugin->lib));

if (lib) {
	void *create = lib->symbol(QFile::encodeName(plugin->factory));
	if (create) {
		QVMiscPlugin* (*func)(QtVision*,QWidget*);
		func = (QVMiscPlugin* (*)(QtVision*,QWidget*)) create;
		module = func(_qtv,w);
		if (module) {
			module->_description = *plugin;
			return module;
		}
	}
} else {
	kdDebug() << "Error loading library qtvision_" << plugin->lib << endl;
}
return NULL;
}


QVSourcePlugin* PluginFactory::getVideoPlugin(const PluginDesc *plugin, QWidget* w) {
KLibLoader *loader = KLibLoader::self();
QVSourcePlugin* module = NULL;

if (!plugin || plugin->type != PluginDesc::VIDEO)
	return NULL;

if (!plugin->enabled)
	return NULL;

KLibrary *lib = loader->library(QFile::encodeName(QString("qtvision_")+plugin->lib));

if (lib) {
	void *create = lib->symbol(QFile::encodeName(plugin->factory));
	if (create) {
		QVSourcePlugin* (*func)(QtVision*,QWidget*);
		func = (QVSourcePlugin* (*)(QtVision*,QWidget*)) create;
		module = func(_qtv, w);
		if (module) {
			module->_description = *plugin;
			return module;
		}
	}
} else {
	kdDebug() << "Error loading library qtvision_" << plugin->lib << endl;
}
return NULL;
}


QVMixerPlugin* PluginFactory::getMixerPlugin(const PluginDesc *plugin) {
KLibLoader *loader = KLibLoader::self();
QVMixerPlugin* module = NULL;

    if (!plugin || plugin->type != PluginDesc::MIXER) return NULL;
    if (!plugin->enabled)
        return NULL;

KLibrary *lib = loader->library(QFile::encodeName(QString("qtvision_")+plugin->lib));

if (lib) {
	void *create = lib->symbol(QFile::encodeName(plugin->factory));
	if (create) {
		QVMixerPlugin* (*func)(QtVision*);
		func = (QVMixerPlugin* (*)(QtVision*)) create;
		module = func(_qtv);
		if (module) {
			module->_description = *plugin;
			return module;
		}
	}
} else {
	kdDebug() << "Error loading library qtvision_" << plugin->lib << endl;
}
return 0;
}


QVOSDPlugin* PluginFactory::getOSDPlugin(const PluginDesc *plugin, QWidget *w) {
KLibLoader *loader = KLibLoader::self();
QVOSDPlugin* module = NULL;

if (!plugin || plugin->type != PluginDesc::OSD) return NULL;

if (!plugin->enabled)
	return NULL;

KLibrary *lib = loader->library(QFile::encodeName(QString("qtvision_")+plugin->lib));

if (lib) {
	void *create = lib->symbol(QFile::encodeName(plugin->factory));
	if (create) {
		QVOSDPlugin* (*func)(QtVision*,QWidget*);
		func = (QVOSDPlugin* (*)(QtVision*,QWidget*)) create;
		module = func(_qtv, w);
		if (module) {
			module->_description = *plugin;
			return module;
		}
	}
} else {
	kdDebug() << "Error loading library qtvision_" << plugin->lib << endl;
}
return NULL;
}

PluginDesc::PluginDesc(const PluginDesc& copy) {
	id = copy.id;
	name = copy.name;
	author = copy.author;
	comment = copy.comment;
	icon = copy.icon;
	lib = copy.lib;
	factory = copy.factory;
	type = copy.type;
	configurable = copy.configurable;
	enabled = copy.enabled;
}

PluginDesc::PluginDesc() {
	id = -1;
	type = UNKNOWN;
	configurable = false;
	enabled = true;
}


int operator>(const PluginDesc& l, const PluginDesc& r) {
   return (l.id > r.id) ? 1 : 0;
}

int operator<(const PluginDesc& l, const PluginDesc& r) {
   return (l.id < r.id) ? 1 : 0;
}

int operator==(const PluginDesc& l, const PluginDesc& r) {
   return (l.id == r.id) ? 1 : 0;
}

int operator!=(const PluginDesc& l, const PluginDesc& r) {
   return (l.id == r.id) ? 0 : 1;
}

