/**
 * @file get_input.c
 *
 * @brief This file contains functions that provides demonstration of
 *        usage of input collecting APIs
 *
 * The functions provided in the file provides demonstration on
 * usage of input collecting APIs
 */
#include "get_input.h"

#include "file_transfer.h"
#include "fsm.h"
#include "ftci.h"
#include "upload_def.h"
#include "suspend_resume.h"
#include "notify_apps.h"
#include "ftfci_decode.h"
#include "ftci_decode.h"
#include "segmentation.h"
#include "ft_timer.h"
#include "file_integrity_check.h"
#include "ft_sender.h"
#include "ft_receiver.h"

#define MODE_FT 0
#define MODE_DT 1
#define INPUT_ARRAY_SIZE 50

//char input_file_name[INPUT_ARRAY_SIZE];
char *input_file_name;

char output_file_path[INPUT_ARRAY_SIZE];
uint16_t get_mtu;

extern uint8_t bulk_data_buffer[200];





uint8_t ft_mode_select(uint8_t mode)
{
	uint8_t ret_sts = 1;
#ifndef FT_OBC
	if (mode < 2)
#else
	if (mode == 1)
#endif
	{
		tx_info.tx_mode = mode;
	}
	else
	{
		printf("Invalid mode, Enter again\r\n");
		ret_sts = 0;
	}
	return ret_sts;
}

uint8_t ft_get_sender_file_name_path(char name_and_path[])
{
	uint8_t ret_sts = 0;
	uint8_t len;

	FILE *fp = fopen(name_and_path, "r");

	// checking if the file exist or not
	if (fp == NULL)
	{
		printf("File %s Not Found! Enter again\n", name_and_path);
		ft_fsm_change_state(Input_State);
	}
	else
	{
		fclose(fp);
		len = strlen(name_and_path);
		input_file_name = malloc(len+1);
		//memset(input_file_name,'\0',INPUT_ARRAY_SIZE);
		memcpy(input_file_name, name_and_path, len);
		input_file_name[len] = '\0';
		ret_sts = 1;
	}

	return ret_sts;
}

uint8_t ft_get_receiver_node_storage_address(uint64_t mem_address)
{
	uint8_t ret_sts = 0;


	// checking if the file exist or not
	if (mem_address == 0)
	{
		printf("Bulk data buffer is Null \n");
		ft_fsm_change_state(Input_State);
	}
	else
	{
		printf("Bulk data buffer SIZE\n");
		dwnld_rqst.mptr = (uint8_t*)mem_address;
		dwnld_rqst.obc_mem_addr = mem_address;
		printf("Download Address %lux \n",(uint64_t)dwnld_rqst.mptr);
	}

	return ret_sts;
}

#ifndef FT_OBC
uint8_t ft_get_receiver_file_name_path(char name_and_path[])
{
	uint8_t ret_sts = 0;
	uint8_t len;

	FILE *fp = fopen(name_and_path, "r");

	// checking if the file exist or not
	if (fp == NULL)
	{
		printf("File %s Not Found! Enter again\n", name_and_path);
		ft_fsm_change_state(Input_State);
	}
	else
	{
		len = strlen(name_and_path);
		memcpy(output_file_path, name_and_path, len);
		ret_sts = 1;
		fclose(fp);
	}

	return ret_sts;
}
#endif

uint8_t ft_get_bulk_data_input_buffer(uint8_t *buffer, uint16_t buf_length)
{
	uint8_t ret_sts = 0;


	// checking if the file exist or not
	if (buffer == NULL)
	{
		printf("Bulk data buffer is Null \n");
		ft_fsm_change_state(Input_State);
	}
	else
	{
		printf("Bulk data buffer SIZE ; %d \n",buf_length);
		tx_info.mptr = buffer;
		tx_info.size = buf_length;
		printf("Buffer Address %lux \n",(uint64_t)tx_info.mptr);
	}

	return ret_sts;
}

uint8_t ft_get_bulk_data_rec_store_address(uint64_t mem_address)
{
	uint8_t ret_sts = 0;

	if (mem_address == 0)
	{
		printf("Bulk data buffer is Null \n");
		ft_fsm_change_state(Input_State);
	}
	else
	{
		tx_info.mem_address = (uint32_t)mem_address;
		printf("Buffer Address %ux \n",tx_info.mem_address);
	}

	return ret_sts;
}


