/******************************************************************************/
/**
 * @file file_transfer.c
 *
 * @brief This file contains functions that provides demonstration of
 *        usage of app notification
 *
 * The functions provided in the file provides demonstration on
 * usage of app registration and app notification 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 headers of the component                      */
/******************************************************************************/

#include "notify_apps.h"
#include "download_def.h"
#include "stdio.h"
#include "ft_receiver.h"
#include "file_integrity_check.h"
#include "exo_types.h"
#include "logger.h"

/******************************************************************************/
/*                  Definition of local function like macros                  */
/******************************************************************************/

#define FT_APP_MAX_LIMIT 5




/******************************************************************************/
/*          Definition of local types (typedef, enum, struct, union)          */
/******************************************************************************/


/**
 * @brief App registration details
 */
typedef struct ft_app_register
{
	uint16_t app_id;		///< Application ID
	notify_api app_api;     ///< Application callback
}s_ft_app_register;


/**
 * @brief Cumulative App registration details
 */
typedef struct ft_app_list
{
	uint16_t registered_app_cnt;					///< No of registered app
	s_ft_app_register app_list[FT_APP_MAX_LIMIT];   ///< App ID and callback for each app
}s_ft_app_list;


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



s_ft_app_list sender_apps =
{
		0,
		{
        { 0, NULL},
  		{ 0, NULL},
  		{ 0, NULL},
  		{ 0, NULL},
  		{ 0, NULL},
    }
};

s_ft_app_list receiver_apps =
{
		0,
		{
        { 0, NULL},
  		{ 0, NULL},
  		{ 0, NULL},
  		{ 0, NULL},
  		{ 0, NULL},
    }
};



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

extern s_treceive_info dwnld_rqst;

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


static void    save_context_info(ft_notification_info* sts);

/**
 * @brief This function used to search the registered sender app and invoke for app notification
 *
 * @param[in]  notify_info : type of notfifcation and info
 *
 * @return status of notification invoke
 * @retval 1 indicates notification published successfully
 */
static uint8_t ft_notify_sender_app(ft_notification_info* notify_info);

/**
 * @brief This function used to search the registered receiver app and invoke for app notification
 *
 * @param[in]  notify_info : type of notification and info
 *
 * @return status of notification invoke
 * @retval 1 indicates notification published successfully
 */
static uint8_t ft_notify_receiver_app(ft_notification_info* notify_info);


/**
 * @brief This function used to register notification callback function with FTM
 *
 * @param[in]  apps : pointer to structure that will contain table of sender or receiver app
 * @param[in]  app_id : app ID to be registered
 * @param[in]  app_api : callback to be registered
 *
 * @return status of registration
 * @retval 1 indicates notification api registered successfully
 */
static uint8_t register_apps(s_ft_app_list* apps, uint16_t app_id, notify_api app_api);

/**
 * @brief This function used to de register notification callback function if duplicate entry has found
 *
 * @param[in]  apps : pointer to structure that will contain table of sender or receiver app
 * @param[in]  app_id : app ID to be registered
 *
 * @return status of app removal
 * @retval 1 indicates notification callback removed successfully
 */
static void    remove_duplicate_entry(s_ft_app_list* apps, uint16_t app_id);

/**
 * @brief This function used to invoke notification callback function
 *
 * @param[in]  apps : pointer to structure that will contain table of sender or receiver app
 * @param[in]  notify_info : information to be published
 *
 * @return status of app invoking
 * @retval 1 indicates notification callback invoked successfully
 */
static uint8_t invoke_app_api(s_ft_app_list* apps,ft_notification_info* notify_info);


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


