/* NMM - Network-Integrated Multimedia Middleware
 *
 * Copyright (C) 2006
 *               Motama GmbH, Saarbruecken, Germany
 *
 * Maintainer: Bernhard Fuchshumer <fub@motama.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; version 2
 * of the License only.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 */


#include "backend.h"
#include "mediaobject.h"
#include "avcapture.h"
#include "bytestream.h"
#include "audiopath.h"
#include "audioeffect.h"
#include "audiooutput.h"
#include "audiodataoutput.h"

#include "videopath.h"
#include "videoeffect.h"
#include "videodataoutput.h"

#include <kgenericfactory.h>
#include "volumefadereffect.h"

//nmm specific
#include <nmm/utils/NamedObject.hpp>
#include <nmm/base/ProxyApplication.hpp>

#include <iostream>
#include <QSet>
#include <QVariant>

typedef KGenericFactory<Phonon::nmm::Backend, QObject> NmmBackendFactory;
K_EXPORT_COMPONENT_FACTORY( phonon_nmm, NmmBackendFactory( "nmm" ) )

namespace Phonon
{
namespace nmm
{

Backend::Backend( QObject* parent, const QStringList& )
	: QObject( parent ), m_initialized(false)
{
	kDebug() << k_funcinfo << endl;
	// disable all debug output (error, warning, message, debug)
    
    QString nmmDebug(getenv( "PHONON_DEBUG_NMM" ));
    if (! nmmDebug.isEmpty())
    {
        NamedObject::getGlobalInstance().setErrorStream(&std::cout, NamedObject::ALL_LEVELS);
 	    NamedObject::getGlobalInstance().setWarningStream(&std::cout, NamedObject::ALL_LEVELS);
 	    NamedObject::getGlobalInstance().setMessageStream(&std::cout, NamedObject::ALL_LEVELS);
 	    NamedObject::getGlobalInstance().setDebugStream(&std::cout, NamedObject::ALL_LEVELS);
    }
    else
    {
        NamedObject::getGlobalInstance().setErrorStream(0, NamedObject::ALL_LEVELS);
        NamedObject::getGlobalInstance().setWarningStream(0, NamedObject::ALL_LEVELS);
        NamedObject::getGlobalInstance().setMessageStream(0, NamedObject::ALL_LEVELS);
        NamedObject::getGlobalInstance().setDebugStream(0, NamedObject::ALL_LEVELS);
    }
	try
	{
		m_app = NMM::ProxyApplication::getApplication(0, 0);
	}
	catch(...)
	{
		kError() << "Unusable NMM Backend because no NMMApplication object could be created.";
		// TODO provide for the backend to announce to the frontend that
		// it's useless and may be discarded so that the frontend and
		// try to use the next backend.
		return;
	}
	m_initialized = true;

	//TODO maybe load infos about backend capabilities(e.g. supported filetypes, capture devices, ...) here.
}

Backend::~Backend()
{
	delete m_app;
	m_app = 0;
}

QObject* Backend::createObject0(BackendInterface::Class0 c, QObject *parent)
{
    switch (c) {
        case MediaObjectClass:
            return new MediaObject(this, parent);
        case MediaQueueClass:
            return 0;
        case AvCaptureClass:
            return new AvCapture(this, parent);
        case ByteStreamClass:
            return new ByteStream(this, parent);
        case AudioPathClass:
            return new AudioPath(parent);
        case VolumeFaderEffectClass:
            return new VolumeFaderEffect(parent);
        case AudioOutputClass:
            return new AudioOutput(this, parent);
        case AudioDataOutputClass:
            return new AudioDataOutput(parent);
        case VisualizationClass:
            return 0;
        case VideoPathClass:
            return new VideoPath(parent);
        case BrightnessControlClass:
            return 0;
        case VideoDataOutputClass:
            return new VideoDataOutput(parent);
    }
    return 0;
}

QObject* Backend::createObject1(BackendInterface::Class1 c, QObject *parent, QVariant arg1)
{
    switch (c) {
        case AudioEffectClass:
            return new AudioEffect(arg1.toInt(), parent);
        case VideoEffectClass:
            return new VideoEffect(arg1.toInt(), parent);
    }
    return 0;
}

bool Backend::supportsVideo() const
{
	return true;
}

bool Backend::supportsOSD() const
{
	return false;
}

bool Backend::supportsFourcc( quint32 fourcc ) const
{
	switch( fourcc )
	{
		//TODO
		// return true for supported YUV and RGB formats
	}
	return false;
}

bool Backend::supportsSubtitles() const
{
	return false;
}

QStringList Backend::knownMimeTypes() const
{
	if( m_supportedMimeTypes.isEmpty() )
		const_cast<Backend*>( this )->m_supportedMimeTypes
			<< QLatin1String( "audio/x-vorbis+ogg" )
			<< QLatin1String( "audio/mpeg" )
			<< QLatin1String( "audio/x-wav" )
			<< QLatin1String( "video/x-ogm+ogg" );
//TODO add all supported types. load them dynamically from serverregistry?!!
	return m_supportedMimeTypes;
}

QSet<int> Backend::objectDescriptionIndexes( ObjectDescriptionType type ) const
{
	//TODO
	QSet<int> set;
	switch( type )
	{
		case Phonon::AudioOutputDeviceType:
			set << 10000 << 10001 << 10002;
			break;
		case Phonon::AudioCaptureDeviceType:
			//TODO in case this only reflects the backend capabilities, maybe ask serverregistry
			set << 20000 << 20001;
			break;
		case Phonon::VideoOutputDeviceType:
			set << 40000 << 40001 << 40002 << 40003;
			break;
		case Phonon::VideoCaptureDeviceType:
			set << 30000 << 30001;
			break;
		case Phonon::VisualizationType:
			break;
		case Phonon::AudioCodecType:
			break;
		case Phonon::VideoCodecType:
			break;
		case Phonon::ContainerFormatType:
			break;
		case Phonon::AudioEffectType:
			set << 0x7F000001;
			break;
		case Phonon::VideoEffectType:
			set << 0x7E000001;
			break;
	}
	return set;
}

QHash<QByteArray, QVariant> Backend::objectDescriptionProperties(ObjectDescriptionType type, int index) const
{
    QHash<QByteArray, QVariant> ret;
    switch (type) {
        case Phonon::AudioOutputDeviceType:
            switch (index) {
                case 10000:
                    ret.insert("name", QLatin1String("OSS"));
                    break;
                case 10001:
                    ret.insert("name", QLatin1String("ALSA 'default'"));
                    break;
                case 10002:
                    ret.insert("name", QLatin1String("ALSA 'intel'"));
                    break;
            }
            break;
        case Phonon::AudioCaptureDeviceType:
            switch (index) {
                case 20000:
                    ret.insert("name", QLatin1String("Soundcard"));
                    ret.insert("description", QLatin1String("first description"));
                    break;
                case 20001:
                    ret.insert("name", QLatin1String("DV"));
                    ret.insert("description", QLatin1String("second description"));
                    break;
            }
            break;
        case Phonon::VideoOutputDeviceType:
            switch (index) {
                case 40000:
                    ret.insert("name", QLatin1String("XVideo"));
                    break;
                case 40001:
                    ret.insert("name", QLatin1String("XShm"));
                    break;
                case 40002:
                    ret.insert("name", QLatin1String("X11"));
                    break;
                case 40003:
                    ret.insert("name", QLatin1String("SDL"));
                    break;
            }
            break;
        case Phonon::VideoCaptureDeviceType:
            switch (index) {
                case 30000:
                    ret.insert("name", QLatin1String("USB Webcam"));
                    ret.insert("description", QLatin1String("first description"));
                    break;
                case 30001:
                    ret.insert("name", QLatin1String("DV"));
                    ret.insert("description", QLatin1String("second description"));
                    break;
            }
            break;
        case Phonon::VisualizationType:
            break;
        case Phonon::AudioCodecType:
            break;
        case Phonon::VideoCodecType:
            break;
        case Phonon::ContainerFormatType:
            break;
        case Phonon::AudioEffectType:
            switch (index)
            {
                case 0x7F000001:
                    ret.insert("name", QLatin1String("Delay"));
                    ret.insert("description", QLatin1String("Simple delay effect with time, feedback and level controls."));
                    break;
            }
            break;
        case Phonon::VideoEffectType:
            switch (index)
            {
                case 0x7E000001:
                    ret.insert("name", QLatin1String("VideoEffect1"));
                    ret.insert("description", QLatin1String("Description 1"));
                    break;
            }
            break;
    }
    return ret;
}

const char* Backend::uiLibrary() const
{
	return "phonon_nmmui";
}

void Backend::freeSoundcardDevices()
{
	//TODO
}

ClientRegistry& Backend::getRegistry()
{
	return m_app->getRegistry();
}

NMM::INode* Backend::requestNode( NMM::NodeDescription nd_descr)
{
    kDebug()<< k_funcinfo << endl;
    NMM::INode* inode=0;
    list<NMM::Response> node_response;
    NMM::ClientRegistry& registry = m_app->getRegistry();
    {
        NMM::RegistryLock lock( registry );
        node_response = registry.initRequest( nd_descr );
        if( !node_response.empty() )
        {
            inode = registry.requestNode( node_response.front(), &nd_descr );
            if( !inode )
            {
                kError()<<"Requested node could not be created"<<endl;
                return 0;
            }
            else
            {
                return inode;
            }

        }
        else
        {
            kError()<<"Registry returned no nodes"<<endl;
            return 0;
        }

    }
}

}}


#include "backend.moc"
// vim: sw=4 ts=4 tw=80 et