/*
 *@brief API to get the MTU size
 *Function:  ft_get_mtu_size
 * --------------------
 *get the mtu size and check the range
 *
 *size: MTU size in bytes, Range 1 - 65535
 *
 *returns: returns zero on error
 */
uint8_t ft_get_mtu_size(uint16_t size)
{
	uint8_t u8ret_sts = 0;
	// checking if the size in range

	if (size < 16)
	{
		/*set default MTU size */
		printf("\r\nInvalid MTU, default value 16 Bytes assigned\r\n");
		get_mtu = 16;
	//	sleep(2);
	}
	else if (size > 0xFFF)
	{
		/*set default MTU size */
		printf("\r\nInvalid MTU, default value 254 Bytes assigned\r\n");
		get_mtu = 254;
	//	sleep(2);
	}
	else
	{
		get_mtu = size;
		u8ret_sts = 1;
	}

	return u8ret_sts;
}

/*
 *
 */
uint8_t ft_transfer_request(ft_request request, uint16 timeout)
{
	uint8_t ret_sts = 0;
	e_ft_current_process ft_state;
	switch(request)
	{
	case Start_Transmission_rqst:
		ft_state =  get_file_transfer_state();
		if(ft_state == ft_process_na)
		{
			ft_set_err_sts(ft_noerror);
			if(ft_payload_send != NULL)
			{
				ret_sts = is_sender_app_resgistered(tx_info.app_id);
				if(ret_sts != 0)
				{
					ft_tx_session_id_update(FT_SESSION_ID_INC);
					ft_fsm_change_state(FT_Send_Upload_Request);
					set_file_transfer_state(ft_upload);
					ret_sts = 1;
				}
				else
				{
					ft_set_err_sts(ft_sender_app_not_reg_error);
					printf("Requesting Sender App not registered\n");
				}
			}
			else
			{
				ft_set_err_sts(ft_icd_tctm_pld_callback_error);
				printf("FT ICD/TCTM tx callback not registered\n");
			}
		}
		else
		{
			ft_set_err_sts(ft_framework_busy_error);
			printf("Error !!! FT busy\n");
		}
		break;

	case Suspend_Timeout_Mode_rqst:
		ft_set_master_slave(sus_res_master);
		ft_suspend(Suspend_Timeout_Mode_rqst,timeout,0);
		ret_sts = 1;
		break;

	case Suspend_Savecontext_Mode_rqst:
		ft_state =  get_file_transfer_state();
		if(ft_state != ft_process_na)
		{
			ft_set_master_slave(sus_res_master);
			ft_suspend(Suspend_Savecontext_Mode_rqst,timeout,0);
			ret_sts = 1;
		}
		else
		{
			printf("Error, FTM service not available.");
		}
		break;

	case Resume_Timeout_Mode_rqst:
		ft_set_master_slave(sus_res_master);
		ft_resume(Resume_Timeout_Mode_rqst,0);
		ret_sts = 1;
		break;

	case Suspend_Savecontext_ack_rqst:
//		ft_stop_timer();
//		ft_savecontext_ack(1);
//		ft_fsm_change_state(FT_Inactive);
//		set_file_transfer_state(ft_process_na);

		ft_savecontext_ack(1);
		break;

	case Suspend_Savecontext_nack_rqst:
		//ft_set_master_slave(sus_res_master);
		ft_state =  get_file_transfer_state();
		if(ft_state == ft_upload)
		{
			ft_file_reopen_upload();
		}
		else if(ft_state == ft_download)
		{
			ft_file_reopen_download();
		}
		restart_transmission();
		ft_savecontext_ack(0);
		break;

	case Resume_Savecontext_nack_rqst:
		ft_savecontext_ack(0);
		break;

	case Terminate_Transmission_rqst:
	case T_Txnode:
	case T_Rxnode:
	case T_SuspendTimeout:
		ft_terminate(request,1);
		break;

	default:
		break;
	}
	return ret_sts;
}


