/*  This file is part of the KDE project
    Copyright (C) 2006 Matthias Kretz <kretz@kde.org>
    Copyright (C) 2006 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 "abstractmediaproducer.h"

#include <QByteArray>
#include <QFile>
#include <QStringList>
#include <QTimer>
#include <QVector>

#include <kdebug.h>

#include "videopath.h"
#include "audiopath.h"

namespace Phonon
{
namespace GStreamer
{
AbstractMediaProducer::AbstractMediaProducer(Backend *backend, QObject *parent)
    : QObject(parent)
    , m_state(Phonon::LoadingState)
    , m_tickTimer(new QTimer(this))
    , m_lastSamplesMissing(0)
    , m_backend(backend)
{
    //kDebug(611) << k_funcinfo << endl;
}

AbstractMediaProducer::~AbstractMediaProducer()
{
    //kDebug(611) << k_funcinfo << endl;
}

bool AbstractMediaProducer::addVideoPath(QObject *videoPath)
{
    //kDebug(611) << k_funcinfo << endl;

    Q_ASSERT(videoPath);
    VideoPath *vp = qobject_cast<VideoPath *>(videoPath);
    Q_ASSERT(vp);
    Q_ASSERT(!m_videoPathList.contains(vp));
    m_videoPathList.append(vp);
    return true;
}

bool AbstractMediaProducer::addAudioPath(QObject *audioPath)
{
    //kDebug(611) << k_funcinfo << endl;

    Q_ASSERT(audioPath);
    AudioPath *ap = qobject_cast<AudioPath *>(audioPath);
    Q_ASSERT(ap);
    Q_ASSERT(!m_audioPathList.contains(ap));
    m_audioPathList.append(ap);
    return true;
}

void AbstractMediaProducer::removeVideoPath(QObject *videoPath)
{
    Q_ASSERT(videoPath);
    VideoPath *vp = qobject_cast<VideoPath *>(videoPath);
    Q_ASSERT(vp);
    Q_ASSERT(m_videoPathList.contains(vp));
    m_videoPathList.removeAll(vp);
}

void AbstractMediaProducer::removeAudioPath(QObject *audioPath)
{
    Q_ASSERT(audioPath);
    AudioPath *ap = qobject_cast<AudioPath *>(audioPath);
    Q_ASSERT(ap);
    Q_ASSERT(m_audioPathList.contains(ap));
    m_audioPathList.removeAll(ap);
}

State AbstractMediaProducer::state() const
{
    //kDebug(611) << k_funcinfo << endl;

    return m_state;
}

bool AbstractMediaProducer::hasVideo() const
{
    //kDebug(611) << k_funcinfo << endl;

    return false;
}

bool AbstractMediaProducer::isSeekable() const
{
    //kDebug(611) << k_funcinfo << endl;

    return true;
}

qint64 AbstractMediaProducer::currentTime() const
{
    //kDebug(611) << k_funcinfo << endl;

    switch (state()) {
    case Phonon::PausedState:
    case Phonon::BufferingState:
        return m_startTime.msecsTo(m_pauseTime);
    case Phonon::PlayingState:
        return m_startTime.elapsed();
    case Phonon::StoppedState:
    case Phonon::LoadingState:
        return 0;
    case Phonon::ErrorState:
        break;
    }

    return -1;
}

qint32 AbstractMediaProducer::tickInterval() const
{
    //kDebug(611) << k_funcinfo << endl;

    return m_tickInterval;
}

void AbstractMediaProducer::setTickInterval(qint32 newTickInterval)
{
    //kDebug(611) << k_funcinfo << endl;

    m_tickInterval = newTickInterval;
    if (m_tickInterval <= 0)
        m_tickTimer->setInterval(50);
    else
        m_tickTimer->setInterval(newTickInterval);
}

QStringList AbstractMediaProducer::availableAudioStreams() const
{
    QStringList ret;
    ret << QLatin1String("en") << QLatin1String("de");
    return ret;
}

QStringList AbstractMediaProducer::availableVideoStreams() const
{
    QStringList ret;
    ret << QLatin1String("en") << QLatin1String("de");
    return ret;
}

QStringList AbstractMediaProducer::availableSubtitleStreams() const
{
    QStringList ret;
    ret << QLatin1String("en") << QLatin1String("de");
    return ret;
}

QString AbstractMediaProducer::selectedAudioStream(const QObject *audioPath) const
{
    return m_selectedAudioStream[audioPath];
}

QString AbstractMediaProducer::selectedVideoStream(const QObject *videoPath) const
{
    return m_selectedVideoStream[videoPath];
}

QString AbstractMediaProducer::selectedSubtitleStream(const QObject *videoPath) const
{
    return m_selectedSubtitleStream[videoPath];
}

void AbstractMediaProducer::selectAudioStream(const QString &streamName, const QObject *audioPath)
{
    if (availableAudioStreams().contains(streamName))
        m_selectedAudioStream[audioPath] = streamName;
}

void AbstractMediaProducer::selectVideoStream(const QString &streamName, const QObject *videoPath)
{
    if (availableVideoStreams().contains(streamName))
        m_selectedVideoStream[videoPath] = streamName;
}

void AbstractMediaProducer::selectSubtitleStream(const QString &streamName, const QObject *videoPath)
{
    if (availableSubtitleStreams().contains(streamName))
        m_selectedSubtitleStream[videoPath] = streamName;
}

void AbstractMediaProducer::play()
{
    //kDebug(611) << k_funcinfo << endl;

    m_tickTimer->start();
    setState(Phonon::PlayingState);
}

void AbstractMediaProducer::pause()
{
    //kDebug(611) << k_funcinfo << endl;

    m_tickTimer->stop();
    setState(Phonon::PausedState);
}

void AbstractMediaProducer::stop()
{
    //kDebug(611) << k_funcinfo << endl;

    m_tickTimer->stop();
    setState(Phonon::StoppedState);
}

void AbstractMediaProducer::seek(qint64 time)
{
    //kDebug(611) << k_funcinfo << endl;

    if (isSeekable()) {

        switch (state()) {
        case Phonon::PausedState:
        case Phonon::BufferingState:
            m_startTime = m_pauseTime;
            break;
        case Phonon::PlayingState:
            m_startTime = QTime::currentTime();
            break;
        case Phonon::StoppedState:
        case Phonon::ErrorState:
        case Phonon::LoadingState:
            return; // cannot seek
        }

        m_startTime = m_startTime.addMSecs(-time);
    }
}

QString AbstractMediaProducer::errorString() const
{
    //TODO
    return QString();
}

Phonon::ErrorType AbstractMediaProducer::errorType() const
{
    //TODO
    return Phonon::NoError;
}

void AbstractMediaProducer::setState(State newstate)
{
    if (newstate == m_state)
        return;

    State oldstate = m_state;
    m_state = newstate;

    switch (newstate) {
    case Phonon::PausedState:
    case Phonon::BufferingState:
        m_pauseTime.start();
        break;
    case Phonon::PlayingState:
        if (oldstate == Phonon::PausedState || oldstate == Phonon::BufferingState)
            m_startTime = m_startTime.addMSecs(m_pauseTime.elapsed());
        else
            m_startTime.start();
        break;
    case Phonon::StoppedState:
    case Phonon::ErrorState:
    case Phonon::LoadingState:
        break;
    }

    //kDebug(611) << "emit stateChanged(" << newstate << ", " << oldstate << ")" << endl;
    emit stateChanged(newstate, oldstate);
}

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