static void save_context_info(ft_notification_info* sts)  //uint8_t *save_info, uint16_t *size)
{
	uint16_t calc_buf_size;
	e_ft_current_process ft_state;
	uint32_t checksum;
	uint32_t data_dwnld_sofar;


	ft_state =  get_file_transfer_state();
	if(ft_state == ft_upload)
	{
		if(tx_info.tx_mode == 1)
		{
			calc_buf_size = sizeof(ft_contextsave_info) + sizeof(s_transfer_info) + sizeof(s_segment_info) + 4;
		}
		else
		{
			calc_buf_size = sizeof(ft_contextsave_info) + sizeof(s_transfer_info) + sizeof(s_segment_info) + tx_info.file_name_size + 4;
		}

		sts->context_info.context_info_buf_ptr  = os_malloc(calc_buf_size);
		if(sts->context_info.context_info_buf_ptr != NULL)
		{
			DEBUG_CPRINT(("Malloc %d \n",calc_buf_size));


			if(tx_info.tx_mode == 1)
			{
				/* if suspend requested during bulk data tx mode,
				 * calculate checksum for input bufferr and save the checksum value in
				 * context header.
				 */
				sts->context_info.bulkdata_checksum = tx_info.checksum;
				sts->context_info.bulkdata_len = tx_info.size;
				sts->context_info.bulkdata_mem_addr = (ptr_typ)tx_info.mptr & 0xffffffff;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
				DEBUG_CPRINT(("BULKDATA Checksum: 0x%luX\n",sts->context_info.bulkdata_checksum));
				DEBUG_CPRINT(("BULKDATA Mem_ptr: 0x%luX\n",(ptr_typ)tx_info.mptr));
#pragma GCC diagnostic pop
			}

			sts->context_info.tx_mode = tx_info.tx_mode;
			sts->context_info.context_info_size = calc_buf_size;
			sts->context_info.session_id = 0;
			sts->context_info.node_operation = ft_upload;
			sts->context_info.file_name_size = tx_info.file_name_size;
			sts->context_info.fsm_state_save = ft_get_state_before_suspend();
			sts->context_info.mast_slave_sel = ft_get_master_slave_status();

			/* copy context info */
			memcpy(&sts->context_info.context_info_buf_ptr[0],&sts->context_info,sizeof(ft_contextsave_info));
			/* copy tx info */
			calc_buf_size = sizeof(ft_contextsave_info);
			memcpy(&sts->context_info.context_info_buf_ptr[calc_buf_size],&tx_info,sizeof(s_transfer_info));
			/* copy segment info */
			calc_buf_size = sizeof(ft_contextsave_info) + sizeof(s_transfer_info);
			memcpy(&sts->context_info.context_info_buf_ptr[calc_buf_size],&seg_info,sizeof(s_segment_info));

			if(tx_info.tx_mode == 0)
			{
				/* copy file name and path info */
				calc_buf_size = sizeof(ft_contextsave_info) + sizeof(s_transfer_info) + sizeof(s_segment_info);
				memcpy(&sts->context_info.context_info_buf_ptr[calc_buf_size],input_file_name,tx_info.file_name_size);
			}

			/* calculate checksum and apped CRC of 4 bytes */
			checksum = calc_checksum_bulkdata(sts->context_info.context_info_buf_ptr, sts->context_info.context_info_size-4);
			if(tx_info.tx_mode == 1)
			{
				calc_buf_size = sizeof(ft_contextsave_info) + sizeof(s_transfer_info) + sizeof(s_segment_info) ;
			}
			else
			{
				calc_buf_size = sizeof(ft_contextsave_info) + sizeof(s_transfer_info) + sizeof(s_segment_info) +tx_info.file_name_size ;
			}
			memcpy(&sts->context_info.context_info_buf_ptr[calc_buf_size],&checksum,4);
			//sts->context_info.context_info_size += 4;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
			DEBUG_CPRINT(("Calculated checksum %luX\n",checksum));
#pragma GCC diagnostic pop
			DEBUG_CPRINT(("Save upload context pass:%d\n",sts->context_info.context_info_size));

		}
		else
		{
			DEBUG_CPRINT(("Save upload context malloc fail \n"));
			ft_set_err_sts(ft_sc_malloc_error);
		}
	}
	else if(ft_state == ft_download)
	{
		/*
		 *
		 * Expected buffer size is 150 bytes approximately and it shouldn't excide 200-4
		 */
		if(dwnld_rqst.tx_mode == 1)
		{
			calc_buf_size = sizeof(ft_contextsave_info) + sizeof(s_treceive_info) +4;
		}
		else
		{
			calc_buf_size = sizeof(ft_contextsave_info) + sizeof(s_treceive_info) + dwnld_rqst.file_name_buf_length +4;
		}
		sts->context_info.context_info_buf_ptr = os_malloc(calc_buf_size);
		if(sts->context_info.context_info_buf_ptr != NULL)
		{


// NOR copy update	if(dwnld_rqst.tx_mode == 1)
			{
				/* if suspend requested during bulk data tx mode,
				 * calculate checksum for bytes downloaded so far and save the checksum value in
				 * context header.
				 */
				data_dwnld_sofar = dwnld_rqst.pckt_seq_head * dwnld_rqst.seq_payload_len;
				sts->context_info.bulkdata_checksum = calc_checksum_bulkdata(dwnld_rqst.mptr, data_dwnld_sofar);
				sts->context_info.bulkdata_len = data_dwnld_sofar;
				sts->context_info.bulkdata_mem_addr = (ptr_typ)dwnld_rqst.mptr;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
				DEBUG_CPRINT(("BULKDATA Checksum: 0x%lu for size %lu\n",sts->context_info.bulkdata_checksum,data_dwnld_sofar));
				DEBUG_CPRINT(("BULKDATA Mem_ptr: 0x%luX\n",(ptr_typ)dwnld_rqst.mptr));
#pragma GCC diagnostic pop
			}

			sts->context_info.tx_mode = dwnld_rqst.tx_mode;
			sts->context_info.context_info_size = calc_buf_size;
			sts->context_info.session_id = 0;
			sts->context_info.node_operation = ft_download;
			sts->context_info.file_name_size = dwnld_rqst.file_name_buf_length;
			sts->context_info.fsm_state_save = ft_get_state_before_suspend();
			sts->context_info.mast_slave_sel = ft_get_master_slave_status();

			/* copy context info */
			memcpy(&sts->context_info.context_info_buf_ptr[0],&sts->context_info,sizeof(ft_contextsave_info));
			/* copy file name and path info */
			calc_buf_size = sizeof(ft_contextsave_info);
			memcpy(&sts->context_info.context_info_buf_ptr[calc_buf_size],&dwnld_rqst,sizeof(s_treceive_info));

			if(dwnld_rqst.tx_mode == 0)
			{
				/* copy file name and path info */
				calc_buf_size = sizeof(ft_contextsave_info) + sizeof(s_treceive_info);
				memcpy(&sts->context_info.context_info_buf_ptr[calc_buf_size],dwnld_rqst.file_name,dwnld_rqst.file_name_buf_length);
			}
			/* calculate checksum and apped CRC of 4 bytes */
			checksum = calc_checksum_bulkdata(sts->context_info.context_info_buf_ptr, sts->context_info.context_info_size-4);
			if(dwnld_rqst.tx_mode == 0)
			{
				calc_buf_size = sizeof(ft_contextsave_info) + sizeof(s_treceive_info) + dwnld_rqst.file_name_buf_length ;
			}
			else
			{
				calc_buf_size = sizeof(ft_contextsave_info) + sizeof(s_treceive_info);
			}
			memcpy(&sts->context_info.context_info_buf_ptr[calc_buf_size],&checksum,4);
			//sts->context_info.context_info_size += 4;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
			DEBUG_CPRINT(("Calculated checksum %luX\n",checksum));
#pragma GCC diagnostic pop
			DEBUG_CPRINT(("Save download context pass, Size:%d\n",sts->context_info.context_info_size));
		}
		else
		{
			ft_set_err_sts(ft_sc_malloc_error);
			DEBUG_CPRINT(("Save download context malloc fail \n"));
		}
	}
	else
	{
		DEBUG_CPRINT(("FTM Save context not prepared since state in ft_no _process\n"));
		sts->context_info.context_info_buf_ptr = NULL;
	}

}



