/******************************************************************************/
/**
 * @file ftfci_decode.c
 *
 * @brief This file contains functions that provides demonstration of
 *        usage of FTFCI frame decoding
 *
 * The functions provided in the file provides demonstration on
 * usage of FTFCI frame decoding
 *
 * @copyright Copyright 2023 Antaris, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License 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 headers of the component                      */
/******************************************************************************/

#include "ftfci_decode.h"
#include "ft_config.h"
#include "file_transfer.h"
#include "suspend_resume.h"
#include "notify_apps.h"
#include "ftds_decode.h"
#include "ftsr.h"
#include "ftci_decode.h"
#include "ft_receiver.h"
#include "ft_debug.h"
#include "logger.h"
#include "message_frame_def.h"


/******************************************************************************/
/*                       Definition of local variables                        */
/******************************************************************************/
static s_string_info  		ftfci_rxd_frame;
static uint8_t 				continous_ping_only_receive_cntr =0;
tc_tm_id_e_ft               tctm_id_inform_ftfci = FT_TC_FTFCI;

/******************************************************************************/
/*                      Definition of exported variables                      */
/******************************************************************************/

#ifdef FT_SUSRES_TEST
extern ftm_db_params ftm_db_test;
#endif

/******************************************************************************/
/*                  Declaration of local function prototypes                  */
/******************************************************************************/

/**
 * @brief This function used to decode FTFCI frame
 *
 *
 * @param[in]  void  : none
 *
 * @return none
 * @retval void
 */
static void decode_ftfci_frame(void);

/**
 * @brief This function used to process the request as per the response code has received
 *
 *
 * @param[in]  response  : response code
 * @param[in]  waiting_time  : only valid for suspend request has initiated by sender node
 * timeout time of suspend request initiated by sender
 *
 * @return none
 * @retval void
 */
static void check_ftfci_response_code(e_ftfci_response_code response, uint16_t waiting_time);


/******************************************************************************/
/*                       Definition of local functions                        */
/******************************************************************************/

/**
 * @brief This function used to process the request as per the response code has received
 *
 */
