/**
 * @file ftci.c
 *
 * @brief This file contains functions that provides demonstration of
 *        usage of FTCI frame related APIs
 *
 * The functions provided in the file provides demonstration on
 * usage of FTCI frame related APIs
 */
#include "ftci.h"
#include "file_integrity_check.h"
#include "file_transfer.h"
#include "fsm.h"
#include "get_input.h"
#include "segmentation.h"
#include "tc_tm_sample.h"
#include "suspend_resume.h"
#include "ft_sender.h"

/*
 *total = control field 1 + control field 2 + checksum + mtu size + connection failure timer + Reserved *total = 1+1+4+2+2+2 >> 12 bytes
 */
#define FTCI_FIXED_FRAME_FIELD_SIZE 12

/*
 *total = memory address + size + file name length + file name/path *total = 4+4+1+50(assumption) >> 59 bytes
 */
#define FTCI_VARAIABLE_FRAME_FIELD_SIZE 59

/*
 *FTCI frame max length in bytes
 */
#define FTCI_FRAME_MAX_LENGTH     (FTCI_FIXED_FRAME_FIELD_SIZE + FTCI_VARAIABLE_FRAME_FIELD_SIZE)

s_file_tx_ctrl_info ftci_frame;
s_file_tx_ctrl_info ftci_frame_decode;
s_transfer_info tx_info;
uint8_t session_id;
uint8_t ftci_buffer[FTCI_FRAME_MAX_LENGTH];
extern uint16_t get_mtu;
s_string_info dest_path_name_info;

s_string_info ftci_frame_info = { ftci_buffer,
	0
};

/*
 *to covert bytes into user defined unit such as KB, MB, GB
 */
static uint32_t size_into_userdefined_format(uint8_t unit, uint32_t size)
{
	uint32_t ret_size;
	if (unit == 0)
	{
		/*size in bytes */
		ret_size = size;
	}
	else if (unit == 1)
	{
		/*size in KB */
		ret_size = size / 1024;
	}
	else if (unit == 2)
	{
		/*size in MB */
		ret_size = size / (1024 *1024);
	}
	else if (unit == 3)
	{
		/*size in GB */
		ret_size = size / (1024 * 1024 *1024);
	}
	else
	{
		ret_size = 0;
	}

	return ret_size;
}

uint8_t determine_size_field_holding_len(uint32_t size)
{
	uint8_t field_length;
	if (size < 0x100)
	{
		field_length = 0;
	}
	else if (size < 0x10000)
	{
		field_length = 1;
	}
	else if (size < 0x1000000)
	{
		field_length = 2;
	}
	else
	{
		field_length = 3;
	}

	return field_length;
}

