text: /*
   * Copyright 2017-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
   *
   * Licensed under the Apache License, Version 2.0 (the "License").
   * You may not use this file except in compliance with the License.
   * A copy of the License is located at
   *
   *     http://aws.amazon.com/apache2.0/
   *
   * or in the "license" file accompanying this file. This file is distributed
   * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
   * express or implied. See the License for the specific language governing
   * permissions and limitations under the License.
   */
  
  #include <Settings/SettingCallbacks.h>
  #include "AACE/Engine/Alexa/DoNotDisturbEngineImpl.h"
  #include "AACE/Engine/Core/EngineMacros.h"
  
  namespace aace {
  namespace engine {
  namespace alexa {
  
  // String to identify log entries originating from this file.
  static const std::string TAG("aace.alexa.DoNotDisturbEngineImpl");
  
  // report setting strings
  static const std::string DND_ON = "true";
  static const std::string DND_OFF = "false";
  
  DoNotDisturbEngineImpl::DoNotDisturbEngineImpl( std::shared_ptr<aace::alexa::DoNotDisturb> doNotDisturbPlatformInterface ) :
      alexaClientSDK::avsCommon::utils::RequiresShutdown( TAG ),
      m_doNotDisturbPlatformInterface( doNotDisturbPlatformInterface ) {
  }
  
  bool DoNotDisturbEngineImpl::initialize(
  	std::shared_ptr<alexaClientSDK::endpoints::EndpointBuilder> defaultEndpointBuilder,
      std::shared_ptr<alexaClientSDK::acl::AVSConnectionManager> connectionManager,
      std::shared_ptr<alexaClientSDK::registrationManager::CustomerDataManager> customerDataManager,
      std::shared_ptr<alexaClientSDK::avsCommon::sdkInterfaces::ExceptionEncounteredSenderInterface> exceptionSender,
      std::shared_ptr<alexaClientSDK::avsCommon::sdkInterfaces::MessageSenderInterface> messageSender,
      aace::engine::alexa::DeviceSettingsDelegate& deviceSettingsDelegate ) {
      try
      {
          m_doNotDisturbCapabilityAgent = alexaClientSDK::capabilityAgents::doNotDisturb::DoNotDisturbCapabilityAgent::create( exceptionSender, messageSender, deviceSettingsDelegate.getDeviceSettingStorage());
          ThrowIfNull( m_doNotDisturbCapabilityAgent, "couldNotCreateCapabilityAgent" );
  
          // add DND CA to settings manager builder
          deviceSettingsDelegate.configureDoNotDisturbSetting( m_doNotDisturbCapabilityAgent );
          deviceSettingsDelegate.getDeviceSettingsManager()->addObserver<DeviceSettingsDelegate::DeviceSettingsIndex::DO_NOT_DISTURB>(shared_from_this());
  
          // add the capability agent to the connection manager
          m_connectionManager = connectionManager;
          m_connectionManager->addConnectionStatusObserver( m_doNotDisturbCapabilityAgent );
  
          // register capability with the default endpoint
          defaultEndpointBuilder->withCapability( m_doNotDisturbCapabilityAgent, m_doNotDisturbCapabilityAgent );
          
          // set the platform's engine interface reference
          m_doNotDisturbPlatformInterface->setEngineInterface( std::dynamic_pointer_cast<aace::alexa::DoNotDisturbEngineInterface>( shared_from_this() ) );
  
          return true;
      }
      catch( std::exception& ex ) {
          AACE_ERROR(LX(TAG,"initialize").d("reason", ex.what()));
          return false;
      }
  }
  
  std::shared_ptr<DoNotDisturbEngineImpl> DoNotDisturbEngineImpl::create(
      std::shared_ptr<aace::alexa::DoNotDisturb> doNotDisturbPlatformInterface,
  	std::shared_ptr<alexaClientSDK::endpoints::EndpointBuilder> defaultEndpointBuilder,
      std::shared_ptr<alexaClientSDK::acl::AVSConnectionManager> connectionManager,
      std::shared_ptr<alexaClientSDK::registrationManager::CustomerDataManager> customerDataManager,
      std::shared_ptr<alexaClientSDK::avsCommon::sdkInterfaces::ExceptionEncounteredSenderInterface> exceptionSender,
      std::shared_ptr<alexaClientSDK::avsCommon::sdkInterfaces::MessageSenderInterface> messageSender,
      aace::engine::alexa::DeviceSettingsDelegate& deviceSettingsDelegate ) {
  
      std::shared_ptr<DoNotDisturbEngineImpl> doNotDisturbEngineImpl = nullptr;
  
      try
      {
          ThrowIfNull( doNotDisturbPlatformInterface, "invalidDoNotDisturbPlatformInterface" );
          ThrowIfNull( defaultEndpointBuilder, "invalidDefaultEndpointBuilder" );
          ThrowIfNull( connectionManager, "invalidConnectionManager" );
  
          doNotDisturbEngineImpl = std::shared_ptr<DoNotDisturbEngineImpl>( new DoNotDisturbEngineImpl( doNotDisturbPlatformInterface ) );
  
          ThrowIfNot( doNotDisturbEngineImpl->initialize( 
              defaultEndpointBuilder,
              connectionManager,
              customerDataManager,
              exceptionSender,
              messageSender,
              deviceSettingsDelegate ), "initializeDoNotDisturbEngineImplFailed" );
  
          return doNotDisturbEngineImpl;
      }
      catch( std::exception& ex ) {
          AACE_ERROR(LX(TAG,"create").d("reason", ex.what()));
          if( doNotDisturbEngineImpl != nullptr ) {
              doNotDisturbEngineImpl->shutdown();
          }
          return nullptr;
      }
  }
  
  void DoNotDisturbEngineImpl::doShutdown()
  {
      if( m_doNotDisturbPlatformInterface != nullptr ) {
          m_doNotDisturbPlatformInterface->setEngineInterface( nullptr );
      }
  
      if( m_doNotDisturbCapabilityAgent != nullptr )
      {
          m_connectionManager->removeConnectionStatusObserver( m_doNotDisturbCapabilityAgent );
          
          m_doNotDisturbCapabilityAgent->shutdown();
      }
  }
  
  void DoNotDisturbEngineImpl::onSettingNotification( const bool& value, alexaClientSDK::settings::SettingNotifications notification) {
      AACE_DEBUG(LX(TAG,"onSettingNotification").d("notification", notification));
      std::string stateString = value ? DND_ON : DND_OFF; 
      if( m_doNotDisturbPlatformInterface != nullptr ) {
          switch( notification ) {
              case alexaClientSDK::settings::SettingNotifications::AVS_CHANGE:
              // intentional fall-through
              case alexaClientSDK::settings::SettingNotifications::LOCAL_CHANGE:
                  m_doNotDisturbPlatformInterface->setDoNotDisturb( value );
                  m_doNotDisturbCapabilityAgent->sendReportEvent( stateString );
                  AACE_VERBOSE(LX(TAG,"onSettingNotification").d("DND ON", stateString));
                  break;
              case alexaClientSDK::settings::SettingNotifications::AVS_CHANGE_FAILED:
                  AACE_ERROR(LX(TAG,"onSettingNotificationFailed").d("reason", "AVS_CHANGE_FAILED"));
                  break;
              case alexaClientSDK::settings::SettingNotifications::LOCAL_CHANGE_FAILED:
                  AACE_ERROR(LX(TAG,"onSettingNotificationFailed").d("reason", "LOCAL_CHANGE_FAILED"));
                  break;
              case alexaClientSDK::settings::SettingNotifications::LOCAL_CHANGE_IN_PROGRESS:
              case alexaClientSDK::settings::SettingNotifications::AVS_CHANGE_IN_PROGRESS:
              case alexaClientSDK::settings::SettingNotifications::LOCAL_CHANGE_CANCELLED:
              case alexaClientSDK::settings::SettingNotifications::AVS_CHANGE_CANCELLED:
                  // Do nothing
                  break;
          }
      } else AACE_ERROR(LX(TAG,"onSettingNotificationFailed").d("reason", "no platform interface registered"));
  }
  
  // DoNotDisturbEngineInterface
  bool DoNotDisturbEngineImpl::onDoNotDisturbChanged( bool doNotDisturb )
  {
      if( m_doNotDisturbCapabilityAgent != nullptr ) {
          std::string stateString = doNotDisturb ? DND_ON : DND_OFF; 
          AACE_VERBOSE(LX(TAG,"onDoNotDisturbChanged").d("DND ON", stateString));
          auto m_dndModeSetting = m_doNotDisturbCapabilityAgent->getDoNotDisturbSetting();
          m_dndModeSetting->setLocalChange(doNotDisturb);
          if ( !m_doNotDisturbCapabilityAgent->sendChangedEvent( stateString ).get() ) {
              return false;
              AACE_ERROR(LX(TAG,"onDoNotDisturbChangedFailed").d("sendChangedEventFailed", "event not sent"));
          } else return true;
      }
      return false;
  }
  
  } // aace::engine::alexa
  } // aace::engine
  } // aace
  