static void check_ftfci_response_code(e_ftfci_response_code response, uint16_t waiting_time)
{
	static uint8_t report_sel_cntr = 0;
	ft_receiver_ping_rest();
	ft_debug_save_prev_frame_info(tctm_id_inform_ftfci ,response);
	switch (response)
	{
		case ftfci_suspend:
			log_id(LOG_INFO_L1,LOG_FTM,FTFCI_SUSPEND);
			ft_set_master_slave(sus_res_slave);
			ft_suspend(Suspend_Timeout_Mode_rqst,waiting_time,1);
			//prepare_sts_and_notify_receiver_app(transfer_suspended);
			break;

		case ftfci_suspend_savecontext:
            log_id(LOG_ERROR,LOG_FTM,FTFCI_SUSPEND_SAVECONTEXT);
			ft_set_master_slave(sus_res_slave);
			ft_suspend(Suspend_Savecontext_Mode_rqst,waiting_time,3);
			if(s_sus_res_info.sus_savctxt_ack_sent != 1)
			{
				prepare_sts_and_notify_receiver_app(transfer_suspended_savecontext);
			}
			else
			{
				/* already context saved so just send ACK */
				DEBUG_CPRINT(("FTM - send ACK only\n"));
				ft_savecontext_ack(1);
			}
			break;

		case ftfci_resume:
			log_id(LOG_INFO_L1,LOG_FTM,FTFCI_RESUME);
			ft_set_master_slave(sus_res_slave);
			ft_resume(Resume_Timeout_Mode_rqst,1);
//			prepare_sts_and_notify_receiver_app(transfer_resumed);
			break;

		case ftfci_resume_savecontext:
			log_id(LOG_INFO_L1,LOG_FTM,FTFCI_RESUME_SAVECONTEXT);
			ft_set_master_slave(sus_res_slave);
			set_file_transfer_state(ft_download);
			//sample_app_regisration_dwld();
			prepare_sts_and_notify_receiver_app(transfer_resumed_restorecontext);
			break;


		case ftfci_ack:
			log_id(LOG_INFO_L1,LOG_FTM,FTFCI_SUSPEND_RESUME_ACK_RECEIVED);
			DEBUG_CPRINT(("Suspend/ Resume ACK received\n"));
			ft_acceptance_received(prepare_sts_and_notify_receiver_app);
			break;

		case ftfci_nak: 
		    log_id(LOG_WARNING,LOG_FTM,FTFCI_SUSPEND_RESUME_NOT_ACK_RECEIVED);
			DEBUG_CPRINT((" Warning !!! Suspend/ Resume not ACK received\n"));
			ft_acceptance_nack(prepare_sts_and_notify_receiver_app);
			break;

		case ftfci_cancelled_by_susp_timeoout: 
            log_id(LOG_WARNING,LOG_FTM,FTFCI_CANCELLED_BY_SUSP_TIMEOUT);
			ft_terminate(T_SuspendTimeout, 0);
			prepare_sts_and_notify_receiver_app(tx_terminated_suspend_timeout_expired);
			break;

		case ftfci_ping:
			DEBUG_CPRINT(("FTM-PG\n"));
			if(dwnld_rqst.dwnld_cmp_sts != 0)
			{
				send_ftsr(dwnld_rqst.dwnld_cmp_sts,0);
			}
			else
			{
				if(continous_ping_only_receive_cntr < 3)
				{
					continous_ping_only_receive_cntr++;
					send_ftsr(ftsr_ping,0);
				}
				else
				{
					/* if ping request is received continuously without FTDS receive
					 * send head change request to sender
					 * check data loss
					 *  */
					continous_ping_only_receive_cntr =0;
					report_sel_cntr++;
					if(report_sel_cntr <  2)
	                                {
					ft_fsm_change_state(FT_Report_Head_Change);
					}
					else if(report_sel_cntr < 4)
					{
						ftsr_set_resend_flag(&dwnld_rqst);
                        ft_fsm_change_state(FT_Report_Sequence_loss);
                        DEBUG_CPRINT(("\nLRQST\n"));
					}
					else
					{
                        report_sel_cntr = 0;
					}
				}
			}
			break;



		case ftfci_cancelled_by_txnode:
            log_id(LOG_INFO_L1,LOG_FTM,FTFCI_CANCELLED_BY_TXNODE);
			ft_terminate(T_Txnode, 0);
			prepare_sts_and_notify_receiver_app(transmission_terminated_by_rx_node);
			break;

		default:
			break;
	}
}



/**
 * @brief This function used to decode FTFCI frame
 *
 *
 */
static void decode_ftfci_frame(void)
{
	s_file_tx_framework_ctrl_info *ftfci = (s_file_tx_framework_ctrl_info*)ftfci_rxd_frame.str_ptr;
	uint8_t sid = ft_rx_session_id_read();
	if(ftfci->ctrl.bit.file_tx_session_id != sid && ftfci->ctrl.bit.response_code != ftfci_cancelled_by_txnode)
	{
		// send invalid session id response to sender node
		send_ftsr(ftsr_invalid_session_id,0);
	}
	else
	{
		check_ftfci_response_code(ftfci->ctrl.bit.response_code,ftfci->suspend_wait_timeout);
	}
}

/******************************************************************************/
/*                      Definition of exported functions                      */
/******************************************************************************/


/**
 * @brief This function is used to clear the ping request counter value whenever FTDS has received
 * Receiver will receive ping request for every 20 sequences if sender continuously send
 * only ping for three times, receiver node will ask sender to change the head sequence
 * So the counter will monitor whether the sender only sending consequently ping request
 * for three times.
 *
 *
 */
void ftfci_clear_continous_ping_cntr(void)
{
	continous_ping_only_receive_cntr  = 0;
}


/**
 * @brief This API receives the FTFCI frame data from TC-TM then decode FTFCI frame
 *
 *
 */
void ft_receive_ftfci(uint8_t *ftfci_data, uint16_t ftfci_data_length)
{
	ftfci_rxd_frame.str_ptr = ftfci_data;
	decode_ftfci_frame();

}
