///
/// @file multimediamanager.cpp
/// @author Domenico Nicita
/// @date 01 March 2022
/// @brief Template for multimediaManager source code
///
///
///

//-----------------------------------
// INCLUDE FILES
//-----------------------------------

#include "AudioManagerEndPoint.h"
#include "BTFileManagerImpl.h"
#include "BluetoothPlayerImpl.h"
#include "DbWorker.h"
#include "FileManagerHelpers.h"
#include "MediaPlayerManagerInterfacePlatformImpl.h"
#include "MediaTransitions.hpp"
#include "MulMDBusToMain.h"
#include "MultimediaStateMachine.h"
#include "PersistenceEngine.h"
#include "QtConnectionManager.h"
#include "SeekAndPlay.h"
#include "ServiceProvider.h"
#include "SystemManagerProxy.h"
#include "filemanager.h"
#include "multimediautils.h"
#include <QStorageInfo>
#include <multimediamanager.h>

//Art libraries

//-----------------------------------
// C-Style functions
//-----------------------------------

//-----------------------------------
// USED NAMESPACES
//-----------------------------------
// None

//-----------------------------------
// PRIVATE DEFINES
//-----------------------------------
#define SAFE_CALL(ptr, call, defaultValue) ((ptr) ? ptr->call : defaultValue);

#define PLAYER_SAFE_CALL(call)                                                                                         \
    if (getCurrenPlayer())                                                                                             \
        getCurrenPlayer()->call;

//-----------------------------------
// PRIVATE MACROS
//-----------------------------------
// None

//-----------------------------------
// PRIVATE TYPEDEFS
//-----------------------------------
// None

//-----------------------------------
// CLASS DEFINITION
//-----------------------------------

//-----------------------------------
// Static members definitions
//-----------------------------------
// None

//-----------------------------------
// Constructors & destructors
//-----------------------------------

MultimediaManager::MultimediaManager():
    m_connections(std::make_shared<QtConnectionManager>(QString("MultimediaManager")))
{
    m_sourceManager = services::MultimediaServiceProvider::GetInstance()->getshared_MediaSourceManager();
    m_persistence   = services::MultimediaServiceProvider::GetInstance()->getshared_PersistenceEngineDB();
    m_sourceManager->init(services::MultimediaServiceProvider::GetInstance()->getshared_PersistenceEngineDB());

    MultimediaTypes::registerTypes();
    m_adaptor = new MultimediaManagerArtRpcAdaptor(this);

    initFileManagerInterface();
    initSystemManagerInterface();
    initMediaPlayerManagerInstance();
    initBluetooth();
    initStateMachine();
}

MultimediaManager::~MultimediaManager()
{
    qInfo() << "DTOR MultimediaManger call :) good job!";
    multimediamanager::MediaSources currentSource = m_sourceManager->GetCurrentSource();
    m_persistence->setLastMediaSource(currentSource);
    qInfo() << "Last source is " << QString::fromStdString(std::string(magic_enum::enum_name(currentSource)));
    services::MultimediaServiceProvider::ReleaseInstance();
    m_stateMachine.reset();
    qInfo() << "Finish with multimedia DTOR";
}

//------------------------------------
// Overloaded operators
//------------------------------------
// None

//-----------------------------------
// Public methods
//-----------------------------------

void MultimediaManager::init()
{
    // Initialize Persistence
    qInfo() << "Initializing Persistence";
    m_persistence->init(ArtDBManager::DbWorker::GetWorker(ArtDBManager::DbWorker::DB_MEDIA));

    // Get Devices connection status
    auto sysM                         = services::MultimediaServiceProvider::GetInstance()->get_SystemManager();
    const UsbConnectionStatus& status = sysM->GetUsbConnectionsStatus();

    // Retrieve last media source
    multimediamanager::MediaSources source = m_persistence->getLastMediaSource();
    qInfo() << "LastMediaSource was" << source;

    switch (source)
    {
        case multimediamanager::MediaSources::MEDIA_USB1:
        case multimediamanager::MediaSources::MEDIA_USB2:
        {
            const auto usbId
                = (multimediamanager::MediaSources::MEDIA_USB1 == source ? UsbId_enum::USB_1 : UsbId_enum::USB_2);

            const bool isConnected = status.IsUsbConnected(usbId);

            if (isConnected == false)
            {
                source = multimediamanager::MediaSources::MEDIA_HDD;
                qInfo() << "LastMediaSource is not connected. Setting" << source;
            }
        }
        break;

        default:
        {
            source = multimediamanager::MediaSources::MEDIA_HDD;
            qInfo() << "LastMediaSource is not valid. Setting" << source;
        }
        break;
    }

    // Check that we manage all the USB of the systemmanager
    static_assert((static_cast<int>(UsbId_enum::MAX_USB_INDEX) == (2U + 1U)), "Not managing all the SYSTEM sources");

    // Align SourceManager
    m_sourceManager->SetCurrentSource(source);

    // Start StateMachine
    m_stateMachine->start(source);

    // Register types and init adaptor
    m_adaptor->initialize();

    // Send ready!
    multimediaReady = true;
    qInfo() << "Multimedia is ready.";
    m_adaptor->MultimediaIsReady();

    // Let's start parsing HDD here anyway
    MulM::MediaStorageSource* HddSourceH = m_sourceManager->GetMediaInternalStorageSourceHandler();

    HddSourceH->SetConnectionState(MulM::MediaSource::StorageConnectionState::kWaitIndexingStart);
    HddSourceH->RestoreLastMode();
    m_adaptor->StorageSourceConnectionStateChanged(
        multimediamanager::MediaSources::MEDIA_HDD,
        MulMAdaptor::MediaSourceToDBus(MulM::MediaSource::StorageConnectionState::kWaitIndexingStart));
    m_fileManager->DoScanSource(HddSourceH);

    // Retrieve USB Status and, if connected, manage it
    for (auto src: {multimediamanager::MediaSources::MEDIA_USB1, multimediamanager::MediaSources::MEDIA_USB2})
    {
        const auto usbId = (multimediamanager::MediaSources::MEDIA_USB1 == src ? UsbId_enum::USB_1 : UsbId_enum::USB_2);

        if (status.IsUsbConnected(usbId) == true)
        {
            OnUsbConnectedInfo(getUsbInfo(src));
        }
    }
    const auto SourceH = m_sourceManager->GetCurrentSourceHandler();
    m_playerInterface->ClearQueue();
    m_playerInterface->UpdateNowPlayingList(SourceH->GetNowPlayingSongList());
    m_playerInterface->SetShuffle(SourceH->GetShuffle());
    m_playerInterface->SetRepeat(SourceH->GetRepeat());
}

// MultimediaManager Functions

bool MultimediaManager::isMultimediaReady()
{
    return multimediaReady;
}

multimediamanager::MediaAudioOwnership_t MultimediaManager::CanPlayAudio()
{
    // TODO this applies only for storage. For BT, it is not straightforward
    multimediamanager::MediaAudioOwnership_t ret
        = multimediamanager::MediaAudioOwnership_t::MEDIA_AUDIO_OWNERSHIP_UNTAKEN;
    auto audioMan = services::MultimediaServiceProvider::GetInstance()->get_AudioManager();
    if (audioMan->getIsAudioMine() == true)
    {
        ret = multimediamanager::MediaAudioOwnership_t::MEDIA_AUDIO_OWNERSHIP_CAN_PLAY;
    }
    return ret;
}