/**
 * @brief This function used to invoke notification callback function
 */
static uint8_t invoke_app_api(s_ft_app_list* apps,ft_notification_info* notify_info)
{
	uint8_t ret =0;
	uint8_t u8cnt;
	//DEBUG_CPRINT(("Searching App ID : %x\n",notify_info->app_id));

	for (u8cnt = 0; u8cnt < FT_APP_MAX_LIMIT; u8cnt++)
	{
		if(apps->app_list[u8cnt].app_id == notify_info->app_id)
		{
			//DEBUG_CPRINT(("App found\n"));
			if(apps->app_list[u8cnt].app_api != NULL)
			{
				//DEBUG_CPRINT(("Invoking API\n"));
				apps->app_list[u8cnt].app_api(notify_info);
				ret = 1;
			}
			else
			{
				DEBUG_CPRINT(("App FP Null !\n"));
			}
			break;
		}
	}
	if(ret != 1)
	{
		DEBUG_CPRINT(("Error App:0x%dX not registered\n",notify_info->app_id));

	}
	return ret;
}




/**
 * @brief This function used to de register notification callback function if duplicate entry has found
 */
static void remove_duplicate_entry(s_ft_app_list* apps, uint16_t app_id)
{
	uint8_t u8cnt;

	for (u8cnt = 0; u8cnt < FT_APP_MAX_LIMIT; u8cnt++)
	{
		if(apps->app_list[u8cnt].app_id == app_id)
		{
			apps->app_list[u8cnt].app_api = NULL;
			apps->app_list[u8cnt].app_id = 0;
			DEBUG_CPRINT(("app duplicated\n"));
			break;
		}
	}
}

