/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtFeedback module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtCore/QtPlugin>
#include <QtCore/QCoreApplication>
#include <QtCore/QFile>

#include <QDebug>
#include "qfeedback.h"

QT_BEGIN_NAMESPACE

QFeedbackMMK::QFeedbackMMK() : QObject(qApp)
{
}

QFeedbackMMK::~QFeedbackMMK()
{
    foreach(FeedbackInfo fi, mEffects.values()) {
        delete fi.soundEffect;
    }
}

void QFeedbackMMK::setLoaded(QFeedbackFileEffect *effect, bool load)
{
    if (!effect)
        return;

    // See if we have seen this effect before
    FeedbackInfo fi = mEffects.value(effect);

    if (load) {
        // Well.. we might already have an effect, since we don't create them until
        // we load...
        if (fi.loaded) {
            // We've already loaded?
            return;
        } else {
            if (fi.soundEffect) {
                // We've started a load, they must just be impatient
                // Pushing this elevator button does nothing..
                return;
            } else {
                // New sound effect!
                QUrl url = effect->source();
                if (QFile::exists(url.toLocalFile())) {
                    fi.soundEffect = new QSoundEffect(this);
                    mEffects.insert(effect, fi);
                    mEffectMap.insert(fi.soundEffect, effect);

                    connect(fi.soundEffect, SIGNAL(statusChanged()), this, SLOT(soundEffectStatusChanged()));
                    connect(fi.soundEffect, SIGNAL(playingChanged()), this, SLOT(soundEffectPlayingChanged()));
                    fi.soundEffect->setSource(url);

                    // conceptually we're now loading, so we have to do this manually??
                    QMetaObject::invokeMethod(effect, "stateChanged");
                } else {
                    reportLoadFinished(effect, false);
                }
            }
        }
    } else {
        // Time to unload.
        if (fi.soundEffect) {
            mEffectMap.remove(fi.soundEffect);
            fi.soundEffect->deleteLater();
        }
        mEffects.remove(effect);
    }
}

void QFeedbackMMK::setEffectState(QFeedbackFileEffect *effect, QFeedbackEffect::State state)
{
    FeedbackInfo fi = mEffects.value(effect);
    switch (state)
    {
        case QFeedbackEffect::Stopped:
            if (fi.playing) {
                Q_ASSERT(fi.soundEffect);
                fi.playing = false;
                mEffects.insert(effect, fi); // overwrite previous version
                fi.soundEffect->stop();
            }
            break;

        case QFeedbackEffect::Paused:
            // Well, we can't pause, really
            reportError(effect, QFeedbackEffect::UnknownError);
            break;

        case QFeedbackEffect::Running:
            if (fi.playing) {
                // We're already playing.
            } else if (fi.soundEffect) {
                fi.playing = true;
                mEffects.insert(effect, fi); // overwrite previous version
                fi.soundEffect->play();
            }
            break;
        default:
            break;
    }
}

QFeedbackEffect::State QFeedbackMMK::effectState(const QFeedbackFileEffect *effect)
{
    FeedbackInfo fi = mEffects.value(effect);
    if (fi.soundEffect) {
        if (fi.playing) // we might not be loaded, however
            return QFeedbackEffect::Running;
        if (fi.loaded)
            return QFeedbackEffect::Stopped; // No idle?
        return QFeedbackEffect::Loading;
    }
    return QFeedbackEffect::Stopped;
}

int QFeedbackMMK::effectDuration(const QFeedbackFileEffect *effect)
{
    Q_UNUSED(effect);
    // XXX This isn't supported by MMK currently
    return 0;
}

QStringList QFeedbackMMK::supportedMimeTypes()
{
    return QSoundEffect::supportedMimeTypes();
}

void QFeedbackMMK::soundEffectStatusChanged()
{
    QSoundEffect* se = qobject_cast<QSoundEffect*>(sender());
    if (se) {
        // Hmm, now look up the right sound effect
        QFeedbackFileEffect* fe = mEffectMap.value(se);
        if (!fe)
            return;

        FeedbackInfo fi = mEffects.value(fe);

        switch(se->status()) {
            case QSoundEffect::Error:
                if (!fi.soundEffect || !fi.loaded) {
                    // Error before we got loaded, so fail the load
                    mEffectMap.remove(se);
                    mEffects.remove(fe);
                    se->deleteLater();
                    reportLoadFinished(fe, false); // this ends our involvement
                } else {
                    reportError(fe, QFeedbackEffect::UnknownError); // this doesn't do much
                }
                break;

            case QSoundEffect::Ready:
                if (fe->state() == QFeedbackEffect::Loading) {
                    reportLoadFinished(fe, true);

                    FeedbackInfo fi = mEffects.value(fe);
                    fi.loaded = true;
                    mEffects.insert(fe, fi);

                    QMetaObject::invokeMethod(fe, "stateChanged");
                }
                break;

            default:
                // Nothing to handle here?
                break;
        }
    }
}

void QFeedbackMMK::soundEffectPlayingChanged()
{
    QSoundEffect* se = qobject_cast<QSoundEffect*>(sender());
    if (se) {
        QFeedbackFileEffect* fileEffect = mEffectMap.value(se);
        FeedbackInfo fi = mEffects.value(fileEffect);

        if (fi.soundEffect == se) {
            if (fi.playing != se->isPlaying()) {
                fi.playing = se->isPlaying();
                mEffects.insert(fileEffect, fi); // overwrite previous version

                QFeedbackFileEffect* fe = mEffectMap.value(se);
                // Emit the stateChanged() signal
                if (fe) {
                    QMetaObject::invokeMethod(fe, "stateChanged");
                }
            } else {
                // Do nothing, internal state is already ok
            }
        }
    }
}

QT_END_NAMESPACE