multimediamanager::StorageSourceConnection_t
MultimediaManager::GetStorageSourceConnectionState(multimediamanager::MediaSources in0)
{
    multimediamanager::StorageSourceConnection_t state = multimediamanager::StorageSourceConnection_t::NOT_CONNECTED;
    if (MulM::MediaSourceManager::IsStorageSource(in0) == true)
    {
        MulM::MediaStorageSource* sourceCtx = m_sourceManager->GetMediaStorageSourceHandler(in0);
        state                               = MulMAdaptor::MediaSourceToDBus(sourceCtx->GetConnectionState());
    }
    qInfo() << multimediamanager::helper::MediaSourcesString(in0) << state;
    return state;
}

bool MultimediaManager::IsStorageSourceKnown(multimediamanager::MediaSources in0)
{
    bool ret = false;
    if (MulM::MediaSourceManager::IsRemovableSource(in0) == true)
    {
        MulM::MediaRemovableSource* sourceCtx = m_sourceManager->GetMediaRemovableSourceHandler(in0);
        ret                                   = sourceCtx->IsNewDevice();
    }
    return ret;
}

multimediamanager::StorageSourceInfo_t MultimediaManager::GetStorageSourceInfo(multimediamanager::MediaSources source)
{
    multimediamanager::StorageSourceInfo_t srcInfo;
    MulM::MediaStorageSource* sourceCtx = m_sourceManager->GetMediaStorageSourceHandler(source);
    if (sourceCtx != nullptr)
    {
        srcInfo = sourceCtx->GetSourceInfo();
        qDebug() << srcInfo.Label << srcInfo.AbsoluteFilePath;
    }
    return srcInfo;
}

multimediamanager::BluetoothSourceInfo_t
MultimediaManager::GetBluetoothSourceInfo(multimediamanager::MediaSources source)
{
    multimediamanager::BluetoothSourceInfo_t info;

    if (m_sourceManager->IsBTSource(source) == true)
    {
        MulM::MediaBTSource* sourceCtx = m_sourceManager->GetMediaBTSourceHandler(source);
        info                           = sourceCtx->getSourceInfo();
    }

    return info;
}

void MultimediaManager::FilterItemsByQuery(multimediamanager::MediaSources source,
                                           multimediamanager::MediaAudioQueryType_t query,
                                           const QStringList& queries)
{
    if (query >= multimediamanager::MediaAudioQueryType_t::MEDIA_AUDIO_QUERY_MAX_IDX)
    {
        qWarning() << "Invalid query type";
    }
    else if (m_sourceManager->IsStorageSource(source) == false)
    {
        qWarning() << "Invalid source" << source;
    }
    else if (queries.length() == 0)
    {
        qWarning() << "Queries has length == 0";
    }
    else
    {
        MulM::MediaStorageSource* const storageSourceHandle = m_sourceManager->GetMediaStorageSourceHandler(source);

        multimediamanager::AudioItemList listToPlay;
        const multimediamanager::AudioItemList& itemList = storageSourceHandle->GetSongListTotal();
        listToPlay.reserve(itemList.length());

        qInfo() << "Filtering for source" << source << static_cast<int>(query) << queries << "SongList"
                << itemList.size();

        // TODO Manage when queries are empty
        switch (query)
        {
            case multimediamanager::MediaAudioQueryType_t::MEDIA_AUDIO_QUERY_ALL:    // AbsoluteFilePath
            {
                QString query = queries.at(0);
                std::copy_if(itemList.begin(),
                             itemList.end(),
                             std::back_inserter(listToPlay),
                             [&query](const multimediamanager::AudioItem& item) {
                                 return item.getAbsoluteFilePath().contains(query) == true;
                             });
            }
            break;

            case multimediamanager::MediaAudioQueryType_t::MEDIA_AUDIO_QUERY_BY_SONG_TITLE:
            {
                QString query = queries.at(0);
                std::copy_if(itemList.begin(),
                             itemList.end(),
                             std::back_inserter(listToPlay),
                             [&query](const multimediamanager::AudioItem& item) {
                                 return item.getTitle().contains(query) == true;
                             });
            }
            break;

            case multimediamanager::MediaAudioQueryType_t::MEDIA_AUDIO_QUERY_BY_ALBUMS:
            {
                QString query = queries.at(0);
                std::copy_if(itemList.begin(),
                             itemList.end(),
                             std::back_inserter(listToPlay),
                             [&query](const multimediamanager::AudioItem& item) {
                                 return item.getAlbum().contains(query) == true;
                             });
            }
            break;

            case multimediamanager::MediaAudioQueryType_t::MEDIA_AUDIO_QUERY_BY_ARTIST:
            {
                QString query = queries.at(0);
                std::copy_if(itemList.begin(),
                             itemList.end(),
                             std::back_inserter(listToPlay),
                             [&query](const multimediamanager::AudioItem& item) {
                                 return item.getArtist().contains(query) == true;
                             });
            }
            break;

            case multimediamanager::MediaAudioQueryType_t::MEDIA_AUDIO_QUERY_BY_GENRE:
            {
                QString query = queries.at(0);
                std::copy_if(itemList.begin(),
                             itemList.end(),
                             std::back_inserter(listToPlay),
                             [&query](const multimediamanager::AudioItem& item) {
                                 return item.getGenre().contains(query) == true;
                             });
            }
            break;

            case multimediamanager::MediaAudioQueryType_t::MEDIA_AUDIO_QUERY_BY_PLAYLIST:
            {
                // Must call another API
                qWarning() << "To Be implemented";
            }
            break;

            default:
                break;
        }

        qInfo() << "Filtered list is" << listToPlay.length();

        m_adaptor->FilteredItemsByQuery(source, query, queries, listToPlay);
    }
}

int MultimediaManager::CopyFromUSBOnMMC(multimediamanager::MediaSources source)
{
    int opId = -1;
    if (m_sourceManager->IsRemovableSource(source) == false)
    {
        qWarning() << "CopyFromUsbOnMMC cannot proceed. Source" << source << "not valid";
    }
    else if (m_sourceManager->IsSourceReady(source) == false)
    {
        qWarning() << "cannot copy from a not ready source";
    }
    else
    {
        MulM::MediaStorageSource* sourceCtx              = m_sourceManager->GetMediaStorageSourceHandler(source);
        const multimediamanager::AudioItemList& songList = sourceCtx->GetSongListTotal();
        QStringList filesToCopy;
        for (int i = 0; i < songList.length(); i++)
        {
            filesToCopy << songList.at(i).getAbsoluteFilePath();
        }

        opId = m_fileManager->DoCopy(
            sourceCtx, filesToCopy, FileM::getMediaSourceDir(multimediamanager::MediaSources::MEDIA_HDD), false);
    }
    return opId;
}

int MultimediaManager::CopyFromUSBOnMMC(const QStringList& FileList,
                                        const QString& targetPath,
                                        multimediamanager::MediaSources source)
{
    int opId = -1;
    if (m_sourceManager->IsRemovableSource(source) == false)
    {
        qWarning() << "CopyFromUsbOnMMC cannot proceed. Source" << source << "not valid";
    }
    else if (m_sourceManager->IsSourceReady(source) == false)
    {
        qWarning() << "cannot copy from a not ready source";
    }
    else if (FileList.isEmpty() == true)
    {
        qInfo() << "fileList is empty";
    }
    else
    {
        MulM::MediaStorageSource* sourceCtx = m_sourceManager->GetMediaStorageSourceHandler(source);

        // Fix input paths if are not absolute
        QStringList fileListFixed = FileM::cleanMediaSourceFiles(FileList, source);

        QString targetPathFixed = FileM::RelativePathToAbsolute(targetPath, multimediamanager::MediaSources::MEDIA_HDD);
        opId                    = m_fileManager->DoCopy(sourceCtx, FileList, targetPathFixed, false);
    }

    return opId;
}