uint8_t ft_get_app_id(uint16 app_id)
{
	uint8_t ret=0;
	if(app_id != 0)
		{
			tx_info.app_id = app_id;
			ret = 1;
		}
	return ret;
}


uint16_t ft_read_app_id_tx(void)
{
	return tx_info.app_id;
}


/*
 * error code
 * 0x00 - no error
 * 0x01 - context data corrupted
 * 0x02 - input bulk data buffer corrupted
 * 0x03 - input file not available
 * 0x04 - downloading buffer data corrupted
 * 0x05 - downloading file not available
 * 0x06 - input context buffer null
 */

uint8_t ft_resume_context(uint8_t *save_info, uint16_t size)
{
	ft_contextsave_info* c_info_ptr;
	uint16_t calc_buf_size;
	//uint16_t u16cnt;
	uint8_t ret_sts = 0;
	uint32_t checksum;
	uint32_t *rx_checksum;
	uint64_t mem_addrs_loc;
	uint8_t error_code = 0;

	static uint8_t test_var1 = 1;
	static uint8_t test_var2 = 1;
	
	if(size < 4 || size > 1024)
	{
		ft_savecontext_ack(0);
		return 0x01;
	}

	if(save_info != NULL)
	{

		checksum = calc_checksum_bulkdata(save_info, size-4);
		rx_checksum = (uint32_t*)&save_info[size-4];

		if(checksum != *rx_checksum)
		{
			printf("Error !!! Context data Checksum fail\n");
			printf("Calculated context checksum %X failed against %X\n",checksum,*rx_checksum);
			error_code = 0x01;
			ft_set_err_sts(ft_rc_context_input_error);
		}
		else
		{
			/* Context info integrity pass */

			c_info_ptr = (ft_contextsave_info*)save_info;

			printf("Read context info: ");
	//		for (u16cnt = 0; u16cnt < c_info_ptr->context_info_size; u16cnt++)
	//		{
	//			printf("%x ",save_info[u16cnt]);
	//		}
			printf("\n");

			if(c_info_ptr->node_operation == ft_upload)
			{

				if(c_info_ptr->tx_mode == 1)
				{
					/* perform input data buffer integrity before restoring upload process
					 *
					 */
					printf("DATA mode \n");
					checksum = calc_checksum_bulkdata(tx_info.mptr, c_info_ptr->bulkdata_len);
					if(checksum != c_info_ptr->bulkdata_checksum)
					{
						printf("Error !!! Input buffer data Checksum fail\n");
						printf("Calculated checksum %X failed against %X\n",checksum,c_info_ptr->bulkdata_checksum);
						printf("Uploading buffer corrupted\n");
						error_code = 0x02;
					}
					else
					{
						ret_sts = 1;
						mem_addrs_loc = (uint64_t)tx_info.mptr;
						printf("Success Calculated Upload buffer checksum %X against %X\n",checksum,c_info_ptr->bulkdata_checksum);
					}
				}
				else
				{
					ret_sts = 1;
				}


				if(	test_var1 == 0)
				{
					error_code = 0xff;
					test_var1 = 1;
					ret_sts = 0;
				}


				if(ret_sts != 0)
				{

					/* read tx info */
					calc_buf_size = sizeof(ft_contextsave_info);
					memcpy(&tx_info,&save_info[calc_buf_size],sizeof(s_transfer_info));

					/* read sequence loss info */
					calc_buf_size = sizeof(ft_contextsave_info) + sizeof(s_transfer_info);
					memcpy(&seg_info,&save_info[calc_buf_size],sizeof(s_segment_info));
					input_file_name = NULL;
					if(c_info_ptr->tx_mode == 0)
					{
						/* read file name */
						input_file_name = malloc(c_info_ptr->file_name_size);
						calc_buf_size = sizeof(ft_contextsave_info) + sizeof(s_transfer_info) + sizeof(s_segment_info);
						memcpy(input_file_name,&save_info[calc_buf_size],c_info_ptr->file_name_size);
					}

					if(tx_info.tx_mode == 0)
					{
						ret_sts = ft_file_reopen_upload();
					}
					else
					{
						ret_sts = 1;
						tx_info.mptr = (uint8_t*)mem_addrs_loc;
					}

					if(ret_sts != 0)
					{
						ft_set_suspend_resume_sts(state_suspend);
						s_sus_res_info.fsm_state_save = c_info_ptr->fsm_state_save;
						set_file_transfer_state(ft_upload);
						ft_set_master_slave(c_info_ptr->mast_slave_sel);
						if(c_info_ptr->mast_slave_sel == sus_res_master)
						{
							printf("[Upload] Send Resume frame \n");
							ft_resume(0xff,0);
							/* send FTCI frame again with flash resume context mode enabled */
							tx_info.resume_ctxt_mode =1;
							dest_path_name_info.str_ptr = (uint8_t *)input_file_name;
							dest_path_name_info.size = c_info_ptr->file_name_size;
							ft_sequenceLoss_mode_select(1);
							prepare_ftci_frame();
					#ifndef FT_SAT
							ft_save_tc_request(FT_TC_FTCI);
							ft_send_tctm(FT_TC_FTCI,ftci_frame_info.str_ptr,ftci_frame_info.size);
					#else
							ft_save_tm_request(FT_TM_FTCI);
							ft_send_tctm(FT_TM_FTCI,ftci_frame_info.str_ptr,ftci_frame_info.size);
					#endif
						}
						else if(c_info_ptr->mast_slave_sel == sus_res_slave)
						{
							printf("[Upload] Send Resume ACK \n");
							s_sus_res_info.type = suspend_by_savecontext;
							ft_resume(0xff,1);
						}
						printf("[Upload] Resume-Store Context Success !!! \n");
					}
					else
					{
						printf("[Upload] Resume-Store Context Fail !!! \n");
						error_code = 0x03;
					}

				}
				else
				{
					printf("[Upload] Resume-Store Context Fail - Input buffer corrupted !!! \n");
				}



			}
			else if(c_info_ptr->node_operation == ft_download)
			{


				if(c_info_ptr->tx_mode == 1)
				{
					printf("DATA mode \n");
					checksum = calc_checksum_bulkdata(dwnld_rqst.mptr, c_info_ptr->bulkdata_len);
					if(checksum != c_info_ptr->bulkdata_checksum)
					{
						printf("Error !!! Input buffer data Checksum fail\n");
						printf("Calculated checksum %X failed against %X\n",checksum,c_info_ptr->bulkdata_checksum);
						printf("Downloading buffer corrupted\n");
						error_code = 0x04;
					}
					else
					{
						ret_sts = 1;
						mem_addrs_loc = (uint64_t)dwnld_rqst.mptr;
						printf("Success Calculated download buffer checksum %X against %X\n",checksum,c_info_ptr->bulkdata_checksum);
					}
				}
				else
				{
					ret_sts = 1;
				}


				if(	test_var2 == 0)
				{
					error_code = 0xff;
					test_var2 = 1;
					ret_sts = 0;
				}


				if(ret_sts != 0)
				{

					/* read tx info */
					calc_buf_size = sizeof(ft_contextsave_info);
					memcpy(&dwnld_rqst,&save_info[calc_buf_size],sizeof(s_treceive_info));
					dwnld_rqst.file_name = NULL;
					if(c_info_ptr->tx_mode == 0)
					{
						/* read file name */
						dwnld_rqst.file_name = malloc(c_info_ptr->file_name_size+1);
						calc_buf_size = sizeof(ft_contextsave_info) + sizeof(s_treceive_info);
						memcpy(dwnld_rqst.file_name,&save_info[calc_buf_size],c_info_ptr->file_name_size);
						dwnld_rqst.file_name[c_info_ptr->file_name_size] = '\0';
					}

					if(dwnld_rqst.tx_mode == 0)
					{
#ifndef FT_OBC
						ret_sts = ft_file_reopen_download();
#else
						ret_sts = 1;
#endif
					}
					else
					{
						ret_sts = 1;
						dwnld_rqst.mptr = (uint8_t*)mem_addrs_loc;
					}

					if(ret_sts != 0)
					{
						if(c_info_ptr->mast_slave_sel == sus_res_master)
						{
							printf("[Download] Send Resume frame \n");
							s_sus_res_info.state = state_suspend;
							s_sus_res_info.fsm_state_save = c_info_ptr->fsm_state_save;
							set_file_transfer_state(ft_download);
							ft_set_master_slave(c_info_ptr->mast_slave_sel);
							ft_resume(0xff,0);
							printf("[Download] Resume-Store Context Success !!! \n");
						}
						else if(c_info_ptr->mast_slave_sel == sus_res_slave)
						{

							if(resume_ctxt_rqst.size != 0)
							{
								/* check resume context info is available*
								 *
								 */
								if(resume_ctxt_rqst.size == dwnld_rqst.size)
								{
									if(resume_ctxt_rqst.checksum == dwnld_rqst.checksum)
									{
										/* Resume context info matched with FTCI request */
										printf("[Download] Send Resume frame \n");
										s_sus_res_info.state = state_suspend;
										s_sus_res_info.fsm_state_save = c_info_ptr->fsm_state_save;
										set_file_transfer_state(ft_download);
										ft_set_master_slave(c_info_ptr->mast_slave_sel);
										ft_resume(0xff,1);
										printf("[Download] Resume-Store Context Success !!! \n");
									}
									else
									{
										/* no restore context available as requested from FTCI*/
										error_code = 0x0A;
										printf("[Download] Resume-Store Context Fail - No context Avail!!! \n");
									}
								}
								else
								{
									/* no restore context available */
									error_code = 0x0A;
									printf("[Download] Resume-Store Context Fail - No context Avail!!! \n");
								}
							}
							else
							{
								/* resume context enabled manually */
								printf("[Download] Send Resume frame \n");
								s_sus_res_info.state = state_suspend;
								s_sus_res_info.fsm_state_save = c_info_ptr->fsm_state_save;
								set_file_transfer_state(ft_download);
								ft_set_master_slave(c_info_ptr->mast_slave_sel);
								ft_resume(0xff,1);
								printf("[Download] Resume-Store Context Success !!! \n");
							}
						}
					}
					else
					{
						printf("[Download] Resume-Store Context Fail !!! \n");
						error_code = 0x05;
					}

				}
				else
				{
					printf("[Download] Resume-Store Context Fail - Buffer corrupted !!! \n");
				}



			}

		}


		if(c_info_ptr->mast_slave_sel == sus_res_slave)
		{
			if(error_code != 0)
			{
				/* abort resume context */
				printf("Restore failed at Slave side ! NACK sent\n");
				ft_savecontext_ack(0);
			}
		}


	}
	else
	{
		printf("Restored failed - Null error\n");
		error_code = 0x06;
		ft_set_err_sts(ft_rc_null_error);
	}

	return error_code;
}