/**
 * @brief This function used to register notification callback function with FTM
 *
 */
static uint8_t register_apps(s_ft_app_list* apps, uint16_t app_id, notify_api app_api)
{
	uint8_t u8cnt;
	uint8_t ret =0;
	if(apps->registered_app_cnt < FT_APP_MAX_LIMIT)
	{
		remove_duplicate_entry(apps, app_id);
		for (u8cnt = 0; u8cnt < FT_APP_MAX_LIMIT; u8cnt++)
		{
			if(apps->app_list[u8cnt].app_api == NULL)
			{
				apps->app_list[u8cnt].app_api = app_api;
				apps->app_list[u8cnt].app_id = app_id;
				apps->registered_app_cnt++;
				ret = 1;
				DEBUG_CPRINT(("FTM App registered at [%d]\n",u8cnt));
				break;
			}
		}
	}
	return ret;
}


/**
 * @brief This function used to search the registered sender app and invoke for app notification
 */
static uint8_t ft_notify_sender_app(ft_notification_info* notify_info)
{
	uint8_t ret =0;
	DEBUG_CPRINT(("\r\n-----/Sender side notify/-----\n"));
	ret = invoke_app_api(&sender_apps,notify_info);
	return ret;
}


static uint8_t ft_notify_receiver_app(ft_notification_info* notify_info)
{
	uint8_t ret =0;
	DEBUG_CPRINT(("\r\n-----/Receiver side notify-----\n"));
	ret = invoke_app_api(&receiver_apps,notify_info);
	return ret;
}


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

/**
 * @brief This function used to initialize notification related params
 *
 *
 */
void ft_init_notify()
{
	uint8_t u8cnt;
	DEBUG_CPRINT(("Delete notify apps register\n"));

	for (u8cnt = 0; u8cnt < FT_APP_MAX_LIMIT; u8cnt++)
	{
		sender_apps.app_list[u8cnt].app_api = NULL;
		sender_apps.app_list[u8cnt].app_id = 0;
		receiver_apps.app_list[u8cnt].app_api = NULL;
		receiver_apps.app_list[u8cnt].app_id = 0;
	}
	sender_apps.registered_app_cnt = 0;
	receiver_apps.registered_app_cnt = 0;

}


/**
 * @brief This function used to check that notification callback has been registered for the requested app id
 *
 *
 */