bool MultimediaManager::CreateMMCFolder(const QString& FolderName)
{
    bool valret = true;
    // AIRP-5424
    if (FileM::isFormatValid(FolderName) == false)
    {
        qWarning() << "invalid format" << FolderName;
        valret = false;
    }
    else
    {
        QString hddPath = FileM::getMediaSourceDir(multimediamanager::MediaSources::MEDIA_HDD);

        m_fileManager->createFolder(FolderName, hddPath);
    }
    return valret;
}

int MultimediaManager::MoveFiles(const QStringList& fileList, const QString& targetPath)
{
    // fileList = { "path1" }, targetPath = "path2"
    // Path will be created if non-existant
    QString targetPathFixed   = FileM::RelativePathToAbsolute(targetPath, multimediamanager::MediaSources::MEDIA_HDD);
    QStringList fixedFileList = FileM::cleanMediaSourceFiles(fileList, multimediamanager::MediaSources::MEDIA_HDD);

    qInfo() << "Moving" << fixedFileList.count() << "into" << targetPathFixed;

    return m_fileManager->DoMove(
        m_sourceManager->GetMediaInternalStorageSourceHandler(), targetPathFixed, fixedFileList);
}

int MultimediaManager::RemoveFiles(const QStringList& fileList)
{
    QStringList fixedFileList = FileM::cleanMediaSourceFiles(fileList, multimediamanager::MediaSources::MEDIA_HDD);
    return m_fileManager->DoRemove(m_sourceManager->GetMediaInternalStorageSourceHandler(), fixedFileList);
}

int MultimediaManager::RenameFile(const QString& filePath, const QString& newName)
{
    int opID = -1;
    if (newName.contains(QDir::separator()) == true)
    {
        qWarning() << "Cannot rename in a name with" << QDir::separator();
    }
    // AIRP-5424
    else if (FileM::isFormatValid(newName) == false)
    {
        qWarning() << newName << "is invalid";
    }
    else
    {
        opID = m_fileManager->DoRename(m_sourceManager->GetMediaInternalStorageSourceHandler(), filePath, newName);
    }
    return opID;
}

int MultimediaManager::ResetMMC()
{
    qInfo() << "Resetting MMC";
    MulM::MediaStorageSource* sourceCtx              = m_sourceManager->GetMediaInternalStorageSourceHandler();
    const multimediamanager::AudioItemList& songList = sourceCtx->GetSongListTotal();
    QStringList filesToRemove;
    for (int i = 0; i < songList.length(); i++)
    {
        filesToRemove << songList.at(i).getAbsoluteFilePath();
    }

    if (m_sourceManager->GetCurrentSource() == multimediamanager::MediaSources::MEDIA_HDD)
    {
        m_playerInterface->SetPlaybackStatus(multimediamanager::PlaybackStatus_t::PB_STOPPED);
        m_playerInterface->ClearQueue();
    }

    return m_fileManager->DoRemove(sourceCtx, filesToRemove);
}

void MultimediaManager::stopFileOperation(int in0)
{
    m_fileManager->stopOperation(in0);
}

void MultimediaManager::BrowseToRoot(multimediamanager::MediaSources source)
{
    if (m_sourceManager->IsStorageSource(source) == true)
    {
        // /media/usbX or /media/music
        QString sourcePath = FileM::getMediaSourceDir(source);
        qInfo() << "Browsing Root of" << multimediamanager::helper::MediaSourcesString(source) << "Absolute"
                << sourcePath;
        (void) m_fileManager->DoBrowse(m_sourceManager->GetMediaStorageSourceHandler(source), sourcePath);
    }
    else if (m_sourceManager->IsBTSource(source) == true)
    {
        m_btFileManager->BrowseToRoot(source);
    }
}

void MultimediaManager::BrowseMediaSource(multimediamanager::MediaSources source, const QString& path)
{
    if (m_sourceManager->IsStorageSource(source) == true)
    {
        // You can Submit one of the following and obtaining the same behaviour
        // /media/usb1/pathtobrowse - pathtobrowse
        QString targetPathFixed = FileM::RelativePathToAbsolute(path, source);
        qInfo() << "Browsing by" << path << multimediamanager::helper::MediaSourcesString(source) << "Absolute"
                << targetPathFixed;
        (void) m_fileManager->DoBrowse(m_sourceManager->GetMediaStorageSourceHandler(source), targetPathFixed);
    }
    else if (m_sourceManager->IsBTSource(source) == true)
    {
        qWarning() << "Browsing Media Source by itemId not handled for sources = Bluetooth";
    }
}

void MultimediaManager::BrowseMediaSource(multimediamanager::MediaSources source, int itemId)
{
    if (m_sourceManager->IsBTSource(source) == true)
    {
        m_btFileManager->BrowseToItem(source, itemId);
    }
    else
    {
        qWarning() << "Browsing Media Source by itemId not handled for sources != Bluetooth";
    }
}

void MultimediaManager::setMediaSource(multimediamanager::MediaSources mediaSource, QString btMac)
{
    multimediamanager::MediaSources currentSource = m_sourceManager->GetCurrentSource();
    qInfo() << "Selected" << mediaSource << "Current" << currentSource << "BTMac" << btMac;

    // Post Event
    if (MulM::MediaSourceManager::IsStorageSource(mediaSource) == true)
    {
        m_stateMachine->postEvent(new statemachine::StorageSourceChangeEvent(mediaSource), true);
    }
    else if (MulM::MediaSourceManager::IsBTSource(mediaSource) == true)
    {
        m_stateMachine->postEvent(new statemachine::BTSourceChangeEvent(mediaSource, btMac), true);
    }
    else
    {
        m_stateMachine->postEvent(new statemachine::EmptySourceChangeEvent(mediaSource));
    }
}

multimediamanager::MediaSources MultimediaManager::getCurrentMediaSource()
{
    return m_sourceManager->GetCurrentSource();
}

int MultimediaManager::getCurrentNowPlayingIndex(multimediamanager::MediaSources source)
{
    int ret       = 0;
    auto ISourceH = m_sourceManager->GetMediaSourceHandler(source);
    if (ISourceH != nullptr)
    {
        auto pbProgress = ISourceH->GetPlaybackProgress();
        ret             = pbProgress.Index;
    }
    return ret;
}

void MultimediaManager::StartFastForwardRewind(multimediamanager::FastForwardRewind_t type)
{
    PLAYER_SAFE_CALL(StartFastForwardRewind(type))
}

void MultimediaManager::StopFastForwardRewind(multimediamanager::FastForwardRewind_t)
{
    PLAYER_SAFE_CALL(StopFastForwardRewind())
    //send a signal?
}

void MultimediaManager::seekTo(int msec)
{
    qInfo() << multimediamanager::helper::millisecToString(msec);
    PLAYER_SAFE_CALL(SeekTo(qint64(msec)))
}

multimediamanager::PlaybackProgress_t
MultimediaManager::getCurrentPlaybackProgress(multimediamanager::MediaSources source)
{
    multimediamanager::PlaybackProgress_t ret;
    auto SourceH = m_sourceManager->GetMediaSourceHandler(source);
    if (SourceH != nullptr)
    {
        ret = SourceH->GetPlaybackProgress();
    }
    return ret;
}

void MultimediaManager::setMediaPlayerPlaybackStatus(multimediamanager::PlaybackStatus_t playbackStatus)
{
    multimediamanager::MediaSources currentSource = m_sourceManager->GetCurrentSource();
    if (MulM::MediaSourceManager::IsStorageSource(currentSource) == true)
    {
        auto SourceH = m_sourceManager->GetMediaSourceHandler(currentSource);
        SourceH->SetLastUserPlaybackStatus(playbackStatus);
    }
    qDebug() << "currentSource" << static_cast<int>(currentSource);
    PLAYER_SAFE_CALL(SetPlaybackStatus(playbackStatus))
}

