/****************************************************************
 *  RetroShare is distributed under the following license:
 *
 *  Copyright (C) 2012 RetroShare Team
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; either version 2
 *  of the License, or (at your option) any later version.
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, 
 *  Boston, MA  02110-1301, USA.
 ****************************************************************/

#include <QApplication>
#include <QFile>
#include <QProcess>
#include <QSound>
#include <QDir>

#if QT_VERSION >= QT_VERSION_CHECK (5, 0, 0)
#include <QAudio>
#include <QAudioDeviceInfo>
#endif

// #ifdef QMEDIAPLAYER
// #nclude <QMediaPlayer>
// #endif

#include "SoundManager.h"
#include "settings/rsharesettings.h"
#include "retroshare/rsinit.h"
#include <retroshare/rsplugin.h>

#define GROUP_MAIN      "Sound"
#define GROUP_ENABLE    "Enable"
#define GROUP_SOUNDFILE "SoundFilePath"

SoundManager *soundManager = NULL;

SoundEvents::SoundEvents()
{
}

void SoundEvents::addEvent(const QString &groupName, const QString &eventName, const QString &event, const QString &defaultFilename)
{
	if (event.isEmpty()) {
		return;
	}

	SoundEventInfo info;
	info.mGroupName = groupName;
	info.mEventName = eventName;
	info.mDefaultFilename = defaultFilename;

	mEventInfos[event] = info;
}

void SoundManager::create()
{
	if (soundManager == NULL) {
		soundManager = new SoundManager;
	}
}

SoundManager::SoundManager() : QObject()
{
}

void SoundManager::soundEvents(SoundEvents &events)
{
	QDir baseDir = QDir(QString::fromUtf8(RsAccounts::DataDirectory().c_str()) + "/sounds");

	events.mDefaultPath = baseDir.absolutePath();

	/* add standard events */
	events.addEvent(tr("Friend"), tr("Go Online"), SOUND_USER_ONLINE, QFileInfo(baseDir, "online1.wav").absoluteFilePath());
	events.addEvent(tr("Chatmessage"), tr("New Msg"), SOUND_NEW_CHAT_MESSAGE, QFileInfo(baseDir, "incomingchat.wav").absoluteFilePath());
	events.addEvent(tr("Message"), tr("Message arrived"), SOUND_MESSAGE_ARRIVED, QFileInfo(baseDir, "receive.wav").absoluteFilePath());
	events.addEvent(tr("Download"), tr("Download complete"), SOUND_DOWNLOAD_COMPLETE, QFileInfo(baseDir, "ft_complete.wav").absoluteFilePath());
    events.addEvent(tr("Lobby"), tr("Message arrived"), SOUND_NEW_LOBBY_MESSAGE, QFileInfo(baseDir, "incomingchat.wav").absoluteFilePath());

	/* add plugin events */
	int pluginCount = rsPlugins->nbPlugins();
	for (int i = 0; i < pluginCount; ++i) {
		RsPlugin *plugin = rsPlugins->plugin(i);

		if (plugin) {
			plugin->qt_sound_events(events);
		}
	}
}

QString SoundManager::defaultFilename(const QString &event, bool check)
{
	SoundEvents events;
	soundEvents(events);

	QMap<QString, SoundEvents::SoundEventInfo>::iterator eventIt = events.mEventInfos.find(event);
	if (eventIt == events.mEventInfos.end()) {
		return "";
	}

	QString filename = eventIt.value().mDefaultFilename;
	if (filename.isEmpty()) {
		return "";
	}

	if (!check) {
		return convertFilename(filename);
	}

	if (QFileInfo(filename).exists()) {
		return convertFilename(filename);
	}

	return "";
}

void SoundManager::initDefault()
{
	SoundEvents events;
	soundEvents(events);

	QString event;
	foreach (event, events.mEventInfos.keys()) {
		SoundEvents::SoundEventInfo &eventInfo = events.mEventInfos[event];

		if (QFileInfo(eventInfo.mDefaultFilename).exists()) {
			setEventFilename(event, convertFilename(eventInfo.mDefaultFilename));
			setEventEnabled(event, true);
		}
	}
}

