/*  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 "mediaobject.h"

#include "qbtgstreamer/qbtgstreamerelementfactory.h"

#include <QTimer>
#include <QTime>

#include <kdebug.h>

#include "backend.h"
/*

    Constructs a MediaObject with the name MediaObject_currenttime.
    The media object contains the media object gstreamer bin.

      +--------------------------------------------------+
      |               Phonon Media Object                |
      |                                                  |
      |       +---------------------------------+        |
      |       |  GStreamer Media Object Bin     |        |
      |       |                                 |        |
    --#-------# Sink                        Src #--------#--
      |       |                                 |        |
      |       |                                 |        |
      |       +---------------------------------+        |
      |                                                  |
      |                                                  |
      +--------------------------------------------------+

      The mediaobjectbin contains a file source and a decoding bin.
      The decoding bin will search for the correct elements to decode and demux the source.
*/

namespace Phonon
{
namespace GStreamer
{
MediaObject::MediaObject(Backend *backend, QObject *parent)
    : QObject(parent)
    , m_backend(backend)
{
    QString mediaObjectName = "MediaObject_" + QTime::currentTime().toString("hhmmss");
    QString binName = "MediaObjectBin_" + QTime::currentTime().toString("hhmmss");
    setObjectName(mediaObjectName); 

    m_mediaObjectBin = new QbtGStreamerBin(binName);     

    if (!m_mediaObjectBin) {
        m_backend->debugmessage(2, 0, mediaObjectName, "FATAL! Could not create a GStreamer bin!");
        return;
    }

    if (!m_backend->gstreamerPipeline()->addElement(m_mediaObjectBin)) {
        m_backend->debugmessage(2, 0, mediaObjectName, "FATAL! Could not add the media object bin to the backend pipeline!");
        return;
    }

    QbtGStreamerElementFactory *factory = new QbtGStreamerElementFactory;
    QString sourceElementName = "MediaObjectSourceElement_" + QTime::currentTime().toString("hhmmss");
    m_sourceElement = factory->makeElement("filesrc", sourceElementName);

    if (!m_sourceElement) {
        m_backend->debugmessage(2, 0, mediaObjectName, "FATAL! Could not create a file source element!");
        return;
    }

    if (!m_mediaObjectBin->addElement(m_sourceElement)) {
        m_backend->debugmessage(2, 0, mediaObjectName, "FATAL! Could not add the file source element to the media object bin!");
        return;
    }

    m_backend->debugmessage(0, 0, mediaObjectName, "Created");

    m_mediaObjectDecoder = new MediaObjectDecoder(m_backend, m_sourceElement, m_mediaObjectBin);
}

MediaObject::~MediaObject()
{
    delete m_mediaObjectBin;

    m_backend->debugmessage(0, 2, objectName(), "Destroyed");
}

qint64 MediaObject::totalTime() const
{
    //Return the duration of the MediaObjectBin.
    m_backend->debugmessage(0, 5, objectName(), "Total time requested. Returned 0 seconds.");
    return 0;
}

qint32 MediaObject::tickInterval() const
{
    m_backend->debugmessage(0, 5, objectName(), "Tickinterval requested. Returned 0 seconds.");
    return 0;
}

void MediaObject::setTickInterval(qint32 newTickInterval)
{
    m_backend->debugmessage(0, 5, objectName(), "Setting tickinterval to " + QString::number(newTickInterval) + " seconds.");
}

QString MediaObject::errorString() const
{
    m_backend->debugmessage(2, 0, objectName(), "Error: ");
}

Phonon::ErrorType MediaObject::errorType() const
{
    m_backend->debugmessage(2, 0, objectName(), "Error type: ");
}

qint32 MediaObject::prefinishMark() const
{
    m_backend->debugmessage(0, 5, objectName(), "Prefinish mark requested. Returned 0 seconds.");
    return 0;
}

void MediaObject::setPrefinishMark(qint32 newPrefinishMark)
{
    m_backend->debugmessage(0, 5, objectName(), "Setting prefinish mark to " + QString::number(newPrefinishMark) + " seconds.");
}

qint32 MediaObject::transitionTime() const
{
    m_backend->debugmessage(0, 5, objectName(), "Transition time requested. Returned 0 seconds.");
    return 0;
}

void MediaObject::setTransitionTime(qint32 newTransitionTime)
{
    m_backend->debugmessage(0, 5, objectName(), "Setting transition time to " + QString::number(newTransitionTime) + " seconds.");
}

bool MediaObject::hasInterface(AddonInterface::Interface i) const
{
    m_backend->debugmessage(1, 0, objectName(), "Has interface? Returned false.");
}

QVariant MediaObject::interfaceCall(AddonInterface::Interface, int, const QList<QVariant> &)
{
    m_backend->debugmessage(0, 5, objectName(), "Calling interface.");
}

State MediaObject::state() const
{
    m_backend->debugmessage(1, 0, objectName(), "State requested. Returned nothing yet!");
}

bool MediaObject::hasVideo() const
{
    m_backend->debugmessage(1, 0, objectName(), "Has video? Returned nothing yet!");
}

bool MediaObject::isSeekable() const
{
    m_backend->debugmessage(1, 0, objectName(), "Is seekable? Returned nothing yet!");
}

qint64 MediaObject::currentTime() const
{
    m_backend->debugmessage(1, 0, objectName(), "Current time requested. Returned nothing yet!");
}

qint64 MediaObject::remainingTime() const
{
    m_backend->debugmessage(1, 0, objectName(), "Remaining time requested. Returned nothing yet!");
}

void MediaObject::play()
{
    m_backend->debugmessage(0, 1, objectName(), "Play");

    QbtGStreamerStateChangeReturn returnValue = m_backend->gstreamerPipeline()->setState(QbtGStreamerStatePlaying);

    switch(returnValue) {
        case QbtGStreamerStateChangeFailure:
            m_backend->debugmessage(2, 0, objectName(), "State Change Failure! Could not set the pipeline in playing state!");
            stop();
            break;
        case QbtGStreamerStateChangeSuccess:
            m_backend->debugmessage(0, 4, objectName(), "State Change Success. The pipeline is now in playing state!");
            break;
        case QbtGStreamerStateChangeAsync:
            m_backend->debugmessage(1, 0, objectName(), "The State Change will happen asynchronously!");
            break;
        case QbtGStreamerStateChangeNoPreroll:
            m_backend->debugmessage(1, 0, objectName(), "The State Change Succeed. This element is not able to produce data in pause mode!");
            break;
        default:
            m_backend->debugmessage(2, 0, objectName(), "Unknown state change!");
            stop();
            break;
    }
}

void MediaObject::pause()
{
    m_backend->debugmessage(0, 1, objectName(), "Pause");

    //if (state() == PlayingState || state() == BufferingState) {
      //  AbstractMediaProducer::pause();
    //}

    //m_backend->player()->pause();
}

void MediaObject::stop()
{
    m_backend->debugmessage(0, 1, objectName(), "Stop");

    QbtGStreamerStateChangeReturn returnValue = m_backend->gstreamerPipeline()->setState(QbtGStreamerStateNull);

    switch(returnValue) {
        case QbtGStreamerStateChangeFailure:
            m_backend->debugmessage(2, 0, objectName(), "State Change Failure! Could not set the pipeline in null state!");
            break;
        case QbtGStreamerStateChangeSuccess:
            m_backend->debugmessage(0, 4, objectName(), "State Change Success. The pipeline is now in null state!");
            break;
        case QbtGStreamerStateChangeAsync:
            m_backend->debugmessage(1, 0, objectName(), "The State Change will happen asynchronously!");
            break;
        case QbtGStreamerStateChangeNoPreroll:
            m_backend->debugmessage(1, 0, objectName(), "The State Change Succeed. This element is not able to produce data in pause mode!");
            break;
        default:
            m_backend->debugmessage(2, 0, objectName(), "Unknown state change!");
            break;
    }
}

void MediaObject::seek(qint64 time)
{
    m_backend->debugmessage(0, 1, objectName(), "Seek at " + QString::number(time) +" milliseconds.");
    //kDebug(611) << k_funcinfo << endl;

    //AbstractMediaProducer::seek(time);
    //m_backend->player()->seek(time);

    //if (currentTime() < totalTime() - m_aboutToFinishTime) // not about to finish
    //    m_aboutToFinishNotEmitted = true;
}

MediaSource MediaObject::source() const
{
    m_backend->debugmessage(1, 0, objectName(), "Source requested. Returned nothing yet!");
}

void MediaObject::setSource(const MediaSource &source)
{
    m_backend->debugmessage(0, 1, objectName(), "Setting source to " + source.fileName());
    /*TODO: there's more than just files. See MediaSource
    */
    m_sourceElement->setProperty("location", source.fileName());
}

void MediaObject::setNextSource(const MediaSource &source)
{
    m_backend->debugmessage(0, 1, objectName(), "Setting next source " + source.fileName());
}

QbtGStreamerBin *MediaObject::gstreamerBin()
{
    return m_mediaObjectBin;
}

}}

#include "mediaobject.moc"
// vim: sw=4 ts=4 et