multimediamanager::PlaybackStatus_t MultimediaManager::getCurrentPlaybackStatus()
{
    auto player = getCurrenPlayer();
    multimediamanager::PlaybackStatus_t status
        = player ? player->GetPlaybackStatus() : multimediamanager::PlaybackStatus_t::PB_NOT_SET;
    return status;
}

void MultimediaManager::enableDisableShuffle(bool shuffleStatus)
{
    qInfo() << shuffleStatus;
    PLAYER_SAFE_CALL(SetShuffle(shuffleStatus))
}

bool MultimediaManager::getShuffle(multimediamanager::MediaSources source) const
{
    if (multimediamanager::MediaSources::MEDIA_NOT_SET == source)
        qWarning() << "source" << source;
    MulM::MediaSourcePtr handler = SAFE_CALL(m_sourceManager, GetMediaSourceHandler(source), nullptr);
    return SAFE_CALL(handler, GetShuffle(), false);
}

multimediamanager::RepeatStatus_t MultimediaManager::getRepeat(multimediamanager::MediaSources source) const
{
    MulM::MediaSourcePtr handler = SAFE_CALL(m_sourceManager, GetMediaSourceHandler(source), nullptr);
    return SAFE_CALL(handler, GetRepeat(), multimediamanager::RepeatStatus_t::REPEAT_STS_INVALID);
}

void MultimediaManager::setRepeat(multimediamanager::RepeatStatus_t repeatMode)
{
    qInfo() << toString(repeatMode);
    PLAYER_SAFE_CALL(SetRepeat(repeatMode))
}

void MultimediaManager::nextMediaItem(int count)
{
    multimediamanager::MediaSources currentSource = m_sourceManager->GetCurrentSource();
    if (m_sourceManager->IsBTSource(currentSource) == true)
    {
        m_bluetoothPlayer->PlayNext(count);
    }
    else if (m_sourceManager->IsStorageSource(currentSource) == true)
    {
        MulM::MediaStorageSource* StorageSourceH = m_sourceManager->GetMediaStorageSourceHandler(currentSource);

        if (m_playerInterface->IsPlaylistEmpty() == true)
        {
            auto allSongs  = StorageSourceH->GetSongListTotal();
            int indexToSet = count;

            if (indexToSet >= allSongs.count())
                indexToSet = 0;

            m_playerInterface->OnPlayThisList(StorageSourceH->GetSongListTotal(), count);
        }
        else
        {
            m_playerInterface->PlayNext(count);
        }
    }
}

void MultimediaManager::previousMediaItem(int count)
{
    multimediamanager::MediaSources currentSource = m_sourceManager->GetCurrentSource();
    if (m_sourceManager->IsStorageSource(currentSource) == true)
    {
        MulM::MediaStorageSource* StorageSourceH = m_sourceManager->GetMediaStorageSourceHandler(currentSource);

        if (m_playerInterface->IsPlaylistEmpty() == true)
        {
            auto allSongs  = StorageSourceH->GetSongListTotal();
            int indexToSet = 0;

            m_playerInterface->OnPlayThisList(allSongs, indexToSet);
        }
    }
    PLAYER_SAFE_CALL(PlayPrev(count))
}

void MultimediaManager::playItem(int index)
{
    const multimediamanager::MediaSources currentSource = m_sourceManager->GetCurrentSource();
    if (m_sourceManager->IsStorageSource(currentSource) == true)
    {
        auto sourceHandler     = m_sourceManager->GetMediaStorageSourceHandler(currentSource);
        const int currentIndex = sourceHandler->GetCurrentMediaIndex();

        // Check if index is valid considering our nowPlayingList
        const auto& nowPList = sourceHandler->GetNowPlayingSongList();

        if ((index < 0) || (nowPList.count() <= index))
        {
            qInfo() << "Index is invalid. NowP Count is" << nowPList.count() << "Index" << index;
            m_playerInterface->SetPlaybackStatus(multimediamanager::PlaybackStatus_t::PB_STOPPED);
        }
        else
        {
            // Set LastUserPlaybackStatus
            sourceHandler->SetLastUserPlaybackStatus(multimediamanager::PlaybackStatus_t::PB_PLAYING);
            qInfo() << "index:  " << index << " currentIndex:" << currentIndex;
            qInfo() << "current media source: " << currentSource;
            qint64 lastPosition = 0;
            m_playerInterface->SetPlayingIndex(index);
            m_playerInterface->SetPlaybackStatus(multimediamanager::PlaybackStatus_t::PB_PLAYING);
            if (currentIndex == index)
            {
                if (sourceHandler != nullptr)
                {
                    lastPosition = sourceHandler->GetPlaybackProgress().ElapsedMsec;
                }
                m_playerInterface->SetPlaybackStatus(multimediamanager::PlaybackStatus_t::PB_PAUSED);
                qInfo() << " resume playing from last position (" << (lastPosition) << ")"
                        << multimediamanager::helper::millisecToString(lastPosition);
                auto seekAndPlay = [this, lastPosition]() {
                    // TODO Improve SeekAndPlay to take also current source: if seekable changes but source is not the same, then do nothing!
                    // Or add a StateMachine for playing status
                    const Art::PlaybackStatus pbStatus = m_audioPlayer->playbackStatus();
                    const bool seekable                = m_audioPlayer->isSeekable();
                    if (seekable && Art::PlaybackStatus::kStopped != pbStatus)
                    {
                        qInfo() << "resume playing from last position "
                                << multimediamanager::helper::millisecToString(lastPosition) << " and disconnect";
                        seekTo(static_cast<int>(lastPosition));
                        m_playerInterface->SetPlaybackStatus(multimediamanager::PlaybackStatus_t::PB_PLAYING);
                    }
                };
                SeekAndPlay::doSeekAndPlay(seekAndPlay, m_audioPlayer, this);
            }
        }
    }
    else if (m_sourceManager->IsBTSource(currentSource) == true)
    {
        m_bluetoothPlayer->SetPlayingIndex(index);
    }
}

void MultimediaManager::playPlaylist(const QString& path)
{
    multimediamanager::MediaSources currentSource = m_sourceManager->GetCurrentSource();
    // Bugged. No check of the audioToken ? is this function used by LIMU?
    if (m_sourceManager->IsBTSource(currentSource) == true)
    {
        qInfo() << "Not valid for BT Sources";
    }
    else if (m_sourceManager->IsStorageSource(currentSource) && MultiMediaUtils::isPlaylist(path))
    {
        qInfo() << "Loading Playlist" << path;
        m_playerInterface->OnPlayPlaylist(path);
    }
}

void MultimediaManager::PlayThisList(multimediamanager::MediaSources source,
                                     multimediamanager::AudioItemList audioList,
                                     int index)
{
    multimediamanager::MediaSources currentSource = m_sourceManager->GetCurrentSource();

    qInfo() << "Selected " << source << "Current" << currentSource << "list length: " << audioList.length()
            << "index: " << index;

    if (m_sourceManager->IsStorageSource(source) == false)
    {
    }
    else
    {
        MulM::MediaStorageSource* StorageSH = m_sourceManager->GetMediaStorageSourceHandler(source);
        if (audioList.isEmpty() == true)
        {
            qInfo() << " list is empty!";

            m_playerInterface->SetPlaybackStatus(multimediamanager::PlaybackStatus_t::PB_STOPPED);
            StorageSH->ClearNowPlayingSongList();
            m_playerInterface->ClearQueue();
        }
        else
        {
            qInfo() << "source: " << source << "list length " << audioList.length() << "index " << index;

            if ((index < 0) || (index >= audioList.count()))
                index = 0;

            m_playerInterface->OnPlayThisList(audioList, index);
        }
    }
}