void SoundManager::setMute(bool m)
{
	Settings->beginGroup(GROUP_MAIN);
	Settings->setValue("mute", m);
	Settings->endGroup();

	emit mute(m);
}

bool SoundManager::isMute()
{
	Settings->beginGroup(GROUP_MAIN);
	bool mute = Settings->value("mute", false).toBool();
	Settings->endGroup();

	return mute;
}

bool SoundManager::eventEnabled(const QString &event)
{
	Settings->beginGroup(GROUP_MAIN);
	Settings->beginGroup(GROUP_ENABLE);
	bool enabled = Settings->value(event, false).toBool();
	Settings->endGroup();
	Settings->endGroup();

	return enabled;
}

void SoundManager::setEventEnabled(const QString &event, bool enabled)
{
	Settings->beginGroup(GROUP_MAIN);
	Settings->beginGroup(GROUP_ENABLE);
	Settings->setValue(event, enabled);
	Settings->endGroup();
	Settings->endGroup();
}

QString SoundManager::eventFilename(const QString &event)
{
	Settings->beginGroup(GROUP_MAIN);
	Settings->beginGroup(GROUP_SOUNDFILE);
	QString filename = Settings->value(event).toString();
	Settings->endGroup();
	Settings->endGroup();

	return filename;
}

void SoundManager::setEventFilename(const QString &event, const QString &filename)
{
	Settings->beginGroup(GROUP_MAIN);
	Settings->beginGroup(GROUP_SOUNDFILE);
	Settings->setValue(event, filename);
	Settings->endGroup();
	Settings->endGroup();
}

QString SoundManager::convertFilename(const QString &filename)
{
	if (RsInit::isPortable ()) {
		// Save path relative to application path
		QDir baseDir = QDir(qApp->applicationDirPath());
		QString relativeFilename = baseDir.relativeFilePath(filename);
		if (!relativeFilename.startsWith("..")) {
			// Save only subfolders as relative path
			return relativeFilename;
		}
	}

	return filename;
}

QString SoundManager::realFilename(const QString &filename)
{
	if (RsInit::isPortable ()) {
		// Path relative to application path
		QDir baseDir = QDir(qApp->applicationDirPath());
		return baseDir.absoluteFilePath(filename);
	}

	return filename;
}

void SoundManager::play(const QString &event)
{
	if (isMute() || !eventEnabled(event)) {
		return;
	}

	QString filename = eventFilename(event);
	playFile(filename);
}

void SoundManager::playFile(const QString &filename)
{
	if (filename.isEmpty()) {
		return;
	}

	QString playFilename = realFilename(filename);
        bool played = false ;
    
#if QT_VERSION >= QT_VERSION_CHECK (5, 0, 0)
    if (!QAudioDeviceInfo::availableDevices(QAudio::AudioOutput).isEmpty())
#else
    if (QSound::isAvailable())
#endif
        {
        QSound::play(playFilename);
            played = true ;
        }

        if(!played)	// let's go for the hard core stuff
    {
        // #ifdef QMEDIAPLAYER
        //         static QMediaPlayer *qmplayer;
        //         if (qmplayer == NULL) {
        //             qmplayer = new QMediaPlayer();
        //             qmplayer->setMedia(QMediaContent(QUrl::fromLocalFile(playFilename)));
        //         }
        //         std::cerr << "Play QMediaPlayer" << std::endl;
        //         qmplayer->play();
        //         return;
        // #endif

#ifdef Q_OS_LINUX
        QString player_cmd = soundDetectPlayer();
        QStringList args = player_cmd.split(' ');
        args += filename;
        QString prog = args.takeFirst();
        //std::cerr << "Play " << prog.toStdString() << std::endl;
        QProcess::startDetached(prog, args);
#endif
    }
}


#ifdef Q_OS_LINUX
/** Detect default player helper on unix like systems
 * Inspired by Psi IM (0.15) in common.cpp
 */
QString SoundManager::soundDetectPlayer()
{
    // prefer ALSA on linux

    if (QFile("/proc/asound").exists()) {
        return "aplay -q";
    }
    // fallback to "play"
    return "play";
}
#endif