void prepare_ftci_frame()
{
	int16_t i16cnt;
	uint8_t * loc_ptr;
	uint8_t * size_ptr;

	s_string_info file_details;
//	uint8_t * file_name;

	ftci_frame.ctrl_1.file_tx_session_id = ft_tx_session_id_read();
	ftci_frame.ctrl_1.resume_context_mode = tx_info.resume_ctxt_mode;
	ftci_frame.ctrl_2.transfer_mode_sel = tx_info.tx_mode;
	ftci_frame.ctrl_2.file_format = 3;
	ftci_frame.ctrl_2.unit = tx_info.unit;
	ftci_frame.ctrl_2.size_field_length = determine_size_field_holding_len(tx_info.size);
	ftci_frame.checksum = tx_info.checksum;
	ftci_frame.mtu_size = tx_info.mtu_size;
	ftci_frame.ctrl_1.seq_loss_detection_mode = tx_info.seq_loss_detect_enable;
	ftci_frame.ctrl_1.file_identification_number = tx_info.file_id;
        ftci_frame.rx_con_fail_timeout = tx_info.rx_node_conn_fail_timeout;
	/*start framing frame */
	ftci_frame_info.size = 0;

	/*copy fixed filed */
	memcpy(ftci_buffer, &ftci_frame, sizeof(s_file_tx_ctrl_info));
	ftci_frame_info.size += FTCI_FIXED_FRAME_FIELD_SIZE;

	/*copy file/data size */
	loc_ptr = &ftci_buffer[sizeof(s_file_tx_ctrl_info)];

	size_ptr = (uint8_t*) &tx_info.size;
	for (i16cnt = 0; i16cnt <= ftci_frame.ctrl_2.size_field_length; i16cnt++)
	{
		*loc_ptr++ = *size_ptr++;
		ftci_frame_info.size++;
	}

	if (ftci_frame.ctrl_2.transfer_mode_sel == 0)
	{
		/*file transfer */
		printf("\r\nFile TX mode FTCI preparing");

		/*update file path length */
		printf("\r\nPath:");



		/*
		 * 		../file_folder/Readme.md
		 * 		the below statement only extract file name from full path metioned above
		 * 		output : Readme.md
		 *
		 *
		 */
		i16cnt = dest_path_name_info.size -1;

                printf("path size =%d",i16cnt);

		while((i16cnt > (-1)) && (dest_path_name_info.str_ptr[i16cnt] != '/'))
		{
			i16cnt--;
		}

		if(i16cnt != 0)
		{
			i16cnt++;
		}


		file_details.size = dest_path_name_info.size - i16cnt;
		printf("\nFile length extract:%d :%d ",i16cnt, file_details.size);
		file_details.str_ptr = malloc(file_details.size+1);
		memcpy(file_details.str_ptr, &dest_path_name_info.str_ptr[i16cnt], file_details.size);
		file_details.str_ptr[file_details.size] = '\0';
		printf("\nFilename extract: %s ",file_details.str_ptr);

		*loc_ptr = file_details.size;
		ftci_frame_info.size++;
		loc_ptr++;

		/*update destination path */
		for (i16cnt = 0; i16cnt < file_details.size; i16cnt++)
		{
			*loc_ptr = file_details.str_ptr[i16cnt];
			printf("%c", *loc_ptr);
			loc_ptr++;
			//dest_path_name_info.str_ptr++;
			ftci_frame_info.size++;
		}

    free(file_details.str_ptr);

	}
	else
	{
		printf("\r\n Bulkdata TX mode ");
		/*bulk data transfer */
		*((uint32_t*) loc_ptr) = tx_info.mem_address;
		ftci_frame_info.size = ftci_frame_info.size + 4;
	}

	printf("\r\n");

	ft_save_session_start_time();

}

void print_frame(uint8_t *buf, uint8_t len)
{
	int inc;
	printf("\r\n print frame length %d : ", len);

	for (inc = 0; inc < len; inc++)
	{
		printf("%02X ", *buf);
		buf++;
	}
}

void print_string(uint8_t *buf, uint8_t len)
{
	int inc;
	printf("\r\n string length %d : ", len);

	for (inc = 0; inc < len; inc++)
	{
		printf("%c ", *buf);
		buf++;
	}
}


//void ftci_file_tx_ctrl_info(char file_name[],uint16_t mtu_size, uint8_t unit_of_size, char receiver_file_path[])
tc_tm_id_e_ft ftci_bulkdata(void)
{
	long int file_size;
	tc_tm_id_e_ft ret_sts = FT_TC_TM_MAX_ID;

	file_size = tx_info.size;
//	tx_info.mem_address = 0x0;
	tx_info.mtu_size = get_mtu;
	tx_info.unit = 0;
	tx_info.size = size_into_userdefined_format(tx_info.unit, file_size);

	/*calculate file checksum */
	tx_info.checksum = calc_checksum_bulkdata(tx_info.mptr, tx_info.size);
	tx_info.unit = 0;

	printf("\nSize of the file is %u bytes\n", tx_info.size);
	printf("Size of the MTU is %d bytes \n", tx_info.mtu_size);
	printf("Size in user unit is %u\n", tx_info.unit);
	printf("Checksum is 0x%X\n", tx_info.checksum);

	/*Prepare FTCI frame */
	tx_info.resume_ctxt_mode =0;
	prepare_ftci_frame();

  	if(tx_info.seq_loss_detect_enable != SEQ_LOSS_DETECTION_OFF)
	{
		ft_fsm_change_state(FT_Waitfor_FTSR);
		ft_set_timer(SENDER_RESPONSE_WAIT_TIME);
	}
	else
	{
		ft_fsm_change_state(FT_Wait_for_2sec);
	}
  	tx_info.receiver_is_ready = FT_FTSR_RECEIVER_READY_NOT_RECEIVED;


#ifndef FT_SAT
	ret_sts = FT_TC_FTCI;
	ft_save_tc_request(FT_TC_FTCI);
	ft_send_tctm(FT_TC_FTCI,ftci_frame_info.str_ptr,ftci_frame_info.size);

#else
	ret_sts = FT_TM_FTCI;
	ft_save_tm_request(FT_TM_FTCI);
	ft_send_tctm(FT_TM_FTCI,ftci_frame_info.str_ptr,ftci_frame_info.size);

#endif
        free(ftci_frame_info.str_ptr);
	return ret_sts;
}