bool MultimediaManager::isMediaAllSongsEmpty(multimediamanager::MediaSources source)
{
    bool isEmpty = true;

    if (m_sourceManager->IsStorageSource(source) == true)
    {
        MulM::MediaStorageSource* sourceH = m_sourceManager->GetMediaStorageSourceHandler(source);

        if (false == sourceH->isAllSongListValid())
        {
            sourceH->fixAllsonglist();
            m_fileManager->DoScanSource(sourceH);
        }

        isEmpty = sourceH->IsSongListEmpty();
    }

    return isEmpty;
}

bool MultimediaManager::isMediaNowPlayingEmpty(multimediamanager::MediaSources source)
{
    bool isEmpty = true;

    if (m_sourceManager->IsStorageSource(source) == true)
    {
        MulM::MediaStorageSource* sourceH = m_sourceManager->GetMediaStorageSourceHandler(source);
        isEmpty                           = sourceH->IsNowPlayingSongListEmpty();
    }

    return isEmpty;
}

void MultimediaManager::AddToFavourites(multimediamanager::MediaSources source,
                                        const QStringList& absPaths,
                                        bool removeExisting)
{
    qInfo() << "favList num" << absPaths.size();

    auto storageSourceHandle = m_sourceManager->GetMediaStorageSourceHandler(source);
    if (storageSourceHandle != nullptr)
    {
        storageSourceHandle->AddFavourites(absPaths, removeExisting);
    }

    // Retrieve new favourite list and trigger emit through interface.
    getFavouritesAudioList(source);
}

void MultimediaManager::getFavouritesAudioList(multimediamanager::MediaSources source)
{
    auto&& favList = getFavourites(source);
    qInfo() << "favList.size" << favList.size();
    m_adaptor->FavouritesAudioList(source, std::move(favList));
}

void MultimediaManager::SyncData()
{
    qInfo() << "SaveLastMode";
    m_sourceManager->SaveLastMode();
    m_adaptor->DataSynced();
}

void MultimediaManager::RemoveFromFavourites(multimediamanager::MediaSources source, const QStringList& absPaths)
{
    auto sourceH = m_sourceManager->GetMediaStorageSourceHandler(source);
    if (sourceH != nullptr)
    {
        sourceH->RemoveFavourites(absPaths);

        getFavouritesAudioList(source);
    }
}

//-----------------------------------
// Protected methods
//-----------------------------------

//-----------------------------------
// Private methods
//-----------------------------------

// Initializations
void MultimediaManager::initMediaPlayerManagerInstance()
{
    qInfo() << "Initializing MediaPlayerManager";
    m_audioPlayer.reset(new Art::MediaPlayerManager);
    m_audioQueue.reset(new Art::MediaQueue);

    m_playerInterface.reset(new MulM::MediaPlayerPlatformInterface(m_audioPlayer, m_audioQueue, m_sourceManager));

    // Initialize MediaPlayer
    m_playerInterface->Init();
}

bool MultimediaManager::getUsbConnectionStatus(multimediamanager::MediaSources source)
{
    auto sysM                         = services::MultimediaServiceProvider::GetInstance()->get_SystemManager();
    const UsbConnectionStatus& status = sysM->GetUsbConnectionsStatus();
    const auto usbId = (multimediamanager::MediaSources::MEDIA_USB1 == source ? UsbId_enum::USB_1 : UsbId_enum::USB_2);
    return status.IsUsbConnected(usbId);
}

UsbInfo_t MultimediaManager::getUsbInfo(multimediamanager::MediaSources source)
{
    const auto usbId = (multimediamanager::MediaSources::MEDIA_USB1 == source ? UsbId_enum::USB_1 : UsbId_enum::USB_2);
    return services::MultimediaServiceProvider::GetInstance()->get_SystemManager()->GetCurrentUsbInfo(usbId);
}

void MultimediaManager::initBluetooth()
{
    // Player
    m_bluetoothPlayer.reset(new MulM::BluetoothPlayerImpl(m_sourceManager));
    m_bluetoothPlayer->Init();

    // Browsing
    m_btFileManager.reset(new FileM::BluetoothFileManagerImpl(m_sourceManager));
    // AV Profile connected (Music Streaming)
    // SourceInfoChanged
    *m_connections << connect(
        m_btFileManager.get(),
        &FileM::BluetoothFileManagerInterface::SourceInfoChanged,
        this,
        [this]() {
            auto curSource = m_sourceManager->GetCurrentSource();
            if (MulM::MediaSourceManager::IsBTSource(curSource) == true)
            {
                auto BTSourceH                                   = m_sourceManager->GetMediaBTSourceHandler(curSource);
                multimediamanager::BluetoothSourceInfo_t srcInfo = BTSourceH->getSourceInfo();

                m_adaptor->BluetoothSourceInfoChanged(srcInfo);
            }
        },
        Qt::UniqueConnection);
    *m_connections << connect(m_btFileManager.get(),
                              &FileM::BluetoothFileManagerInterface::BrowsedView,
                              m_adaptor,
                              QOverload<multimediamanager::MediaSources, filemanager::FileSystemView>::of(
                                  &MultimediaManagerArtRpcAdaptor::BrowsedMediaSource),
                              Qt::UniqueConnection);
}

void MultimediaManager::initFileManagerInterface()
{
    qInfo() << "Initializing FileManager";
    m_fileManager = services::MultimediaServiceProvider::GetInstance()->get_FileManager();

    // Browse
    *m_connections << connect(
        m_fileManager, &FileM::FileManager::BrowseStarted, this, &MultimediaManager::onBrowseStarted);
    *m_connections << connect(
        m_fileManager, &FileM::FileManager::BrowseResult, this, &MultimediaManager::onBrowseEnded);

    // Copy
    *m_connections << connect(m_fileManager, &FileM::FileManager::CopyStarted, this, &MultimediaManager::onCopyStarted);
    *m_connections << connect(
        m_fileManager, &FileM::FileManager::CopyProgress, this, &MultimediaManager::onCopyProgress);
    *m_connections << connect(m_fileManager, &FileM::FileManager::CopyResult, this, &MultimediaManager::onCopyResult);

    // Move
    *m_connections << connect(m_fileManager, &FileM::FileManager::MoveStarted, this, &MultimediaManager::onMoveStarted);
    *m_connections << connect(m_fileManager, &FileM::FileManager::MoveResult, this, &MultimediaManager::onMoveResult);

    // Remove
    *m_connections << connect(
        m_fileManager, &FileM::FileManager::RemoveStarted, this, &MultimediaManager::onRemoveStarted);
    *m_connections << connect(
        m_fileManager, &FileM::FileManager::RemoveResult, this, &MultimediaManager::onRemoveResult);

    // Rename
    *m_connections << connect(
        m_fileManager, &FileM::FileManager::RenameStarted, this, &MultimediaManager::onRenameStarted);
    *m_connections << connect(
        m_fileManager, &FileM::FileManager::RenameResult, this, &MultimediaManager::onRenameResult);

    // Scan
    *m_connections << connect(m_fileManager, &FileM::FileManager::ScanStarted, this, &MultimediaManager::onScanStarted);
    *m_connections << connect(
        m_fileManager, &FileM::FileManager::SourceCoverScanResult, this, &MultimediaManager::onSourceCoverScanResult);
}

void MultimediaManager::initStateMachine()
{
    m_stateMachine.reset(new statemachine::MultimediaStateMachine);
    m_stateMachine->init(m_adaptor, m_sourceManager.get(), m_playerInterface.get(), m_bluetoothPlayer.get());
}