uint8_t is_sender_app_resgistered(uint16_t input_app_id)
{
	uint8_t ret =0;
	uint8_t u8cnt;
	//DEBUG_CPRINT(("Searching App ID : %x\n",notify_info->app_id));

	for (u8cnt = 0; u8cnt < FT_APP_MAX_LIMIT; u8cnt++)
	{
		if(sender_apps.app_list[u8cnt].app_id == input_app_id)
		{
			//DEBUG_CPRINT(("App found\n"));
			if(sender_apps.app_list[u8cnt].app_api != NULL)
			{
				ret = 1;
			}
			else
			{
				DEBUG_CPRINT(("App FP Null !\n"));
			}
			break;
		}
	}
	if(ret != 1)
	{
		DEBUG_CPRINT(("Error App not registered\n"));

	}
	return ret;
}

/*
 * this api receives the sender side notification function and registered with FT
 */
uint8_t ft_register_sender_app(uint16_t input_app_id, notify_api input_app_api)
{
	uint8_t ret =0;
	ret = register_apps(&sender_apps, input_app_id, input_app_api);
	return ret;
}



/*
 * this api receives the receiver side notification function and registered with FT
 */
uint8_t ft_register_receiver_app(uint16_t input_app_id, notify_api input_app_api)
{
	uint8_t ret =0;
	ret = register_apps(&receiver_apps, input_app_id, input_app_api);
	return ret;
}



/**
 * @brief This function used to restart the transmission
 *
 */
void restart_transmission()
{
	ft_fsm_change_state(s_sus_res_info.fsm_state_save);
	DEBUG_CPRINT(("Resumed - Write back FSM state %d \n",s_sus_res_info.fsm_state_save));
	print_current_fsmstate();
	ft_set_timer(FTDP_WAITING_TIME_INTERVAL);
	s_sus_res_info.state = no_suspend_reusume;
}


/**
 * @brief This function used to restart the transmission without FTDS interval timer ON
 *
 */
void restart_transmission_no_timer_set()
{
	ft_fsm_change_state(s_sus_res_info.fsm_state_save);
	DEBUG_CPRINT(("Resumed - Write back FSM state %d \n",s_sus_res_info.fsm_state_save));
	print_current_fsmstate();
	//ft_set_timer(FTDP_WAITING_TIME_INTERVAL);
	s_sus_res_info.state = no_suspend_reusume;
}

/**
 * @brief This function used to handle the positive acknowledgment received for suspend or resume request
 *
 */
void ft_acceptance_received(notify_complete_sts_fp n_fp)
{

	e_ft_current_process ft_state;
	ft_state =  get_file_transfer_state();


	DEBUG_CPRINT(("s_sus_res_info.state =%d\n",s_sus_res_info.state));
	DEBUG_CPRINT(("s_sus_res_info.type =%d\n",s_sus_res_info.type));
	DEBUG_CPRINT(("s_sus_res_info.sus_res_state_copy =%d\n",s_sus_res_info.sus_res_state_copy));
	DEBUG_CPRINT(("ft_state =%d\n",ft_state));

	if( (s_sus_res_info.state == state_suspend)  ||
	  ( (s_sus_res_info.sus_res_state_copy == state_suspend) && (ft_state == ft_download) ) )
	{
		if(s_sus_res_info.type == suspend_by_timeout)
		{
			n_fp(transfer_suspend_accepted);
			clear_sus_res_req_retry_cntr();
			s_sus_res_info.state = state_suspend;
			s_sus_res_info.sus_res_state_copy = no_suspend_reusume;
		}
		else if(s_sus_res_info.type == suspend_by_savecontext)
		{
			n_fp(transfer_suspend_savecontext_accepeted);
			clear_sus_res_req_retry_cntr();
			ft_stop_timer();
			s_sus_res_info.sus_res_state_copy = no_suspend_reusume;
		}
		else
		{

		}
	}
	else if(s_sus_res_info.state == state_resume)
	{
		if(s_sus_res_info.type == suspend_by_timeout)
		{
			restart_transmission();
			n_fp(transfer_resume_accepted);
			clear_sus_res_req_retry_cntr();
			s_sus_res_info.sus_res_state_copy = no_suspend_reusume;
		}
		else if(s_sus_res_info.type == suspend_by_savecontext)
		{
			restart_transmission();
			n_fp(transfer_resume_savecontext_accepeted);
			s_sus_res_info.sus_res_state_copy = no_suspend_reusume;
		}
		else
		{

		}
	}

	if(s_sus_res_info.request_clear_flag == 1)
	{
		/* clear suspend/request request flag if ack is received */
		s_sus_res_info.request_clear_flag = 0;
	}
}


