/**
 *@file ftsr_decode.c
 *
 *@brief This file contains functions that provides demonstration of
 *       usage of FTSR frame forming APIs
 *
 *The functions provided in the file provides demonstration on
 *usage of  FTSR frame forming APIs
 */
#include "ftsr.h"

#include "stdlib.h"

#include "common.h"
#include "file_transfer.h"
#include "ftci_decode.h"
#include "tc_tm_sample.h"
#include "ft_sender.h"
#include "ft_receiver.h"

extern uint8_t ftsr_res_frame[10];
s_string_info ftsr_data_loss;
tc_tm_id_e_ft tc_response;

#define FTSR_FRAME_CTRL_FIELD_LEN 1
#define WAIT_TIME_FIELD 2
#define SEQ_COUNT_FIELD 1

void send_ftsr(e_ftsr_response_code set,uint16_t timeout_time)
{
	s_file_tx_sts_resp ready_sts;
	memset(&ready_sts, 0, sizeof(s_file_tx_sts_resp));
	ready_sts.ctrl.bit.file_tx_session_id = ft_rx_session_id_read();
	ready_sts.ctrl.bit.response_code = set;
	ready_sts.suspend_wait_timeout = timeout_time;

	ftsr_data_loss.str_ptr = malloc(sizeof(s_file_tx_sts_resp));
	if(ftsr_data_loss.str_ptr != NULL)
	{
		memcpy(ftsr_data_loss.str_ptr, &ready_sts, sizeof(s_file_tx_sts_resp));
		ftsr_data_loss.size = sizeof(s_file_tx_sts_resp);


		if(dwnld_rqst.seq_loss_detect_enable != SEQ_LOSS_DETECTION_OFF)
		{
	#ifndef FT_SAT
			tc_response = FT_TC_FTSR;
			ft_save_tc_request(FT_TC_FTSR);
			ft_send_tctm(FT_TC_FTSR,ftsr_data_loss.str_ptr,ftsr_data_loss.size);
	#else
			tc_response = FT_TM_FTSR;
			ft_save_tm_request(FT_TM_FTSR);
			ft_send_tctm(FT_TM_FTSR,ftsr_data_loss.str_ptr,ftsr_data_loss.size);
	#endif
		}
		free(ftsr_data_loss.str_ptr);
	}
	else
	{
		printf("FTM malloc fail\n");
	}

}

void set_resend_flag(s_treceive_info *rx_info)
{
	uint16_t u16cntr=0;

	while(u16cntr < MAX_PCKT_LOSS_DETECTION_CNTR)
	{
		/* check sequence number is available in buffer */
		if(0 != rx_info->data_loss.lost_packet_list[u16cntr])
		{
			/* set resend flag */
			rx_info->data_loss.resend_rqst_flag = rx_info->data_loss.resend_rqst_flag | (1 << u16cntr);

		}
		u16cntr++;
	}
}


/* prepare FTSR frame with data loss information */