void MultimediaManager::initSystemManagerInterface()
{
    qInfo() << "Initializing SystemManager...";
    auto sysM = services::MultimediaServiceProvider::GetInstance()->get_SystemManager();

    *m_connections << connect(sysM,
                              &SystemManagerProxy::UsbMountedSignal,
                              this,
                              &MultimediaManager::OnUsbConnectedInfo,
                              Qt::UniqueConnection);
    *m_connections << connect(sysM,
                              &SystemManagerProxy::UsbUnmountedSignal,
                              this,
                              &MultimediaManager::OnUsbDisconnectedInfo,
                              Qt::UniqueConnection);
    *m_connections << connect(m_adaptor,
                              &MultimediaManagerArtRpcAdaptor::ClientConnected,
                              this,
                              [this](const QString& peerAddress, quint16 peerPort) {
                                  qInfo() << "ClientConnected. update missing signals" << peerAddress << peerPort;
                                  if (isMultimediaReady())
                                  {
                                      m_adaptor->MultimediaIsReady();
                                      for (const auto src: {multimediamanager::MediaSources::MEDIA_HDD,
                                                            multimediamanager::MediaSources::MEDIA_USB1,
                                                            multimediamanager::MediaSources::MEDIA_USB2})
                                          if (m_sourceManager->IsSourceReady(src))
                                              signalSourceInfo(src, multimediamanager::ListInfo_t::SINGLE);
                                  }
                              });
}

void MultimediaManager::initMessageManagerInterface()
{
    messageManagerSystemEventProxy = new MessageManagerSystemEventProxy(QDBusConnection::systemBus());

    RegisterMessageManagerSystemEventTypes();

    connect(messageManagerSystemEventProxy,
            &MessageManagerSystemEventProxy::systemFuncMode,
            this,
            &MultimediaManager::OnSystemEventCommand);
}

// Multimedia connections with other classes signals
void MultimediaManager::printMediaSourceTable()
{
    // HDD Source
    {
        MulM::MediaRemovableSource* storageSourceHandle
            = m_sourceManager->GetMediaRemovableSourceHandler(multimediamanager::MediaSources::MEDIA_HDD);
        QString sourceStr = multimediamanager::helper::MediaSourcesString(multimediamanager::MediaSources::MEDIA_HDD);
        UsbInfo_t usbInfo = storageSourceHandle->GetUsbInfo();

        qInfo() << "------ " << sourceStr << "------";
        qInfo() << "mediaSource: " << sourceStr;

        qInfo() << "usbInfo: Vendor" << usbInfo.idVendor << "Model" << usbInfo.modelName;

        qInfo() << "available: " << storageSourceHandle->GetAvailability();
        qInfo() << "state: "
                << MulM::MediaStorageSource::ConnectionStateToString(storageSourceHandle->GetConnectionState());
        qInfo() << "songListTotal length: " << storageSourceHandle->GetSongListTotal().length();
        qInfo() << "currentlyPlaying length: " << storageSourceHandle->GetNowPlayingSongList().length();
        qInfo() << "progress elapsed: "
                << multimediamanager::helper::millisecToString(storageSourceHandle->GetPlaybackProgress().ElapsedMsec);
        qInfo() << "currentMediaIndex: " << storageSourceHandle->GetCurrentMediaIndex();
    }

    // Removable Source
    {
        QList<multimediamanager::MediaSources> removableSources = {multimediamanager::MediaSources::MEDIA_USB1,
                                                                   multimediamanager::MediaSources::MEDIA_USB2,
                                                                   multimediamanager::MediaSources::MEDIA_USB3};

        for (multimediamanager::MediaSources source: removableSources)
        {
            MulM::MediaRemovableSource* storageSourceHandle = m_sourceManager->GetMediaRemovableSourceHandler(source);
            QString sourceStr                               = multimediamanager::helper::MediaSourcesString(source);
            UsbInfo_t usbInfo                               = storageSourceHandle->GetUsbInfo();

            qInfo() << "------ " << sourceStr << "------";

            qInfo() << "usbInfo: Vendor" << usbInfo.idVendor << "Model" << usbInfo.modelName;

            qInfo() << "available: " << storageSourceHandle->GetAvailability();
            qInfo() << "state: "
                    << MulM::MediaStorageSource::ConnectionStateToString(storageSourceHandle->GetConnectionState());
            qInfo() << "songListTotal length: " << storageSourceHandle->GetSongListTotal().length();
            qInfo() << "currentlyPlaying length: " << storageSourceHandle->GetNowPlayingSongList().length();
            qInfo() << "progress elapsed: "
                    << multimediamanager::helper::millisecToString(
                           storageSourceHandle->GetPlaybackProgress().ElapsedMsec);
            qInfo() << "currentMediaIndex: " << storageSourceHandle->GetCurrentMediaIndex();
        }
    }

    // BT Source
    {
        QList<multimediamanager::MediaSources> btSources
            = {multimediamanager::MediaSources::MEDIA_BT_1, multimediamanager::MediaSources::MEDIA_BT_2};

        for (multimediamanager::MediaSources source: btSources)
        {
            MulM::MediaBTSource* storageSourceHandle = m_sourceManager->GetMediaBTSourceHandler(source);
            QString sourceStr                        = multimediamanager::helper::MediaSourcesString(source);

            qInfo() << "------ " << sourceStr << "------";

            qInfo() << "macAddress: " << storageSourceHandle->GetMAC();
            qInfo() << "state: "
                    << MulM::MediaBTSource::AVConnectionStateToString(storageSourceHandle->GetAVConnectionState());
            qInfo() << "btAudioItemList length: " << storageSourceHandle->GetAudioItemList().length();
            qInfo() << "currentlyPlaying length: " << storageSourceHandle->GetNowPlayingSongList().length();
            qInfo() << "progress elapsed: "
                    << multimediamanager::helper::millisecToString(
                           storageSourceHandle->GetPlaybackProgress().ElapsedMsec);
        }
    }
}

/* Manage and Update Lists */

void MultimediaManager::printSourcesStatus() const
{
    QList<multimediamanager::MediaSources> sources = {multimediamanager::MediaSources::MEDIA_HDD,
                                                      multimediamanager::MediaSources::MEDIA_USB1,
                                                      multimediamanager::MediaSources::MEDIA_USB2};
    for (const multimediamanager::MediaSources source: sources)
    {
        MulM::MediaStorageSource* sourceCtx = m_sourceManager->GetMediaStorageSourceHandler(source);
        if (sourceCtx->GetAvailability())
        {
            const auto& allSongItems    = sourceCtx->GetSongListTotal();
            const auto& nowPlayingItems = sourceCtx->GetNowPlayingSongList();
            qInfo() << multimediamanager::helper::MediaSourcesString(source) << "AllSong Items" << allSongItems.count()
                    << "NowPlaying Items" << nowPlayingItems.count() << "CurrentIndex"
                    << sourceCtx->GetCurrentMediaIndex();
            qInfo() << "state of" << source
                    << MulM::MediaStorageSource::ConnectionStateToString(sourceCtx->GetConnectionState());
        }
        else
        {
            qInfo() << multimediamanager::helper::MediaSourcesString(source) << " unavailable";
        }
    }
}

void MultimediaManager::triggerInternalMemoryReparse()
{
    auto sourceCtx = m_sourceManager->GetMediaStorageSourceHandler(multimediamanager::MediaSources::MEDIA_HDD);
    auto source    = sourceCtx->GetSourceType();
    sourceCtx->SetConnectionState(MulM::MediaSource::StorageConnectionState::kWaitIndexingStart);
    m_adaptor->StorageSourceConnectionStateChanged(
        source, MulMAdaptor::MediaSourceToDBus(MulM::MediaSource::StorageConnectionState::kIndexingFiles));
    m_fileManager->DoScanSource(sourceCtx);
}

