//*****************************************************************************
//
//! @file am_vos_ama_callback.c
//!
//! @brief Alexa AMA protocol callbacks for interactive operation
//
//*****************************************************************************

//*****************************************************************************
//
// Copyright (c) 2024, Ambiq Micro, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision ambiqvos_r4.5-fdfa8cf6a4 of the AmbiqSuite Development Package.
//
//*****************************************************************************

#include "accessories.pb.h"

#include "am_vos_utils.h"
#include "am_vos_board_setup.h"
#include "am_vos_init.h"
#include "am_vos_ama.h"

#if configUSE_AMVOS_AMA
void am_vos_ama_proc_notify_speech(SpeechState state)
{
    switch(state)
    {
        case SpeechState_IDLE :
            AM_VOS_LOG_INFO("[AMA] Cmd NOTIFY_SPEECH_STATE recv IDLE\n");
            break;

        case SpeechState_LISTENING :
            am_vos_ama_get_state_send(0x203);   // Checking network status
            AM_VOS_LOG_INFO("[AMA] Cmd NOTIFY_SPEECH_STATE recv LISTENING\n");
            break;

        case SpeechState_PROCESSING :
            AM_VOS_LOG_INFO("[AMA] Cmd NOTIFY_SPEECH_STATE recv PROCESSING\n");
            break;

        case SpeechState_SPEAKING :
            AM_VOS_LOG_INFO("[AMA] Cmd NOTIFY_SPEECH_STATE recv SPEAKING\n");
            break;

        default :  
            AM_VOS_LOG_INFO("[AMA] Cmd NOTIFY_SPEECH_STATE recv unknown %d\n", state);
            break;
    }
    return;
}
void am_vos_ama_proc_get_state(uint32_t feature)
{
    State sState = {0,};

    sState.feature = feature;

    switch(feature)
    {
        case 0x130:     // Bluetooth A2DP Enabled
            sState.which_value = sizeof(bool);
            sState.value.boolean = false;              // A2DP is disabled
            break;

        case 0x131:     // Bluetooth HFP Enabled
            sState.which_value = sizeof(bool);
            sState.value.boolean = false;              // HFP is disabled
            break;

        case 0x132:     // Bluetooth A2DP Connected
            sState.which_value = sizeof(bool);
            sState.value.boolean = false;              // A2DP is not connected
            break;

        case 0x133:     // Bluetooth HFP Connected
            sState.which_value = sizeof(bool);
            sState.value.boolean = false;              // HFP is not connected
            break;

        case 0x137:     // SCO Prioritization Enabled
            sState.which_value = sizeof(bool);
            sState.value.boolean = false;              // SCO prioritization disabled
            break;

        case 0x202:     // DND (Do not disturb) mode
            sState.which_value = sizeof(bool);
            sState.value.boolean = false;              // DND is disabled
            break;

        case 0x204:     // Privacy mode
            sState.which_value = sizeof(bool);
            sState.value.boolean = false;              // Privacy mode is disabled
            break;

        default:  
            break;
    }

    if(sState.which_value)
        am_vos_ama_get_state_rsp_send(&sState);
    else
        am_vos_ama_rsp_send(Command_GET_STATE, ErrorCode_UNSUPPORTED);      // if unknown feature was requested.

    return;
}

void am_vos_ama_proc_set_state(State *pState)
{
    switch(pState->feature)
    {
        case 0x400 :    // AVRCP Override
            if(pState->value.boolean == 0)
            {
                AM_VOS_LOG_DEBUG("[AMA] Regular AVRCP commands are being sent.\n");
            }
            else if(pState->value.boolean == 1)
            {
                AM_VOS_LOG_DEBUG("[AMA] Accessory is sending Media control commands.\n");
            }
            am_vos_ama_rsp_send(Command_SET_STATE, ErrorCode_SUCCESS);
            break;

        default :
            AM_VOS_LOG_DEBUG("[AMA] Unknown feature 0x%X (Not supported)\n", pState->feature);
            am_vos_ama_rsp_send(Command_SET_STATE, ErrorCode_UNSUPPORTED);
            break;
    }
    return;
}

