/*  This file is part of the KDE project
    Copyright (C) 2006 Matthias Kretz <kretz@kde.org>
    Copyright (C) 2006-2007 Tim Beaulen <tbscope@gmail.com>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    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., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

#include "backend.h"
#include "mediaobject.h"
//#include "mediaqueue.h"
//#include "avcapture.h"
//#include "bytestream.h"
//#include "audiopath.h"
//#include "audioeffect.h"
//#include "audiooutput.h"
//#include "audiodataoutput.h"
//#include "visualization.h"
//#include "videopath.h"
//#include "videoeffect.h"
//#include "brightnesscontrol.h"
//#include "volumefadereffect.h"
//#include "videodataoutput.h"
//#include "pipeline.h"
//#include "videowidget.h"

#include "qbtgstreamer/qbtgstreamer.h"
#include "qbtgstreamer/qbtgstreamerelement.h"
#include "qbtgstreamer/qbtgstreamerpipeline.h"
#include "qbtgstreamer/qbtgstreamercapabilities.h"
#include "qbtgstreamer/qbtgstreamerpluginfeature.h"
#include "qbtgstreamer/qbtgstreamerregistry.h"
#include "qbtgstreamer/qbtgstreamerdatapointer.h"
#include "qbtgstreamer/qbtgstreamerelementfactory.h"
#include "qbtgstreamer/qbtgstreamerbus.h"
#include "qbtgstreamer/qbtgstreamermessage.h"
#include "qbtgstreamer/qbtgstreamerstructure.h"
#include "qbtgstreamer/qbtgstreamererror.h"
#include "qbtgstreamer/coreplugins/qbtgstreamertypefindelement.h"

#include <QSet>
#include <QVariant>
#include <QtDBus/QtDBus>
#include <QTime>
#include <QDomDocument>
#include <QDomElement>
#include <QFile>
#include <QTextStream>
#include <QStringList>

#include <kdebug.h>
#include <klocale.h>
#include <kpluginfactory.h>
#include <kpluginloader.h>

#include <phonon/audiodevice.h>
#include <phonon/audiodeviceenumerator.h>

K_PLUGIN_FACTORY(GStreamerBackendFactory, registerPlugin<Phonon::GStreamer::Backend>();)
K_EXPORT_PLUGIN(GStreamerBackendFactory("gstreamerbackend"))

namespace Phonon
{
namespace GStreamer
{

/* The GStreamer backend constructor.

   This will create a new private backend too, which holds the majority of the background work.
   Note that this backend doesn't make use of the arguments.
*/
Backend::Backend(QObject *parent, const QVariantList &args)
    : QObject(parent),
      d(new GstBackendPrivate)
{
    Q_UNUSED(args)

    /* The private backend class needs to know about the configuration too.
    */
    d->setConfig(GStreamerBackendFactory::componentData().config());

    /* Give the backend a unique object name.
       The name is constructed like this:
           The text Backend_
           + the time it was created.
    */
    QString backendObjectName = "Backend_" + QTime::currentTime().toString("hhmmss");
    setObjectName(backendObjectName); 

    /* Set some information properties for the GStreamer Backend
    */
    setProperty("identifier",     QLatin1String("phonon_gstreamer"));
    setProperty("backendName",    QLatin1String("GStreamer"));
    setProperty("backendComment", i18n("Phonon GStreamer Backend"));
    setProperty("backendVersion", QLatin1String("0.1"));
    setProperty("backendIcon",    QLatin1String("phonon-gstreamer"));
    setProperty("backendWebsite", QLatin1String("http://multimedia.kde.org/"));

    /* Important: In order to use the GStreamer libarary, it needs to be initialised.
       TODO: See if it's necessary to pass argc and argv.
    */
    QbtGStreamer::init(0, 0);

    /* Create a new debugging dbus interface for the GStreamer backend.
       TODO: Make the dbus debugging selectable at compile time.
       TODO: Move this to the private class.
    */
    m_phononGStreamerBackendDebuggerDBusIface = new PhononGStreamerBackendDebuggerDBusIface;

    /* Display a debug message with some information about the used GStreamer library
    */
    debugmessage(0, 0, objectName(), "Phonon GStreamer Backend 0.1 - Using " + QbtGStreamer::versionString());

    /* The rest of the backend is initialised in the private class.
    */
    d->initBackend(backendObjectName);
}

/* The GStreamer backend deconstructor.
*/
Backend::~Backend()
{
    debugmessage(0, 1, objectName(), "Destructing Phonon GStreamer Backend");
    delete d;
    delete m_phononGStreamerBackendDebuggerDBusIface;
}

QObject* Backend::createObject(BackendInterface::Class c, QObject *parent, const QList<QVariant> &args)
{
    /* No parentless children.
    */
    if(!parent)
        parent = this;

    switch (c) {
    case MediaObjectClass:
    {
        MediaObject *newMediaObject = new MediaObject(this, parent);
        d->addMediaObject(newMediaObject);
        return newMediaObject;
    }
    case VolumeFaderEffectClass:
        return 0;
    case AudioOutputClass:
        return 0;//return new AudioOutput(parent);
    case AudioDataOutputClass:
        return 0;//return new AudioDataOutput(parent);
    case VisualizationClass:
        return 0;
    case VideoDataOutputClass:
        return 0;
    case EffectClass:
        return 0;
    case VideoWidgetClass:
        return 0;//return new VideoWidget(qobject_cast<QWidget *>(parent));
    }

    return 0;
}

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

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