#ifndef FT_OBC
tc_tm_id_e_ft ftci_file(void)
{
	long int file_size;
	uint8_t len_loc;
	tc_tm_id_e_ft ret_sts = FT_TC_TM_MAX_ID;

	len_loc = strlen(input_file_name) + 1;
	dest_path_name_info.str_ptr = malloc(len_loc);
	if(dest_path_name_info.str_ptr != NULL)
	{
	memcpy(dest_path_name_info.str_ptr, input_file_name, len_loc);
	dest_path_name_info.size = len_loc;
	tx_info.file_name_size = len_loc;

	file_size = findSize(input_file_name);
	if ((file_size != -1) && (file_size != 0))
	{
		//printf("Size of the file is %ld bytes \n", file_size);
		tx_info.mtu_size = get_mtu;
		tx_info.unit = 0;
		tx_info.size = size_into_userdefined_format(tx_info.unit, file_size);

		/*calculate file checksum */
		tx_info.checksum = calc_checksum(input_file_name, file_size);
		tx_info.unit = 0;
 	    printf("\nSession id is %d\n", ft_tx_session_id_read());
		printf("\nSize of the file is %u bytes\n", tx_info.size);
		printf("Size of the MTU is %d bytes \n", tx_info.mtu_size);
		printf("Size in user unit is %u  \n", tx_info.unit);
		printf("Checksum is 0x%X  \n", tx_info.checksum);

		/*Prepare FTCI frame */
		tx_info.resume_ctxt_mode =0;
		prepare_ftci_frame();

	  	if(tx_info.seq_loss_detect_enable != SEQ_LOSS_DETECTION_OFF)
		{
			ft_fsm_change_state(FT_Waitfor_FTSR);
			ft_set_timer(SENDER_RESPONSE_WAIT_TIME);
		}
		else
		{
			ft_fsm_change_state(FT_Wait_for_2sec);
		}
	  	tx_info.receiver_is_ready = FT_FTSR_RECEIVER_READY_NOT_RECEIVED;


		
#ifndef FT_SAT
		ret_sts = FT_TC_FTCI;
		ft_save_tc_request(FT_TC_FTCI);
		ft_send_tctm(FT_TC_FTCI,ftci_frame_info.str_ptr,ftci_frame_info.size);
#else
		ret_sts = FT_TM_FTCI;
		ft_save_tm_request(FT_TM_FTCI);
		ft_send_tctm(FT_TM_FTCI,ftci_frame_info.str_ptr,ftci_frame_info.size);
#endif
                free(dest_path_name_info.str_ptr);
	}
	else
	{
		printf("\nFile opening error or File size is equal to 0\n");
		ft_cancel_ftp();
		ft_set_err_sts(ft_input_file_open_error);
	}
	}
	else
	{
		printf("FTM Malloc fail\n");
	}
	return ret_sts;
}
#endif

tc_tm_id_e_ft ftci(void)
{
	tc_tm_id_e_ft ret_sts = FT_TC_TM_MAX_ID;

	if(tx_info.tx_mode == 0)
	{
#ifndef FT_OBC
		ret_sts = ftci_file();
#endif
	}
	else if(tx_info.tx_mode == 1)
	{
		ret_sts = ftci_bulkdata();
	}
	else
	{
		// do nothing
	}
	return ret_sts;

}


void init_ftci(void)
{
	memset(&tx_info,0,sizeof(s_transfer_info));
	tx_info.app_id = 0xFFFF;
	tx_info.rx_node_conn_fail_timeout = 45;
}