void am_vos_ama_proc_sync_state(State *pState)
{
    switch(pState->feature)
    {
        case 0x135 :    // Bluetooth A2DP Active
            if(pState->value.boolean == 0)
            {
                AM_VOS_LOG_DEBUG("[AMA] A2DP is not active\n");
            }
            else if(pState->value.boolean == 1)
            {
                AM_VOS_LOG_DEBUG("[AMA] A2DP is active\n");
            }
            break;

        case 0x136 :    // Bluetooth HFP Active
            if(pState->value.boolean == 0)
            {
                AM_VOS_LOG_DEBUG("[AMA] HFP is not active\n");
            }
            else if(pState->value.boolean == 1)
            {
                AM_VOS_LOG_DEBUG("[AMA] HFP is active\n");
            }
            break;

        case 0x203 :
            if(pState->value.integer == 0)      // Device Network Connectivity Status
            {
                AM_VOS_LOG_DEBUG("[AMA] Network is in good condition\n");
            }
            else if(pState->value.integer == 1)
            {
                AM_VOS_LOG_DEBUG("[AMA] Network is slow\n");
            }
            else if(pState->value.integer == 2)
            {
                AM_VOS_LOG_DEBUG("[AMA] Network is not available\n");
            }
            else
            {
                AM_VOS_LOG_DEBUG("[AMA] Invailid value: %d\n", pState->value.integer);
            }
            break;

        default :
            break;
    }
    am_vos_ama_rsp_send(Command_SYNCHRONIZE_STATE, ErrorCode_SUCCESS);

    return;
}