/**
 * @brief This function used to handle the negative acknowledgment received for suspend or resume request
 *
 */
void ft_acceptance_nack(notify_complete_sts_fp n_fp)
{
	if(s_sus_res_info.state == state_suspend)
	{
		DEBUG_CPRINT(("Warning !!! Suspend not accepted \n"));
		if(s_sus_res_info.type == suspend_by_timeout)
		{
			restart_transmission();
			n_fp(transfer_suspend_tout_not_accepted);
		}
		else if(s_sus_res_info.type == suspend_by_savecontext)
		{
			restart_transmission();
			n_fp(transfer_suspend_savecontext_failed);
		}
		else
		{

		}
	}
	else if(s_sus_res_info.state == state_resume)
	{
		DEBUG_CPRINT(("Warning !!! Resume not accepted \n"));
		if(s_sus_res_info.type == suspend_by_timeout)
		{
			s_sus_res_info.state = state_suspend;
			ft_fsm_change_state(FT_Suspended);
			n_fp(transfer_rseume_tout_not_accepted);
		}
		else if(s_sus_res_info.type == suspend_by_savecontext)
		{
			ft_fsm_change_state(FT_Inactive);
			set_file_transfer_state(ft_process_na);
			n_fp(transfer_resume_restorecontext_failed);
		}

	}

	if(s_sus_res_info.request_clear_flag == 1)
	{
		/* clear suspend/request request flag if ack is received */
		s_sus_res_info.request_clear_flag = 0;
	}
}







/**
 * @brief This function used to update the notification structure with status information
 * that will be passed to application notification callbacks for sender side.
 *
 */
uint8_t prepare_sts_and_notify_sender_app(ft_status_type status)
{
	uint8_t ret=0;
	ft_notification_info sts;
	sts.app_id = tx_info.app_id;
	sts.status = status;

	switch(status)
	{
		case transfer_upload_success:
			DEBUG_CPRINT(("File uploaded successfully !!! \n"));
			log_id(LOG_INFO_L1, LOG_FTM, FILE_UPLOADED_SUCCESSFULLY);
			sts.dwld_info.tx_mode = tx_info.tx_mode;
			sts.dwld_info.size_file_or_data = tx_info.size;
			break;

		case crc_error:
			DEBUG_CPRINT(("File uploaded failed - CRC error reported !!! \n"));
			log_id(LOG_ERROR, LOG_FTM, FILE_UPLOADED_FAILED_CRC_ERROR_REPORTED);
			break;

		case transfer_suspend_accepted:
			DEBUG_CPRINT(("File uploaded Suspended !!! \n"));
			break;

		case transfer_suspend_savecontext_accepeted:
			DEBUG_CPRINT(("Save context accepted by Receiver !!! \n"));
#ifndef FT_OBC
			ft_file_close(tx_info.fptr,&tx_info.file_opened, tx_info.tx_mode);
#endif
			sts.context_info.session_id = 0;
			sts.context_info.node_operation = ft_upload;
			save_context_info(&sts);
			ft_fsm_change_state(FT_Inactive);
			set_file_transfer_state(ft_process_na);
			break;

		case transfer_suspended_savecontext:
		{
			DEBUG_CPRINT(("Close file %s\n",input_file_name));
#ifndef FT_OBC
			ft_file_close(tx_info.fptr,&tx_info.file_opened, tx_info.tx_mode);
#endif
			save_context_info(&sts);
			if(sts.context_info.context_info_buf_ptr == NULL)
			{
				ft_transfer_request(Suspend_Savecontext_nack_rqst,0);
				return 0;
			}
		}

		default:
			break;
	}

	ret = ft_notify_sender_app(&sts);
	return ret;
}


