/**
 * @file ftsr_decode.c
 *
 * @brief This file contains functions that provides demonstration of
 *        usage of FTSR frame decoding APIs
 *
 * The functions provided in the file provides demonstration on
 * usage of  FTSR frame decoding APIs
 *
 * @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 "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "logger.h"

/******************************************************************************/
/*                      Include headers of the component                      */
/******************************************************************************/

#include "ftsr_decode.h"
#include "data_type.h"
#include "file_transfer.h"
#include "ftci.h"
#include "ftds.h"
#include "message_frame_def.h"
#include "notify_apps.h"
#include "segmentation.h"
#include "upload_def.h"
#include "suspend_resume.h"
#include "ftds_decode.h"
#include "ft_debug.h"
#include "ft_sender.h"
#include "ft_receiver.h"

/******************************************************************************/
/*                       Definition of local variables                        */
/******************************************************************************/

static s_ftsr_frame_buff 	ftsr_rxd_frame;

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

extern s_string_info dest_path_name_info;
extern ftm_db_params ftm_db_test;

/******************************************************************************/
/*                  Declaration of local function prototypes                  */
/******************************************************************************/
/**
 * @brief This function used to decode FTSR frame
 *
 *
 * @param[in]  void  : none
 *
 * @return none
 * @retval void
 */
static void decode_ftsr_frame(void);

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

/**
 * @brief This function used to read head sequence ID that to be update in sender side
 *
 *
 * @param[in]  void  : none
 *
 * @return none
 * @retval void
 */
static void update_head_position(void);

/**
 * @brief This function used to read missing sequence ID which was received in FTSR frame
 *
 *
 * @param[in]  void  : none
 *
 * @return none
 * @retval void
 */
static void log_missing_sequnce(void);

/******************************************************************************/
/*                       Definition of local functions                        */
/******************************************************************************/
/**
 * @brief This function used to terminate the file transfer due to upload error
 *
 *
 */
static void upload_error()
{
        ft_fsm_change_state(FT_Idle_State);
        set_file_transfer_state(ft_process_na);
	    ft_tx_session_id_update(FT_SESSION_ID_DEC);
}

/**
 * @brief This function used to read missing sequence ID which was received in FTSR frame
 *
 *
 */
static void log_missing_sequnce(void)
{
	uint16_t u16cnt;
	uint16_t frame_length_cntr;
	uint32_t *loc_ptr;
	s_file_tx_sts_resp *ftsr;
	ftsr = (s_file_tx_sts_resp*)ftsr_rxd_frame.ftsr_buf_ptr;
	frame_length_cntr = sizeof(s_file_tx_sts_resp);
	for(u16cnt = 0; u16cnt < ftsr->segment_loss_count; u16cnt++)
	{
		loc_ptr = (uint32_t*)(&ftsr_rxd_frame.ftsr_buf_ptr[frame_length_cntr]);
		ftds_update_resend_seq_id_list(*loc_ptr);
		frame_length_cntr = frame_length_cntr + 4;
	}
}

/**
 * @brief This function used to read head sequence ID that to be update in sender side
 *
 *
 */
static void update_head_position(void)
{
	uint8_t len_loc;
	len_loc = sizeof(s_file_tx_sts_resp);
	uint32_t *loc_ptr = (uint32_t*)&ftsr_rxd_frame.ftsr_buf_ptr[len_loc];

	ftds_change_head_position(*loc_ptr);
	ft_fsm_change_state(FT_Sequence_Transmission);


}


/**
 * @brief This function used to process the request as per the reponse code has received
 *
 *
 */
