#include "NotificationAudio.h"
#include "WaveFile.h"


NotificationAudio::NotificationAudio(QObject *parent):
    QObject(parent)
{
    m_file = new BWFFile(QAudioFormat{}, this);

    m_stream = new SoundOutput();

    connect(m_stream, &SoundOutput::status, this, &NotificationAudio::status);
    connect(m_stream, &SoundOutput::error, this, &NotificationAudio::error);
}

NotificationAudio::~NotificationAudio(){
    // stop the audio
    stop();

    // clean cache
    foreach(auto pair, m_cache){
        delete pair.second;
    }
}

void NotificationAudio::status(QString message){
    if(message == "Idle"){
        stop();
    }
}

void NotificationAudio::error(QString message){
    qDebug() << "notification error:" << message;
}

void NotificationAudio::setDevice(const QAudioDeviceInfo &device, unsigned channels, unsigned msBuffer){
    m_device = device;
    m_channels = channels;
    m_msBuffer = msBuffer;
    m_stream->setFormat(device, channels, msBuffer);
}

void NotificationAudio::play(const QString &filePath){
    if(m_cache.contains(filePath)){
        auto pair = m_cache.value(filePath);
        auto format = pair.first;
        auto bytes = pair.second;

        qDebug() << "notification: playing" << filePath << "with format" << format << "from cache";
        playBytes(format, bytes);
        return;
    }

    if(m_file->isOpen()){
        m_file->close();
    }
    m_file->setFileName(filePath);
    if(m_file->open(BWFFile::ReadOnly)){
        QAudioFormat format = m_file->format();
        QByteArray *bytes = new QByteArray(m_file->readAll());

        qDebug() << "notification: playing" << filePath << "with format" << format << "from disk";
        playBytes(format, bytes);

        // cache the buffer
        m_cache.insert(filePath, {format, bytes});
    }
}

void NotificationAudio::playBytes(const QAudioFormat &format, QByteArray *bytes){
    if(bytes == nullptr){
        return;
    }

    if(m_buffer.isOpen()){
        m_buffer.close();
    }

    m_buffer.setBuffer(bytes);

    if(!m_buffer.open(QIODevice::ReadOnly)){
        return;
    }

    m_stream->setDeviceFormat(m_device, format, format.channelCount(), m_msBuffer);
    m_stream->restart(&m_buffer);
}

void NotificationAudio::stop(){
    m_stream->stop();

    if(m_file->isOpen()){
        m_file->close();
    }
}