/*
 * Sequence loss detection mode select
 * 1 >> sequence loss detection is enabled : it will word only on sband communication
 * 0 >> sequence loss detection is disabled : it can be enabled only for xband communication
 */
uint8_t ft_sequenceLoss_mode_select(uint8_t mode)
{
	uint8_t ret_sts = 1;
	if (mode < 2)
	{
		tx_info.seq_loss_detect_enable = mode;
	}
	else
	{
		printf("Invalid mode, Enter again\r\n");
		ret_sts = 0;
	}
	return ret_sts;
}


/*
 * This API is used to assign ID for each file transfered
 * this is useful to identify the multiple file sent to same app
 */
void ft_config_file_id(uint8_t f_id)
{
	if (f_id < 0x8)
	{
		tx_info.file_id = f_id;
	}
	else
	{
		tx_info.file_id = 0;
		printf("Invalid input file ID, Assigning default value 0\r\n");
	}
}


/*
*   This API is used to configure timeout value for connection failure for receiver side.
*   Receiver node will terminate the transmission if communication with sender is not restored in timeout value
*   This timeout value should be greater than 44 seconds and multiples of 15 such as 45, 60, 75, 300 are some valid timeout value can be used.
*/

void ft_config_rx_node_conn_failure_time(uint16_t conn_fail_time)

{

        if (conn_fail_time >= 45 || conn_fail_time <= 1800)

        {

                tx_info.rx_node_conn_fail_timeout = conn_fail_time;

        }

        else

        {

                tx_info.rx_node_conn_fail_timeout = 45;

                printf("Invalid connection failuer time, Assigning default value 45\r\n");

        }

}

