#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <time.h>
#include "base.h"
#include "factor.h"

extern float offload_to_cloud(const char *, struct FactorSet *);

/*
 * Offload file to be scanned to cloud
 * */
float offload_to_cloud(const char *scanned_file, struct FactorSet *fs)
{
	int sockfd, num_r, num_w;
	int errcode;
	char buff[50];
	struct sockaddr_in serv_addr;
	struct timespec start, stop;
	float total_time;
	int size;
	int result;
	struct stat scanned_file_st;
	FILE *scan_fptr;

	clock_gettime(CLOCK_MONOTONIC, &start);		/* time start */

	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (sockfd == -1) {
		system_error();
	}
	FILE *stream = fdopen(sockfd, "r+");

	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_addr.s_addr = inet_addr(fs->server_addr);
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(fs->server_port);

	errcode = connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
	if (errcode == -1) {
		system_error();
	}

	/* Read the greeting message. */
	num_r = fread(buff, sizeof(char), 14, stream);
	printf("[SERVER]: %s\n", buff);

	/* Tell server the size of file */
	stat(scanned_file, &scanned_file_st);
	size = scanned_file_st.st_size;
	num_w = fwrite(&size, sizeof(int), 1, stream);
	/* Transmit file to be scanned */
	char temp[10001];
	int num;
	scan_fptr = fopen(scanned_file, "r");
	while (size != 0) {
		if (size > 10000)
			num = 10000;
		else
			num = size;

		num_r = fread(temp, sizeof(char), num, scan_fptr);
		num_w = fwrite(temp, sizeof(char), num, stream);
		size -= num;
	}
	fclose(scan_fptr);

	float cld_exec_time;
	fread(&cld_exec_time, sizeof(float), 1, stream);
	printf("exec time: %f\n", cld_exec_time);

	/* Receive calculated result from cloud. */
	num_r = fread(&result, sizeof(int), 1, stream);
	printf("result: %d infected\n", result);
	fclose(stream);
	close(sockfd);

	clock_gettime(CLOCK_MONOTONIC, &stop);		/* time stop */

	total_time = calc_diff_time(&start, &stop)/1000; /* us */
	printf("cloud total time: %f us, cloud exec time: %f us\n", total_time, cld_exec_time);

	/* get the cloud capability */
	float alpha = 0.3f;
	fs->U_cld = fs->U_cld * (1-alpha) + ((fs->t_comp * fs->U_cpu)/cld_exec_time) * alpha;
	FILE *fptr = fopen("Docs/exec-log", "a");
	fprintf(fptr, "%f\t", cld_exec_time);
	fclose(fptr);

	return total_time; /* us */
}