bool Backend::supportsFourcc(quint32 fourcc) const
{
    switch (fourcc) {
    case 0x00000000:
        return true;
    default:
        return false;
    }
}

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

QStringList Backend::availableMimeTypes() 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" );
    }

    return m_supportedMimeTypes;
}

QSet<int> Backend::objectDescriptionIndexes(ObjectDescriptionType type) const
{
    QSet<int> set;

    switch (type) {
    case Phonon::AudioOutputDeviceType:
        return d->audioOutputIndexes();
        break;
    /*case Phonon::AudioCaptureDeviceType:
    {
        QList<AudioDevice> devlist = AudioDeviceEnumerator::availableCaptureDevices();
        foreach (AudioDevice dev, devlist) {
            set << dev.index();
        }
        break;
    }
    case Phonon::VideoOutputDeviceType:
        set << 40000 << 40001 << 40002 << 40003;
        break;
    case Phonon::VideoCaptureDeviceType:
        set << 30000 << 30001;
        break;
    case Phonon::VisualizationType:
    case Phonon::AudioCodecType:
    case Phonon::VideoCodecType:
    case Phonon::ContainerFormatType:
        break;*/
    case Phonon::EffectType:
        set << 0x7F000001;
        break;
    }

    return set;
}

QHash<QByteArray, QVariant> Backend::objectDescriptionProperties(ObjectDescriptionType type, int index) const
{
    QHash<QByteArray, QVariant> ret;

    switch (type) {
    case Phonon::AudioOutputDeviceType:
    {
        ret.insert("name", d->audioOutputName(index));
        ret.insert("description", d->audioOutputDescription(index));
        QString icon = d->audioOutputIcon(index);

        if (!icon.isEmpty()) {
            ret.insert("icon", icon);
        }
    
        ret.insert("available", d->audioOutputAvailable(index));
        break;
    }
/*
    case Phonon::AudioCaptureDeviceType:
    {
        QList<AudioDevice> devlist = AudioDeviceEnumerator::availableCaptureDevices();
            
        foreach (AudioDevice dev, devlist) {
            if (dev.index() == index) {
                ret.insert("name", dev.cardName());
                
                 switch (dev.driver()) {
                 case Solid::AudioInterface::Alsa:
                     ret.insert("description", i18n("ALSA Capture Device"));
                     break;
                 case Solid::AudioInterface::OpenSoundSystem:
                     ret.insert("description", i18n("OSS Capture Device"));
                     break;
                 case Solid::AudioInterface::UnknownAudioDriver:
                     break;
                 }

                 ret.insert("icon", dev.iconName());
                 ret.insert("available", dev.isAvailable());
                 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::EffectType:
        switch (index) {
        case 0x7F000001:
            ret.insert("name", QLatin1String("Delay"));
            ret.insert("description", QLatin1String("Simple delay effect with time, feedback and level controls."));
            break;
        }
        break;
    }

    return ret;
}

bool Backend::startConnectionChange(QSet<QObject *> nodes)
{
    Q_UNUSED(nodes);
    // there's nothing we can do but hope the connection changes won't take too long so that buffers
    // would underrun. But we should be pretty safe the way xine works by not doing anything here.
    return true;
}

bool Backend::connectNodes(QObject *_source, QObject *_sink)
{
    // Looks very similar to gstreamer (at first sight) so maybe relay directly to gstreamer.
    return true;
}

bool Backend::disconnectNodes(QObject *_source, QObject *_sink)
{
    // Here too, check if it can be done by gstreamer directly.
    return true;
}

bool Backend::endConnectionChange(QSet<QObject *> nodes)
{

    return true;
}

/* TODO: Move the code below to the mediaobject class.
*/

#if 0
void Backend::tryToPlug(QbtGStreamerPad *pad, QbtGStreamerCapabilities *caps)
{
    Q_UNUSED(pad)
    /* don't plug if we're already plugged*/
    QbtGStreamerPad *audioPad = m_audioSink->pad("sink");
    if (audioPad->linked()) {
        kDebug(611) << "Already linked!" << endl;
        return;
    }

    QbtGStreamerCapabilities *audioCapabilities = audioPad->capabilities();
    QbtGStreamerCapabilities *res = caps->intersect(audioCapabilities);

    if (res && !res->isEmpty()) {
         kDebug(611) << "Found pad to link to audiosink - plugging is now done" << endl;
    }

    delete audioCapabilities;
    delete res;
}
#endif

/* TODO: Is this function needed?
*/
void Backend::freeSoundcardDevices()
{
}

/* Print debug messages.

   Type:	0 = Information
		1 = Warning
		2 = Error

   Level:	0 = Creation and destruction of objects + Errors and warnings
		1
		2
		3
		4 = Full debug

    Objectname: The name of the object which made the debugmessage

    Message:	The actual message

    This function passes the information through to the private class.
*/
void Backend::debugmessage(int type, int level, const QString &objname, const QString &message)
{
    d->debugmessage(type, level, objname, message);
}

/* Get a pointer to the gstreamer pipeline.
   It's used by all Phonon objects and GStreamer objects.
*/
QbtGStreamerPipeline *Backend::gstreamerPipeline()
{
    return d->gstreamerPipeline();
}

}}

#include "backend.moc"

// vim: sw=4 ts=4 et