multimediamanager::AudioItemList MultimediaManager::getFavourites(multimediamanager::MediaSources source) const
{
    multimediamanager::AudioItemList result;
    const auto* storageSourceHandle = m_sourceManager->GetMediaStorageSourceHandler(source);
    if (storageSourceHandle)
        result = storageSourceHandle->GetFavourites();
    else
        qWarning() << "wrong source";

    return result;
}

const std::shared_ptr<MulM::GenericPlayerInterface>& MultimediaManager::getCurrenPlayer() const
{
    const multimediamanager::MediaSources currentSource = m_sourceManager->GetCurrentSource();
    if (m_sourceManager->IsBTSource(currentSource) == true)
    {
        return m_bluetoothPlayer;
    }
    return m_playerInterface;
}

/* Private slots connected to FileManager */
void MultimediaManager::onBrowseStarted(int opID, multimediamanager::MediaSources source)
{
    qInfo() << "Browse for" << source << "ID" << opID << "started.";

    m_adaptor->OperationStarted(opID, filemanager::OperationType_t::FILE_OP_BROWSE);
}

void MultimediaManager::onBrowseEnded(int opID,
                                      multimediamanager::MediaSources source,
                                      filemanager::FileSystemView fsView,
                                      bool success)
{
    qInfo() << "Browse for" << source << "ID" << opID << "ENDED."
            << "Success" << success;
    if (success == true)
        m_adaptor->BrowsedMediaSource(source, fsView.CurrentDir, fsView);
}

void MultimediaManager::onCopyStarted(int opID, multimediamanager::MediaSources source)
{
    qInfo() << "CopyStarted for" << source;

    m_adaptor->OperationStarted(opID, filemanager::OperationType_t::FILE_OP_COPY);
}

void MultimediaManager::onCopyProgress(int opID, multimediamanager::MediaSources source, double progress)
{
    qDebug() << "CopyProgress for" << source << opID << progress;

    m_adaptor->OperationProgress(opID, filemanager::OperationType_t::FILE_OP_COPY, progress);
}

void MultimediaManager::onCopyResult(int opID,
                                     multimediamanager::MediaSources source,
                                     filemanager::FileOperationResult_t success)
{
    qInfo() << "Copy for" << source << "ENDED."
            << " Result " << toString(success);

    triggerInternalMemoryReparse(); /* trigger anyway as copy may be interrupted */

    m_adaptor->OperationDone(opID, filemanager::OperationType_t::FILE_OP_COPY, success);
}

void MultimediaManager::onMoveStarted(int opID, multimediamanager::MediaSources source)
{
    qInfo() << "Move Started for" << source;

    m_adaptor->OperationStarted(opID, filemanager::OperationType_t::FILE_OP_MOVE);
}

void MultimediaManager::onMoveResult(int opID, multimediamanager::MediaSources source, bool success)
{
    qInfo() << "Move for" << source << "ENDED."
            << "Success" << success;

    triggerInternalMemoryReparse(); /* trigger anyway as copy may be interrupted */
    const auto result
        = success ? filemanager::FileOperationResult_t::Success : filemanager::FileOperationResult_t::ExecutionProblem;

    m_adaptor->OperationDone(opID, filemanager::OperationType_t::FILE_OP_MOVE, result);
}

void MultimediaManager::onRemoveStarted(int opID, multimediamanager::MediaSources source)
{
    qInfo() << "Move Started for" << source;

    m_adaptor->OperationStarted(opID, filemanager::OperationType_t::FILE_OP_REMOVE);
}

void MultimediaManager::onRemoveResult(int opID, multimediamanager::MediaSources source, bool success)
{
    qInfo() << "Remove for" << source << "ENDED."
            << "Success" << success;

    triggerInternalMemoryReparse(); /* trigger anyway as copy may be interrupted */
    const auto result
        = success ? filemanager::FileOperationResult_t::Success : filemanager::FileOperationResult_t::ExecutionProblem;
    m_adaptor->OperationDone(opID, filemanager::OperationType_t::FILE_OP_REMOVE, result);
}

void MultimediaManager::onRenameStarted(int opID, multimediamanager::MediaSources source)
{
    qInfo() << "Rename started for" << multimediamanager::helper::MediaSourcesString(source) << "OPID:" << opID;
}

void MultimediaManager::onRenameResult(int opID, multimediamanager::MediaSources source, bool success)
{
    qInfo() << "Rename Ended for" << multimediamanager::helper::MediaSourcesString(source) << "OPID:" << opID
            << success;

    triggerInternalMemoryReparse(); /* trigger anyway as copy may be interrupted */
    const auto result
        = success ? filemanager::FileOperationResult_t::Success : filemanager::FileOperationResult_t::ExecutionProblem;
    m_adaptor->OperationDone(opID, filemanager::OperationType_t::FILE_OP_RENAME, result);
}

void MultimediaManager::onScanStarted(int opID, multimediamanager::MediaSources source)
{
    qInfo() << "Scan of source" << source << "started";
    MulM::MediaStorageSource* const storageSourceHandle = m_sourceManager->GetMediaStorageSourceHandler(source);
    storageSourceHandle->SetConnectionState(MulM::MediaSource::StorageConnectionState::kIndexingFiles);

    m_adaptor->StorageSourceConnectionStateChanged(
        source, MulMAdaptor::MediaSourceToDBus(MulM::MediaSource::StorageConnectionState::kIndexingFiles));
    m_adaptor->OperationStarted(opID, filemanager::OperationType_t::FILE_OP_SCAN);
}

void MultimediaManager::signalSourceInfo(multimediamanager::MediaSources source,
                                         multimediamanager::ListInfo_t order) const
{
    auto* sourceCtx                                  = m_sourceManager->GetMediaStorageSourceHandler(source);
    const multimediamanager::AudioItemList& allSongs = sourceCtx->GetSongListTotal();
    const multimediamanager::AudioItemList& nowP     = sourceCtx->GetNowPlayingSongList();
    signalSourceInfo(source, allSongs, nowP, order);
}

void MultimediaManager::signalSourceInfo(multimediamanager::MediaSources source,
                                         const multimediamanager::AudioItemList& allSongs,
                                         const multimediamanager::AudioItemList& nowP,
                                         multimediamanager::ListInfo_t order) const
{
    auto* sourceCtx                                = m_sourceManager->GetMediaStorageSourceHandler(source);
    int index                                      = sourceCtx->GetCurrentMediaIndex();
    const multimediamanager::RepeatStatus_t repeat = sourceCtx->GetRepeat();
    const bool shuffle                             = sourceCtx->GetShuffle();

    qInfo() << multimediamanager::helper::MediaSourcesString(source) << "order" << order
            << "Repeat:" << toString(repeat) << "shuffle:" << shuffle << "AllSongs:" << allSongs.length()
            << "NowPlaying:" << nowP.length() << "Index:" << index;
    if (nowP.isEmpty())
    {
        qWarning() << "NowPlayingSongList is empty.";
    }

    if (multimediamanager::ListInfo_t::FIRST == order || multimediamanager::ListInfo_t::SINGLE == order)
    {
        m_adaptor->shuffleChanged(shuffle);
        m_adaptor->repeatChanged(repeat);
        m_adaptor->MultimediaItemChanged(source, index);
    }
    if (multimediamanager::ListInfo_t::LAST == order || multimediamanager::ListInfo_t::SINGLE == order)
    {
        m_adaptor->AllSongsListSignal(source, sourceCtx->GetSongListTotal(), multimediamanager::ListInfo_t::SINGLE);
    }
    m_adaptor->NowPlayingSongsListSignal(source, nowP, order);
}

