/*
 * Copyright (c) 2017 FH Dortmund and others
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Description:
 *     Socket server for rover-web to rover-app communication
 *
 * Contributors:
 *    M.Ozcelikors <mozcelikors@gmail.com>, created 26.10.2017
 *
 */

#include <tasks/socket_server_task.h>

#include <string.h>
#include <ctime>
#include <unistd.h>
#include <libraries/timing/timing.h>
#include <interfaces.h>
#include <pthread.h>

#include <signal.h>

/* Socket defs header */
#include <socket_settings.h>

/* json-cpp library */
#include <json/json.h>

#include <roverapp.h>

/* Global definitions */
int roverapp_listen_sockfd;
int newroverapp_listen_sockfd;

/* If returns nonzero -> socket has a non zero error status */
int checkServerSocketStatus (int socket_fd)
{
	//TODO: Fix this function!
	int error = 0;
	socklen_t len = sizeof (error);
	int retval = getsockopt (socket_fd, SOL_SOCKET, SO_ERROR, &error, &len);
	return error;
}

void parseJSONData (char *server_buffer)
{
	Json::Value root;
	Json::Reader reader;
	bool parsingSuccessful = reader.parse( server_buffer, root );
	if ( !parsingSuccessful )
	{
		std::cout  << "Failed to parse" << reader.getFormattedErrorMessages();
	}

	if (root["rover_dtype"].asString() == "control")
	{
		// Update shared variable
		pthread_mutex_lock(&keycommand_lock);
			//Take only the first char - since interface uses 1 char only
			keycommand_shared = root["data"]["command"].asString()[0];
			//printf("RECV=%c\n",keycommand_shared);
		pthread_mutex_unlock(&keycommand_lock);
	}
	else if (root["rover_dtype"].asString() == "speed")
	{
		// Update shared variable
		pthread_mutex_lock(&speed_lock);
			speed_shared = root["data"]["speed"].asInt();
			//printf("RECV=%d\n",speed_shared);
		pthread_mutex_unlock(&speed_lock);
	}
	else
	{
		std::cout << "Unable to parse in socket_server_task.cpp" << std::endl;
	}

}

void Socket_Server_Task_Terminator (int dummy)
{
	close(roverapp_listen_sockfd);
	close(newroverapp_listen_sockfd);
	running_flag = 0;
}

void *Socket_Server_Task(void * arg)
{
	timing socket_server_task_tmr;

	socket_server_task_tmr.setTaskID("Socket_Server_Task");
	socket_server_task_tmr.setDeadline(0.05);
	socket_server_task_tmr.setPeriod(0.05);

	/* Add termination signal handler to properly close socket */
	signal(SIGINT, Socket_Server_Task_Terminator);
	signal(SIGTERM, Socket_Server_Task_Terminator);
	signal(SIGKILL, Socket_Server_Task_Terminator);

	socklen_t clilen;
	char server_buffer[JSON_DATA_BUFSIZE];
	struct sockaddr_in serv_addr, cli_addr;
	int  n;
	int true_ = 1;
	int client_connected_flag = 0;

	/* First call to socket() function */
	roverapp_listen_sockfd = socket(AF_INET, SOCK_STREAM, 0);

	if (roverapp_listen_sockfd < 0) {
		perror("ERROR opening socket");
		exit(1);
	}

	/* Handle re-binding problems */
	setsockopt(roverapp_listen_sockfd, SOL_SOCKET,SO_REUSEADDR,&true_,sizeof(int));

	/* Initialize socket structure */
	bzero((char *) &serv_addr, sizeof(serv_addr));

	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = inet_addr(BINDING_HOSTNAME);
	serv_addr.sin_port = htons(ROVERAPP_LISTEN_PORT);
	memset(serv_addr.sin_zero, '\0', sizeof serv_addr.sin_zero);

	/* Now bind the host address using bind() call.*/
	if (bind(roverapp_listen_sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
		perror("ERROR on binding");
		exit(1);
	}

	/* Now start listening for the clients, here process will
	  * go in sleep mode and will wait for the incoming connection
	*/
	listen(roverapp_listen_sockfd,5); // Max 5 connections queued
	clilen = sizeof(cli_addr);

	while(running_flag)
	{
		socket_server_task_tmr.recordStartTime();
		socket_server_task_tmr.calculatePreviousSlackTime();

		//Task content starts here -----------------------------------------------
		/* Handle client acception or re-acception */
		/* Checking if client socket is available */
		if (checkServerSocketStatus(newroverapp_listen_sockfd)!=0)
		{
			client_connected_flag = 0;
		}

		if (client_connected_flag == 0)
		{
			/* If no client is connected currently */
			/* Accept actual connection from the client */
			newroverapp_listen_sockfd = accept(roverapp_listen_sockfd, (struct sockaddr *)&cli_addr, &clilen);

			if (newroverapp_listen_sockfd < 0) {
				perror("ERROR on accept -> newroverapp_listen_sockfd");
				exit(1);
			}
			else
			{
				printf ("Client connected to newroverapp_listen_sockfd \n");
				client_connected_flag = 1;
			}
		}
		else
		{
			/* If a client is connected */
			/* If connection is established then start communicating */
			size_t buf_idx = 0;

			/* Read one char at a time until the EOF_STR "\r\n" is reached */
			while (buf_idx < JSON_DATA_BUFSIZE)
			{
				if ( 1 == read(newroverapp_listen_sockfd, &server_buffer[buf_idx], 1))
				{
					if (buf_idx > 0 &&  LINE_FEED == server_buffer[buf_idx] && CARRIAGE_RETURN == server_buffer[buf_idx - 1])
					{
						break;
					}
					buf_idx++;
				}
				else
				{
					/* Very important approach to have re-usable socket server */
					/* Client connection status is determined by exit status of read */
					printf ("Client disconnected!");
					client_connected_flag = 0;
					break;
				}

			}
			// Received buffer
			//printf ("buffer: %s\n",server_buffer);

			/* Remove \r\n from at the end of the string */
			server_buffer[buf_idx] = '\0';
			server_buffer[buf_idx-1] = '\0';

			/* Parse the JSON data, and update global variables */
			parseJSONData(server_buffer);
		}

		//Task content ends here -------------------------------------------------

		socket_server_task_tmr.recordEndTime();
		socket_server_task_tmr.calculateExecutionTime();
		socket_server_task_tmr.calculateDeadlineMissPercentage();
		socket_server_task_tmr.incrementTotalCycles();
		pthread_mutex_lock(&socket_server_task_ti_l);
			socket_server_task_ti.deadline = socket_server_task_tmr.getDeadline();
			socket_server_task_ti.deadline_miss_percentage = socket_server_task_tmr.getDeadlineMissPercentage();
			socket_server_task_ti.execution_time = socket_server_task_tmr.getExecutionTime();
			socket_server_task_ti.period = socket_server_task_tmr.getPeriod();
			socket_server_task_ti.prev_slack_time = socket_server_task_tmr.getPrevSlackTime();
			socket_server_task_ti.task_id = socket_server_task_tmr.getTaskID();
			socket_server_task_ti.start_time = socket_server_task_tmr.getStartTime();
			socket_server_task_ti.end_time = socket_server_task_tmr.getEndTime();
		pthread_mutex_unlock(&socket_server_task_ti_l);
		socket_server_task_tmr.sleepToMatchPeriod();

	}
}