/**
 * @brief This function used to update the notification structure with status information
 * that will be passed to application notification callbacks for receiver side.
 */
uint8_t prepare_sts_and_notify_receiver_app(ft_status_type status)
{
	uint8_t ret;
	ft_notification_info sts;
	sts.app_id = ft_get_app_id_rx();
	sts.status = status;

	switch(status)
	{
		case transfer_download_success:
		{
			sts.dwld_info.tx_mode = dwnld_rqst.tx_mode;
			sts.dwld_info.size_file_or_data = dwnld_rqst.size;
			sts.dwld_info.checksum = dwnld_rqst.checksum;
			sts.dwld_info.tx_file_id = dwnld_rqst.file_id;

			if(dwnld_rqst.tx_mode == 0)
			{
				sts.dwld_info.storage_path_and_File_name = dwnld_rqst.file_name;
				sts.dwld_info.path_filename_buf_length = dwnld_rqst.file_name_buf_length;
#ifdef FT_OBC
				sts.dwld_info.bulkdata_ptr = dwnld_rqst.mptr;
#endif
			}
			else
			{
				sts.dwld_info.bulkdata_ptr = dwnld_rqst.mptr;
			}
			log_id(LOG_INFO_L1, LOG_FTM, APP_NOTIFY_DOWNLOAD_SUCCESS);

		}
		break;

		case crc_error:
		{
				/* do nothing */
			log_id(LOG_ERROR, LOG_FTM, APP_NOTIFY_CRC_ERROR);
		}
		break;

		case transfer_suspended:
		{
			log_id(LOG_INFO_L1, LOG_FTM, APP_NOTIFY_TRANSFER_SUSPENDED);
			/* do nothing */
		}
		break;

		case transfer_resumed:
		{
			log_id(LOG_INFO_L1, LOG_FTM, APP_NOTIFY_TRANSFER_RESUMED);
			/* do nothing */
		}
		break;

		case transfer_suspended_savecontext:
		case transfer_suspended_auto_savecontext:
		{
			DEBUG_CPRINT(("Close file %s\n",dwnld_rqst.file_name));
#ifndef FT_OBC
			ft_file_close(dwnld_rqst.fptr,&dwnld_rqst.file_opened, dwnld_rqst.tx_mode);
#endif
			save_context_info(&sts);
			if(sts.context_info.context_info_buf_ptr == NULL)
			{
				ft_transfer_request(Suspend_Savecontext_nack_rqst,0);
				return 0;
			}
		}
		break;

		case transfer_suspend_savecontext_accepeted:
			DEBUG_CPRINT(("Save context accepted by Sender !!! \n"));
#ifndef FT_OBC
			ft_file_close(dwnld_rqst.fptr,&dwnld_rqst.file_opened, dwnld_rqst.tx_mode);
#endif
			sts.context_info.session_id = 0;
			sts.context_info.node_operation = ft_download;
			save_context_info(&sts);
			ft_fsm_change_state(FT_Inactive);
			set_file_transfer_state(ft_process_na);
			break;

		case transfer_resumed_restorecontext:
		{
			/* do nothing */
		}
		break;

		case tx_terminated_suspend_timeout_expired:
		{
			/* do nothing */
		}
		break;

		case transfer_download_ready:
		{
			sts.dwld_info.tx_mode = dwnld_rqst.tx_mode;
			sts.dwld_info.size_file_or_data = dwnld_rqst.size;
			sts.dwld_info.tx_file_id = dwnld_rqst.file_id;
			log_id(LOG_INFO_L1, LOG_FTM, APP_NOTIFY_DOWNLOAD_READY);
		}
		break;

		default:
			break;


	}
	ret = ft_notify_receiver_app(&sts);

	if(status == transfer_download_success)
	{
		if(sts.dwld_info.tx_mode == 0)
		{
			os_free(sts.dwld_info.storage_path_and_File_name);
			DEBUG_CPRINT(("FTM file name pointer free\n"));
		}
	}


	return ret;
}