void MultimediaManager::onSourceCoverScanResult(int,
                                                multimediamanager::MediaSources source,
                                                multimediamanager::AudioItemList audioList,
                                                multimediamanager::ListInfo_t order)
{
    qInfo() << "Scan of source" << source << "(COVER) "
            << "order" << order << "AudioItems:" << audioList.length();

    auto sourceCtx = m_sourceManager->GetMediaStorageSourceHandler(source);
    // If it is the last time this slot is triggered (SINGLE or FIRST)
    bool isSingleTime = (order == multimediamanager::ListInfo_t::SINGLE);
    bool isFirstTime  = (order == multimediamanager::ListInfo_t::FIRST);
    bool isLastTime   = (order == multimediamanager::ListInfo_t::LAST);

    // Clear lists if it is first time ever (single or first chunk)
    if ((isSingleTime == true) || (isFirstTime == true))
    {
        sourceCtx->ClearNowPlayingSongList();
        sourceCtx->ClearListTotal();
    }

    // Add to lists (SongListTotal + NowPlaying)
    if (sourceCtx != nullptr)
    {
        sourceCtx->AddToSongListTotal(audioList);
        sourceCtx->AddToNowPlayingSongList(audioList);
    }

    // If it is related to current source, then update also the player interface
    if ((m_sourceManager != nullptr) && (sourceCtx != nullptr))
    {
        if (m_sourceManager->GetCurrentSource() == sourceCtx->GetSourceType())
        {
            if ((isSingleTime == true) || (isFirstTime == true))
            {
                m_playerInterface->SetNowPlayingList(audioList);
            }
            else
            {
                m_playerInterface->UpdateNowPlayingList(audioList);
            }
        }
        else
        {
            qDebug() << "current source" << m_sourceManager->GetCurrentSource();
            qDebug() << "source type" << sourceCtx->GetSourceType();
        }

        // reset CurrentMediaIndex only for new USB media.
        // for hdd we have index set from persistence.
        // We reset mediaIndex only if invalid
        // IE Consider the case in which we are playing from HDD and user adds a new element
        //  this triggers a re-scan, and we are here in a blink of an eye. What we do ? ;)
        if (sourceCtx->GetCurrentMediaIndex() < 0)
        {
            sourceCtx->SetCurrentMediaIndex(0);
        }
        signalSourceInfo(source, audioList, audioList, order);

        if ((isSingleTime == true) || (isLastTime == true))
        {
            sourceCtx->SetConnectionState(MulM::MediaSource::StorageConnectionState::kReady);
            m_adaptor->StorageSourceConnectionStateChanged(
                source, MulMAdaptor::MediaSourceToDBus(sourceCtx->GetConnectionState()));

            printSourcesStatus();
        }
        else if (isFirstTime == true)
        {
            sourceCtx->SetConnectionState(MulM::MediaSource::StorageConnectionState::kParsingMetadata);
        }
    }
    else
    {
        m_adaptor->StorageSourceConnectionStateChanged(source,
                                                       multimediamanager::StorageSourceConnection_t::NOT_CONNECTED);
    }
}

/* Private slots connected to SystemManager */

void MultimediaManager::OnUsbConnectedInfo(const UsbInfo_t& usbInfo)
{
    qInfo() << "Connected USB" << usbInfo.label << usbInfo.usb << usbInfo.modelName << usbInfo.idVendor << ":"
            << usbInfo.idProduct;

    multimediamanager::MediaSources source = multimediamanager::MediaSources::MEDIA_NOT_SET;
    if (usbInfo.usb == UsbId_enum::USB_1)
    {
        source = multimediamanager::MediaSources::MEDIA_USB1;
    }
    else if (usbInfo.usb == UsbId_enum::USB_2)
    {
        source = multimediamanager::MediaSources::MEDIA_USB2;
    }
    else
    {
    }

    if (source == multimediamanager::MediaSources::MEDIA_NOT_SET)
    {
    }
    else
    {
        m_sourceManager->OnUsbConnectedInfo(source, usbInfo);
        MulM::MediaRemovableSource* SourceH = m_sourceManager->GetMediaRemovableSourceHandler(source);

        bool scanIsNeeded = SourceH->IsNewDevice();

        qInfo() << "Source" << multimediamanager::helper::MediaSourcesString(source) << "connected"
                << "ScanIsNeeded=" << scanIsNeeded;
        auto connectionState = MulM::MediaSource::StorageConnectionState::kInvalid;
        /*  deprecated LIMRP-6969
            New AIRP-10221 */
        if (scanIsNeeded == false)
        {
            SourceH->RestoreLastMode();    // Known storage. Restore data from DB

            const auto& allSongs        = SourceH->GetSongListTotal();
            const auto& nowPlayingSongs = SourceH->GetNowPlayingSongList();

            qInfo() << "SongListTotal" << allSongs.size() << "NowPlayingSongList" << nowPlayingSongs.size();
            if (SourceH->IsSongListEmpty() || SourceH->IsNowPlayingSongListEmpty()
                || allSongs.size() < nowPlayingSongs.size())
            {
                qInfo() << "suspicious situation, DB could be spoiled. Run scan again."
                        << "megaBytesTotal" << usbInfo.megaBytesTotal << " megaBytesFree" << usbInfo.megaBytesFree;
                scanIsNeeded = true;
            }
            else
            {
                signalSourceInfo(source, multimediamanager::ListInfo_t::SINGLE);
                connectionState = MulM::MediaSource::StorageConnectionState::kReady;
            }
        }
        if (scanIsNeeded == true)    // If scanIsNeeded -> let's parse!
        {
            connectionState = MulM::MediaSource::StorageConnectionState::kWaitIndexingStart;
            m_fileManager->DoScanSource(SourceH);
        }
        SourceH->SetConnectionState(connectionState);
        m_adaptor->StorageSourceConnectionStateChanged(source, MulMAdaptor::MediaSourceToDBus(connectionState));
    }
}

void MultimediaManager::OnUsbDisconnectedInfo(UsbId_enum usbInfo)
{
    qInfo() << "USB" << usbInfo << "Disconnected";
    multimediamanager::MediaSources source = multimediamanager::MediaSources::MEDIA_NOT_SET;

    if (usbInfo == UsbId_enum::USB_1)
    {
        source = multimediamanager::MediaSources::MEDIA_USB1;
    }
    else if (usbInfo == UsbId_enum::USB_2)
    {
        source = multimediamanager::MediaSources::MEDIA_USB2;
    }
    else
    {
    }

    if (source == multimediamanager::MediaSources::MEDIA_NOT_SET)
    {
    }
    else
    {
        m_sourceManager->OnUsbDisconnectedInfo(source);
        m_adaptor->StorageSourceConnectionStateChanged(
            source, MulMAdaptor::MediaSourceToDBus(MulM::MediaRemovableSource::StorageConnectionState::kInvalid));

        // Post Event
        m_stateMachine->postEvent(new statemachine::StorageSourceDisconnectedEvent(source));

        // if the source was our current media, then stop the playback
        if (m_sourceManager->GetCurrentSource() == source)
        {
            m_playerInterface->SetPlaybackStatus(multimediamanager::PlaybackStatus_t::PB_STOPPED);
            m_playerInterface->ClearQueue();
        }
    }
}

void MultimediaManager::OnSystemEventCommand(SysFuncMode_t sysEventCmd)
{
    /* not used */
    Q_UNUSED(sysEventCmd);
}

#undef SAFE_CALL
#undef PLAYER_SAFE_CALL
//****************************************************************************
//****************************************************************************
can u find a spot where parsing media files in usb is done?