bool SoundManager::isSoundPlaying(void * soundHandle)
{
#ifdef FMOD_ACTIVE
    FMOD::Studio::EventInstance * instance = static_cast<FMOD::Studio::EventInstance *>(soundHandle);
    if ( nullptr != instance && instance->isValid() )
    {
        FMOD_STUDIO_PLAYBACK_STATE instancePlaybackState;
        instance->getPlaybackState(&instancePlaybackState);
        if (instancePlaybackState == FMOD_STUDIO_PLAYBACK_PLAYING
            || instancePlaybackState == FMOD_STUDIO_PLAYBACK_STARTING
            || instancePlaybackState == FMOD_STUDIO_PLAYBACK_SUSTAINING)
        {
            return true;
        }
        else
        {
            return false;
        }
//        FMOD::ChannelGroup * channelGroup;
//        bool isPlaying;
//        ERRCHECK(instance->getChannelGroup(&channelGroup));
//        ERRCHECK(channelGroup->isPlaying(&isPlaying));
//        return isPlaying;
    }
    else
    {
        return false;
    }
#else
    return false;
#endif
}
void SoundManager::resumeSound(void * soundHandle)
{
#ifdef FMOD_ACTIVE
    FMOD::Studio::EventInstance * instance = static_cast<FMOD::Studio::EventInstance *>(soundHandle);
    if ( nullptr != instance && instance->isValid() )
    {
        ERRCHECK(instance->setPaused(false));
        ERRCHECK(_system->update());
    }
#endif
}
float SoundManager::getSoundTimelinePosition(void * soundHandle)
{
    int milliseconds = 0;
#ifdef FMOD_ACTIVE
    FMOD::Studio::EventInstance * instance = static_cast<FMOD::Studio::EventInstance *>(soundHandle);
    if ( nullptr != instance && instance->isValid() )
    {
        ERRCHECK(instance->getTimelinePosition(&milliseconds));
    }
#endif
    return (float)milliseconds/1000.0f;
}
void SoundManager::updateSoundPosition(void * soundHandle, cocos2d::Point position)
{
#ifdef FMOD_ACTIVE
    FMOD::Studio::EventInstance * instance = static_cast<FMOD::Studio::EventInstance *>(soundHandle);
    if ( nullptr != instance && instance->isValid() )
    {
        FMOD_3D_ATTRIBUTES attributes = { { 0 } };
        FMOD_VECTOR fmodPosition = {position.x, position.y, 0};
        attributes.position = fmodPosition;
        ERRCHECK( instance->set3DAttributes(&attributes) );
    }
#endif
}
bool SoundManager::setUniqueIdForSoundHandle(void * soundHandle, const std::string uniqueId)
{
#ifdef FMOD_ACTIVE
    FMOD::Studio::EventInstance * instance = static_cast<FMOD::Studio::EventInstance *>(soundHandle);
    if ( nullptr != instance && instance->isValid() && !uniqueId.empty() )
    {
        if (this->removeInstanceById(uniqueId))
        {
            CCLOG("Attenzione: UniqueId associato ad un'istanza di FMOD già esistente. La precedente istanza è stata distrutta");
        }
        _instancesMap[uniqueId] = instance;
        return true;
    }
#endif
    return false;
    
}
void SoundManager::setVolumeForSound(void * soundHandle, bool isMusic)
{
#ifdef FMOD_ACTIVE
    FMOD::Studio::EventInstance * instance = static_cast<FMOD::Studio::EventInstance *>(soundHandle);
    if ( nullptr != instance && instance->isValid() )
    {
        float volume;
        if (isMusic)
        {
            volume = _userVolumeMusic * _systemVolumeMusic;
        }
        else
        {
            volume = _userVolumeFX * _systemVolumeFX;
        }
        ERRCHECK(instance->setVolume(volume));
    }
#endif
}
void SoundManager::stopPlaySound(void * soundHandle, const bool fadeOut)
{
#ifdef FMOD_ACTIVE
    FMOD::Studio::EventInstance * instance = static_cast<FMOD::Studio::EventInstance *>(soundHandle);
    if ( nullptr != instance && instance->isValid() )
    {
        ERRCHECK(instance->stop((fadeOut) ? FMOD_STUDIO_STOP_ALLOWFADEOUT : FMOD_STUDIO_STOP_IMMEDIATE));
        ERRCHECK(_system->update());
        
        _instancesFX.erase(std::remove(_instancesFX.begin(), _instancesFX.end(), instance), _instancesFX.end());
        _instancesMusic.erase(std::remove(_instancesMusic.begin(), _instancesMusic.end(), instance), _instancesMusic.end());
        for (auto iter = _instancesMap.begin(); iter != _instancesMap.end(); iter++ )
        {
            if (iter->second == soundHandle)
            {
                _instancesMap.erase(iter);
                break;
            }
        }
        ERRCHECK(instance->release());
    }
#endif
}
void SoundManager::updateSoundParameter(void * soundHandle, const char * paramName, const float paramValue, const bool disableOnMax)
{
#ifdef FMOD_ACTIVE
    FMOD::Studio::EventInstance * instance = static_cast<FMOD::Studio::EventInstance *>(soundHandle);
    if ( nullptr != instance && instance->isValid())
    {
        FMOD::Studio::ParameterInstance * parameter = NULL;
        ERRCHECK(instance->getParameter(paramName, &parameter));
        
        if (!parameter->isValid()) return;
        
        if (disableOnMax)
        {
            FMOD_STUDIO_PLAYBACK_STATE instancePlayState;
            ERRCHECK(instance->getPlaybackState(&instancePlayState));
            
            FMOD_STUDIO_PARAMETER_DESCRIPTION paramDescription;
            ERRCHECK(parameter->getDescription(&paramDescription));
            
            if ((instancePlayState == FMOD_STUDIO_PLAYBACK_PLAYING
                 || instancePlayState == FMOD_STUDIO_PLAYBACK_SUSTAINING)
                && paramValue > paramDescription.maximum)
            {
                instance->stop(FMOD_STUDIO_STOP_IMMEDIATE);
                //CCLOG("Suono disabilitato perché troppo distante");
            }
            else if (instancePlayState == FMOD_STUDIO_PLAYBACK_STOPPED && paramValue < paramDescription.maximum)
            {
                instance->start();
                //CCLOG("Suono riabilitato perché abbastanza vicino");
            }
        }
        ERRCHECK(parameter->setValue(paramValue));
//        ERRCHECK(instance->setParameterValue(paramName, paramValue));
    }
#endif
}