static void check_ftsr_response_code(e_ftsr_response_code response, uint16 waiting_time)
{

	static uint8_t test_var = 1;
	ftds_clear_ping_request();
	switch (response)
	{
		case ftsr_receiver_ready:
            log_id(LOG_INFO_L1,LOG_FTM,FTSR_RECEIVER_READY);
			/*change to next state since receiver node is ready for data packet receive */
			ft_fsm_change_state(FT_Segmentation);
			prepare_sts_and_notify_sender_app(transfer_upload_ready);
			break;

		case ftsr_rx_api_not_found:
            log_id(LOG_ERROR,LOG_FTM,FTSR_RECEIVER_API_NOT_FOUND);
            ft_fsm_change_state(FT_Idle_State);
            set_file_transfer_state(ft_process_na);
            prepare_sts_and_notify_sender_app(invalid_receiver_app_id);
			ft_set_err_sts(ft_receiver_app_not_reg_error);
			break;

		case ftsr_missing_pckts:
            log_id(LOG_WARNING,LOG_FTM,FTSR_MISSING_PACKETS);
			log_missing_sequnce();
			ft_fsm_change_state(FT_Sequence_Transmission);
			break;

		case ftsr_download_complete:
            log_id(LOG_INFO_L1,LOG_FTM,FTSR_UPLOAD_SUCCESS);
			/*transmission success */
			DEBUG_CPRINT(("Upload success\n"));
			prepare_sts_and_notify_sender_app(transfer_upload_success);
			if(test_var == 1)
			{
				ft_fsm_change_state(FT_Idle_State);
#ifndef FT_OBC
				ft_file_close(tx_info.fptr,&tx_info.file_opened, tx_info.tx_mode);
#endif
				set_file_transfer_state(ft_process_na);
			}
			else
			{
				test_var = 1;
			}
			ft_service_disable();
			break;

		case ftsr_crc_fail:
            log_id(LOG_ERROR,LOG_FTM,FTSR_CRC_ERROR);
			DEBUG_CPRINT(("CRC error\n"));
			prepare_sts_and_notify_sender_app(crc_error);
			ft_fsm_change_state(FT_Idle_State);
#ifndef FT_OBC
			ft_file_close(tx_info.fptr,&tx_info.file_opened, tx_info.tx_mode);
#endif
			set_file_transfer_state(ft_process_na);
			ft_service_disable();
			break;

		case ftsr_file_not_found:
            log_id(LOG_ERROR,LOG_FTM,FTSR_RECEIVER_SIDE_OTHER_CATEGORY_ERROR);
			DEBUG_CPRINT(("\r\n Receiver side other category error"));
			ft_set_err_sts(ft_receiver_side_undefined_error);
		    upload_error();
	        prepare_sts_and_notify_sender_app(invalid_receiver_app_id);
			break;


		case ftsr_head_change:
            log_id(LOG_WARNING,LOG_FTM,FTSR_HEAD_CHANGE);
            if(tx_info.receiver_is_ready == FT_FTSR_RECEIVER_READY_NOT_RECEIVED)
			{
				ft_transfer_request(T_Txnode,0);
    			DEBUG_CPRINT(("Session terminated since receiver ready not come\n"));
			}
			else
		    {
				update_head_position();
		    }
			break;

		case ftsr_ack:
            log_id(LOG_INFO_L3,LOG_FTM,FTSR_SUSPEND_RESUME_ACK_RECEIVED);
			DEBUG_CPRINT(("Suspend/ Resume ACK received\n"));
			ft_acceptance_received(prepare_sts_and_notify_sender_app);
			break;

		case ftsr_nak:
            log_id(LOG_WARNING,LOG_FTM,FTSR_SUSPEND_RECEIVE_NACK_RECEIVED);
		 	DEBUG_CPRINT(("Suspend/ Resume NACK received\n"));
			ft_acceptance_nack(prepare_sts_and_notify_sender_app);
			break;

		case ftsr_suspend:
            log_id(LOG_INFO_L1,LOG_FTM,FTSR_SUSPEND);
			ft_set_master_slave(sus_res_slave);
			ft_suspend(Suspend_Timeout_Mode_rqst,waiting_time,1);
//			prepare_sts_and_notify_sender_app(transfer_suspended);
			break;

		case ftsr_suspend_savecontext:
            log_id(LOG_INFO_L1,LOG_FTM,FTSR_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_sender_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 ftsr_resume:
            log_id(LOG_INFO_L1,LOG_FTM,FTSR_RESUME);
			ft_set_master_slave(sus_res_slave);
			ft_resume(Resume_Timeout_Mode_rqst,1);
			break;

		case ftsr_resume_savecontext:
            log_id(LOG_ERROR,LOG_FTM,FTSR_RESUME_SAVECONTEXT);
			ft_set_master_slave(sus_res_slave);
			set_file_transfer_state(ft_upload);
			prepare_sts_and_notify_sender_app(transfer_resumed_restorecontext);
			break;

		case ftsr_cancelled_by_suspend_timeoout:
            log_id(LOG_WARNING,LOG_FTM,FTSR_CANCELLED_BY_SUSPEND_TIMEOUT);
			ft_terminate(T_SuspendTimeout, 0);
			prepare_sts_and_notify_sender_app(tx_terminated_suspend_timeout_expired);
			break;

		case ftsr_terminate_rxnode:
            log_id(LOG_WARNING,LOG_FTM,FTSR_TERMINATE_RXNODE);
			ft_terminate(T_Rxnode, 0);
			prepare_sts_and_notify_sender_app(transmission_terminated_by_rx_node);
			break;

		case ftsr_ping:
            log_id(LOG_INFO_L3,LOG_FTM,FTSR_CLEAR_PING);
			DEBUG_CPRINT(("clear ping\n"));
			break;

    case ftsr_invalid_session_id:
    	    DEBUG_CPRINT(("\r\n ERROR Receiver discarded last frame due to Invalid session ID.\n"));
			break;

    case ftsr_dwnld_ptr_null:
    	    DEBUG_CPRINT(("\r\n ERROR Receiver side dwnld memory ptr null\n"));
			ft_set_err_sts(ft_rx_mem_ptr_null_error);
			upload_error();
	        prepare_sts_and_notify_sender_app(transfer_upload_rejected);
      break;

    case ftsr_ftm_busy:
    	    DEBUG_CPRINT(("\r\n ERROR RX busy with another session\n"));
			ft_set_err_sts(ft_framework_busy_error);
			upload_error();
	        prepare_sts_and_notify_sender_app(transfer_upload_rejected);
			break;
    case ftsr_invalid_cfg_input:
    	    DEBUG_CPRINT(("\r\n ERROR Input configuration invalid\n"));
			ft_set_err_sts(ft_rx_invld_input_cfg);
			upload_error();
	        prepare_sts_and_notify_sender_app(transfer_upload_rejected);
			break;
    case ftsr_rx_system_error:
    	    DEBUG_CPRINT(("\r\n ERROR Receiver side system / memory allocation error\n"));
			ft_set_err_sts(ft_rx_sys_error);
			upload_error();
	        prepare_sts_and_notify_sender_app(transfer_upload_rejected);
			break;        

		default:
			DEBUG_CPRINT(("\r\n ERROR FTSR invalid response code rxd\n"));
			break;
	}
}


/**
 * @brief This function used to decode FTSR frame
 *
 *
 */
static void decode_ftsr_frame(void)
{
	s_file_tx_sts_resp *ftsr = (s_file_tx_sts_resp*)ftsr_rxd_frame.ftsr_buf_ptr;
        uint8_t sid = ft_tx_session_id_read();
        if(ftsr->ctrl.bit.file_tx_session_id != sid)
        {
                 // send invalid session id response to sender node
        	     DEBUG_CPRINT(("\r\n ERROR Receiver discarded last frame due to Invalid session ID RCV%d != STR:%d.\n", ftsr->ctrl.bit.file_tx_session_id,sid));
                 
                 if(ftsr->ctrl.bit.response_code == ftsr_terminate_rxnode)
                 {
                   check_ftsr_response_code(ftsr->ctrl.bit.response_code,ftsr->suspend_wait_timeout);                 
                 }
        }
        else
        {
                 check_ftsr_response_code(ftsr->ctrl.bit.response_code,ftsr->suspend_wait_timeout);
        }

}

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

/**
 * @brief This API receives the FTSR frame data from TC-TM then decode FTSR frame
 *
 *
 */
void ft_receive_ftsr(uint8_t *ftsr_data, uint16_t ftsr_data_length)
{

	ftsr_rxd_frame.ftsr_buf_ptr = ftsr_data;
	decode_ftsr_frame();


}