void prepare_packet_loss_notify_frame(s_treceive_info *rx_info, e_ftsr_response_code response)
{

	uint16_t u16cntr=0;
	uint16_t ftsr_frame_max_length;
	uint16_t ftsr_buffer_length;
	uint8_t resend_flag;
	uint32_t *loc_ptr;

    printf("Prepare FTSR - loss info %d\n",rx_info->data_loss.total_lost_segment_count);
	ft_fsm_change_state(FT_Idle_State);


	if(rx_info->data_loss.total_lost_segment_count != 0)
	{



	s_file_tx_sts_resp data_loss_sts;
	data_loss_sts.ctrl.bit.file_tx_session_id = ft_rx_session_id_read();
	data_loss_sts.ctrl.bit.response_code = response;
	/* set default value 0 */
	data_loss_sts.suspend_wait_timeout = 0;


	ft_fsm_change_state(FT_Idle_State);


	/* determine ftsr frame size */
	ftsr_frame_max_length = rx_info->mtu_size - (FTSR_FRAME_CTRL_FIELD_LEN + WAIT_TIME_FIELD + SEQ_COUNT_FIELD);

	ftsr_buffer_length = (rx_info->data_loss.total_lost_segment_count * 4);
	if(ftsr_buffer_length > ftsr_frame_max_length)
	{
		/* if sequence number total byte count is higher than mtu size, use mtu size as maximum FTSR fuffer length */
		ftsr_buffer_length = (FTSR_FRAME_CTRL_FIELD_LEN + WAIT_TIME_FIELD + SEQ_COUNT_FIELD) + ftsr_frame_max_length;
	}
	else
	{
		ftsr_buffer_length = ftsr_buffer_length + (FTSR_FRAME_CTRL_FIELD_LEN + WAIT_TIME_FIELD + SEQ_COUNT_FIELD);
	}

	ftsr_data_loss.str_ptr = malloc(ftsr_buffer_length);

	if(ftsr_data_loss.str_ptr != NULL)
	{
		printf("\nAllocated size %d : ",ftsr_buffer_length);

		ftsr_data_loss.size = (FTSR_FRAME_CTRL_FIELD_LEN + WAIT_TIME_FIELD + SEQ_COUNT_FIELD);

		data_loss_sts.segment_loss_count = 0;
		ftsr_buffer_length = ftsr_buffer_length /4;
		//ftsr_buffer_length++;
		rx_info->data_loss.ftsr_frame_full = 0;
		while(u16cntr < MAX_PCKT_LOSS_DETECTION_CNTR)
		{
			/* check sequence number is available in buffer */
			if(0 != rx_info->data_loss.lost_packet_list[u16cntr])
			{
				/* check seq number was npt shared to sender already */
				resend_flag = rx_info->data_loss.resend_rqst_flag & (1 << u16cntr);
				if(resend_flag != 0)
				{
					ftsr_buffer_length--;
					/* check seq id not fit in current frame length */
					if(ftsr_buffer_length != 0)
					{
						/* encode FTSR frame with sequence numbers */
						loc_ptr = (uint32_t*)&ftsr_data_loss.str_ptr[ftsr_data_loss.size];
						*loc_ptr = rx_info->data_loss.lost_packet_list[u16cntr];
						data_loss_sts.segment_loss_count++;
						ftsr_data_loss.size = ftsr_data_loss.size + 4;
						/* clear re send flag */
						rx_info->data_loss.resend_rqst_flag = rx_info->data_loss.resend_rqst_flag & (~(1 << u16cntr));
						printf(" %u-%u",u16cntr,*loc_ptr);
					}
					else if(ftsr_buffer_length == 0)
					{
						/* break if sequence id encoding on ftsr frame length reaches maximum mtu size it supports */
						/* set frame full flash to indicate remaining sequence ID has to be shared in another FTSR frame */
						rx_info->data_loss.ftsr_frame_full = 1;
						ft_fsm_change_state(FT_Report_Sequence_loss);
						break;
					}
				}


			}
			u16cntr++;

		}

		memcpy(ftsr_data_loss.str_ptr, &data_loss_sts, sizeof(s_file_tx_sts_resp));

//		printf("\nFTSR size: %d > ",ftsr_data_loss.size);
//
//		for(u16cntr=0;  u16cntr < ftsr_data_loss.size; u16cntr++)
//		{
//			printf("%x ",ftsr_data_loss.str_ptr[u16cntr]);
//		}


		if(ftsr_buffer_length != 0)
		{
			if(rx_info->data_loss.head_change_request ==1)
			{
				ft_fsm_change_state(FT_Report_Head_Change);
		        dwnld_rqst.data_loss.head_change_request = 0;
			}
		}


		if(rx_info->data_loss.total_lost_segment_count != 0)
		{

#ifndef FT_SAT
			ft_save_tc_request(FT_TC_FTSR);
			ft_send_tctm(FT_TC_FTSR,ftsr_data_loss.str_ptr, ftsr_data_loss.size);

#else
			ft_save_tm_request(FT_TM_FTSR);
			ft_send_tctm(FT_TM_FTSR,ftsr_data_loss.str_ptr, ftsr_data_loss.size);
#endif
                        free(ftsr_data_loss.str_ptr);
		}
		else
		{
			printf("\nFTSR skipped: > ");
		}

	}

	}
	else
	{
		if(rx_info->data_loss.head_change_request ==1)
		{
			ft_fsm_change_state(FT_Report_Head_Change);
	        dwnld_rqst.data_loss.head_change_request = 0;
		}
	}


}



/* prepare FTSR frame with data loss information */

tc_tm_id_e_ft prepare_head_change_request_frame(s_treceive_info *rx_info)
{

	tc_tm_id_e_ft tc_id;
	uint16_t ftsr_buffer_length;
	uint32_t *loc_ptr;

	s_file_tx_sts_resp data_loss_sts;
	data_loss_sts.ctrl.bit.file_tx_session_id = ft_rx_session_id_read();
	data_loss_sts.ctrl.bit.response_code = ftsr_head_change;
	/* set default value 0 */
	data_loss_sts.suspend_wait_timeout = 0;

	ft_fsm_change_state(FT_Idle_State);

	ftsr_buffer_length = (FTSR_FRAME_CTRL_FIELD_LEN + WAIT_TIME_FIELD + SEQ_COUNT_FIELD) + 4;
	ftsr_data_loss.str_ptr = malloc(ftsr_buffer_length);
	if(ftsr_data_loss.str_ptr != NULL)
	{
	ftsr_data_loss.size = (FTSR_FRAME_CTRL_FIELD_LEN + WAIT_TIME_FIELD + SEQ_COUNT_FIELD);

	/* encode FTSR frame */
	loc_ptr = (uint32_t*)(&ftsr_data_loss.str_ptr[ftsr_data_loss.size]);
	*loc_ptr = rx_info->pckt_seq_head+1;
    printf("Prepare head change %d info \n",*loc_ptr);
	ftsr_data_loss.size = ftsr_data_loss.size + 4;
	memcpy(ftsr_data_loss.str_ptr, &data_loss_sts, sizeof(s_file_tx_sts_resp));

//    printf("HEAD CHANGE frame ");
//
//	for(u16cntr=0; u16cntr< ftsr_data_loss.size; u16cntr++)
//	{
//	    printf("%x ",ftsr_data_loss.str_ptr[u16cntr]);
//	}
//    printf("\n");

#ifndef FT_SAT
	tc_id = FT_TC_FTSR;
	ft_save_tc_request(FT_TC_FTSR);
	ft_send_tctm(FT_TC_FTSR,ftsr_data_loss.str_ptr, ftsr_data_loss.size);
#else
	tc_id = FT_TM_FTSR;
	ft_save_tm_request(FT_TM_FTSR);
	ft_send_tctm(FT_TM_FTSR,ftsr_data_loss.str_ptr, ftsr_data_loss.size);
#endif
		free(ftsr_data_loss.str_ptr);
	}
	else
	{
		printf("FTM malloc error\n");
	}

	return tc_id;

}


void printf_ftsr_debug()
{
	uint16_t u16cntr;
	printf("\nFTSR size: %d > ",ftsr_data_loss.size);

	for(u16cntr=0;  u16cntr < ftsr_data_loss.size; u16cntr++)
	{
		printf("%x ",ftsr_data_loss.str_ptr[u16cntr]);
	}
}