void am_vos_ama_event_callback(Command cmd, void* pMsg, bool bResponse)
{

    ProvideSpeech *pProvideSpeech;
    StopSpeech *pStopSpeech;
    EndpointSpeech *pEndpointSpeech;
    NotifySpeechState *pSpeechState;
    GetState *pGetState;
    SetState *pSetState;
    SynchronizeState *pSyncState;
    CentralInformation *pCentralInfo;
    IssueMediaControl *pIssueMediaControl;

    switch(cmd)
    {
        case Command_PROVIDE_SPEECH :
            pProvideSpeech = (ProvideSpeech *)pMsg;
            am_vos_ama_provide_speech_rsp_send(pProvideSpeech->dialog.id);
            AM_VOS_LOG_INFO("[AMA] Cmd PROVIDE_SPEECH dialog = %d\n", pProvideSpeech->dialog.id);
            break;

        case Command_START_SPEECH :
            AM_VOS_LOG_INFO("[AMA] Cmd START_SPEECH Ack recv\n");
            break;

        case Command_STOP_SPEECH :
            pStopSpeech = (StopSpeech *)pMsg;
            am_vos_ama_speech_rsp_send(Command_STOP_SPEECH, pStopSpeech->dialog.id);
            AM_VOS_LOG_INFO("[AMA] Cmd STOP_SPEECH dialog %d err_no %d recv\n", pStopSpeech->dialog.id, pStopSpeech->error_code);
            break;

        case Command_ENDPOINT_SPEECH :
            pEndpointSpeech = (EndpointSpeech *)pMsg;
            am_vos_ama_speech_rsp_send(Command_ENDPOINT_SPEECH, pEndpointSpeech->dialog.id);
            AM_VOS_LOG_INFO("[AMA] Cmd ENDPOINT_SPEECH dialog %d recv\n", pEndpointSpeech->dialog.id);
            break;

        case Command_NOTIFY_SPEECH_STATE :
            pSpeechState = (NotifySpeechState *)pMsg;
            am_vos_ama_proc_notify_speech(pSpeechState->state);
            break;
            
        case Command_GET_DEVICE_INFORMATION :
            am_vos_ama_get_devinfo_rsp_send();
            AM_VOS_LOG_INFO("[AMA] Cmd GET_DEVICE_INFORMATION recv\n");
            break;

        case Command_GET_DEVICE_CONFIGURATION :
            am_vos_ama_get_devconf_rsp_send();
            AM_VOS_LOG_INFO("[AMA] Cmd GET_DEVICE_CONFIGURATION recv\n");
            break;

        case Command_START_SETUP :
            am_vos_ama_rsp_send(Command_START_SETUP, ErrorCode_SUCCESS);   
            AM_VOS_LOG_INFO("[AMA] Cmd START_SETUP recv\n");
            break;

        case Command_COMPLETE_SETUP :
            am_vos_ama_rsp_send(Command_COMPLETE_SETUP, ErrorCode_SUCCESS);
            AM_VOS_LOG_INFO("[AMA] Cmd COMPLETE_SETUP recv\n");
            break;

        case Command_SYNCHRONIZE_SETTINGS :
            am_vos_ama_rsp_send(Command_SYNCHRONIZE_SETTINGS, ErrorCode_SUCCESS);
            am_vos_ama_get_central_info_send();         // Get central information (iOS or Android)
            AM_VOS_LOG_INFO("[AMA] Cmd SYNCHRONIZE_SETTINGS recv\n");
            break;

        case Command_KEEP_ALIVE :
            am_vos_ama_rsp_send(Command_KEEP_ALIVE, ErrorCode_SUCCESS);
            AM_VOS_LOG_INFO("[AMA] Cmd KEEP_ALIVE recv\n");
            break;
    
        case Command_GET_STATE :
            if(bResponse)
            {
                State *pState;
                pState = (State *)pMsg;
                AM_VOS_LOG_INFO("[AMA] Cmd GET_STATE ACK recv feature 0x%x value %d integer %d boolean %d\n",
                                pState->feature, pState->which_value == 1?
                                  pState->value.boolean : pState->value.integer, pState->value.integer,
                                  pState->value.boolean);
            }
            else
            {
                pGetState = (GetState *)pMsg;
                AM_VOS_LOG_INFO("[AMA] Cmd GET_STATE recv feature 0x%x\n", pGetState->feature);
                am_vos_ama_proc_get_state(pGetState->feature);
            }
            break;

        case Command_SET_STATE :
            pSetState = (SetState *)pMsg;
            AM_VOS_LOG_INFO("[AMA] Cmd Command_SET_STATE recv feature 0x%x value %d\n",
                            pSetState->state.feature, pSetState->state.which_value == 1?
                              pSetState->state.value.boolean : pSetState->state.value.integer);
            am_vos_ama_proc_set_state(&(pSetState->state));
            break;

        case Command_SYNCHRONIZE_STATE :
            if(bResponse == 0)
            {
                pSyncState = (SynchronizeState *)pMsg;
                AM_VOS_LOG_INFO("[AMA] Cmd SYNCHRONIZE_STATE recv feature 0x%x value %d integer %d boolean %d\n",
                                pSyncState->state.feature, pSyncState->state.which_value == 1?
                                  pSyncState->state.value.boolean : pSyncState->state.value.integer, pSyncState->state.value.integer,
                                  pSyncState->state.value.boolean);

                am_vos_ama_proc_sync_state(&(pSyncState->state));
            }
            break;

        case Command_GET_CENTRAL_INFORMATION :
            if(bResponse)
            {
                pCentralInfo = (CentralInformation *)pMsg;
                g_sVosSys.ui8AlexaAppPlatform = (uint8_t)(pCentralInfo->platform);
                AM_VOS_LOG_INFO("[AMA] Platform : %d Name : %s\n", pCentralInfo->platform, pCentralInfo->name);
            }
            break;

        case Command_ISSUE_MEDIA_CONTROL :
            pIssueMediaControl = (IssueMediaControl *)pMsg;
            AM_VOS_LOG_INFO("[AMA] Cmd Command_ISSUE_MEDIA_CONTROL recv contol 0x%x\n", pIssueMediaControl->control);
            break;
            
        default :
            //AM_VOS_LOG_INFO("[AMA] Cmd %d recv\n", cmd);
            break;
    }
}
#endif
