/* 
 * BS Logic Layer
 * 
 * bs.c
 *
 * Implementation of the BS server logic and service handlers. 
 * The handlers also have to format data from and to the standard
 * message formats associated with requests and responses.
 * 
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <config.h>
#include "bs.h"
#include "system.h"


void bs_init(int argc, char **argv) {
	int res = -1;
	
	if (argc == 1) {
		res = system_init(DEFAULT_USERS, DEFAULT_TITLES);
	} else if (argc == 2) {
		res = system_init(argv[1], DEFAULT_TITLES);
	} else if (argc == 3) {
		res = system_init(argv[1], argv[2]);
	}
	
	if (res != 0) {
		printf("\33[1m[bs_init]\33[0m erro: ficheiro invalido.\n");
		exit(-1);
	}
}


void bs_free_response(response_t* response) {
	free(response->res);
	free(response);
}


void bs_give(bs_pdu_req_t *req, int reqsz, res_list_t **res_lst) {
	printf("\33[1m[bs_give]\33[0m handling a 'Give' request.\n");
	
	// get input arguments
	char* titles = req->body.give.titles;
	
	printf("\33[1m[bs_give]\33[0m received Give message of '%s'.\n", titles);
	
	// handle request
	system_give(titles);
	
	// prepare response
	*res_lst = NULL;
}


void bs_search(bs_pdu_req_t *req, int reqsz, res_list_t **res_lst) {
	printf("\33[1m[bs_search]\33[0m handling a 'Search' request.\n");
	
	// get input arguments
  	char* username = req->body.search.username;
	char* password = req->body.search.password;
	char* titles = req->body.search.titles;
	int weight = req->body.search.weight;
	
	printf("\33[1m[bs_search]\33[0m received Search message of '%s' from '%s' with password '%s' weight:[%d]\n",
		titles, username, password, weight);

	// handle request
	sys_list_t* results;
	sys_lst_iitem_t* item;
	system_search(username, password, titles, weight, &results);
	
	*res_lst = res_lst_new();

	// prepare response
	while ((item = sys_lst_pop(results)) != NULL) {
		response_t response;
		response.res = (bs_pdu_res_t*) malloc(sizeof(bs_pdu_res_t));
		response.ressz = sizeof(*(response.res)) - sizeof(response.res->body) +
			sizeof(response.res->body.search);
		response.res->type = REQ_SEARCH;
		response.res->status = RES_ERROR;
		
		bs_pdu_res_search_t* res = &(response.res->body.search);
		system_res_search_t* sys_res = &(item->system_response.search);
		
		strncpy(res->title, sys_res->title, MAX_BOOKNAME_SIZE);
		strncpy(res->counter, sys_res->counter, MAX_COUNTER_SIZE);
		res->weight = sys_res->weight;
		strncpy(res->neighbours, sys_res->neighbours, MAX_NEIGHBOURS_SIZE);
		strncpy(res->reason, sys_res->reason, MAX_REASON_SIZE);
				
		if (item->status != ERROR) {
			response.res->status = RES_OK;
		}
		
		res_lst_insert(*res_lst, &response);
		free(item);
	}
	
	sys_lst_destroy(results);
}


void bs_cancel(bs_pdu_req_t *req, int reqsz, res_list_t **res_lst) {
  	printf("\33[1m[bs_cancel]\33[0m handling a 'Cancel' request.\n");
	
	// get input arguments
  	char* username = req->body.cancel.username;
  	char* titles = req->body.cancel.titles;

	printf("\33[1m[bs_cancel]\33[0m received Cancel message of '%s' from '%s'\n", titles, username);
	  	
 	// handle request
	system_cancel(username, titles);
	
	// prepare response
	*res_lst = NULL;
}


void bs_take(bs_pdu_req_t *req, int reqsz, res_list_t **res_lst) {
  	printf("\33[1m[bs_take]\33[0m handling a 'Take' request.\n");
  
	// get input arguments
  	char* username = req->body.take.username;
  	char* titlecs = req->body.take.titlecs;

	printf("\33[1m[bs_take]\33[0m received Take message of '%s' from '%s'\n", titlecs, username);
	
	// handle request
	sys_list_t* results;
	sys_lst_iitem_t* item;
	system_take(username, titlecs, &results);
	
	*res_lst = res_lst_new();

	// prepare response
	while ((item = sys_lst_pop(results)) != NULL) {
		response_t response;
		response.res = (bs_pdu_res_t*) malloc(sizeof(bs_pdu_res_t));
		response.ressz = sizeof(*(response.res)) - sizeof(response.res->body) +
			sizeof(response.res->body.take);
		response.res->type = REQ_TAKE;
		response.res->status = RES_ERROR;
		
		bs_pdu_res_take_t* res = &(response.res->body.take);
		system_res_take_t* sys_res = &(item->system_response.take);
		
		strncpy(res->title, sys_res->title, MAX_BOOKNAME_SIZE);
		strncpy(res->counter, sys_res->counter, MAX_COUNTER_SIZE);
		strncpy(res->reason, item->system_response.take.reason, MAX_REASON_SIZE);
		res->size = sys_res->size;
		res->cover = sys_res->cover;
				
		if (res->size != 0) {
			int size = res->size;
			
			response.ressz += sizeof(char) * size;
			response.res = (bs_pdu_res_t*) realloc(response.res, sizeof(bs_pdu_res_t) +
				(sizeof(char) * size));
			
			memcpy(&(response.res->body.take.cover), sys_res->cover, (sizeof(char) * size));
			free(sys_res->cover);
		}
		
		if (item->status != ERROR) {
			response.res->status = RES_OK;
		}
		
		res_lst_insert(*res_lst, &response);
		free(item);
	}
	
	sys_lst_destroy(results);
}


void bs_release(bs_pdu_req_t *req, int reqsz, res_list_t **res_lst) {
	printf("\33[1m[bs_release]\33[0m handling a 'Release' request.\n");
	
	// get input arguments
  	char* username = req->body.release.username;
	char* titles = req->body.release.titles;
	int makeavailable = req->body.release.makeavailable;
	
	printf("\33[1m[bs_release]\33[0m received Release message of '%s' from '%s'%s",
		   titles, username, makeavailable ? " to return.\n" : ".\n");

	// handle request
	sys_list_t* results;
	sys_lst_iitem_t* item;
	system_release(username, titles, makeavailable, &results);
	
	*res_lst = res_lst_new();

	// prepare response
	while ((item = sys_lst_pop(results)) != NULL) {
		response_t response;
		response.res = (bs_pdu_res_t*) malloc(sizeof(bs_pdu_res_t));
		response.ressz = sizeof(*(response.res)) - sizeof(response.res->body) +
			sizeof(response.res->body.release);
		response.res->type = REQ_RELEASE;
		response.res->status = RES_ERROR;
		
		bs_pdu_res_release_t* res = &(response.res->body.release);
		system_res_release_t* sys_res = &(item->system_response.release);
		
		strncpy(res->title, sys_res->title, MAX_BOOKNAME_SIZE);
		strncpy(res->counter, sys_res->counter, MAX_COUNTER_SIZE);
		strncpy(res->reason, sys_res->reason, MAX_REASON_SIZE);
		
		if (item->status != ERROR) {
			response.res->status = RES_OK;
		}
		
		res_lst_insert(*res_lst, &response);
		free(item);
	}
	
	sys_lst_destroy(results);
}


void bs_return(bs_pdu_req_t *req, int reqsz, res_list_t **res_lst) {
	printf("\33[1m[bs_return]\33[0m handling a 'Return' request.\n");
  
	// get input arguments
  	char* titles = req->body.returns.titles;

	printf("\33[1m[bs_return]\33[0m received Return message of '%s'\n", titles);
	
	// handle request
	system_return(titles);
	
	*res_lst = res_lst_new();
	
	// prepare response
	response_t response;
	response.res = (bs_pdu_res_t*) malloc(sizeof(bs_pdu_res_t));
	response.ressz = sizeof(*(response.res)) - sizeof(response.res->body) +
		sizeof(response.res->body.returns);
	response.res->type = REQ_RETURN;
	response.res->status = RES_OK;
	res_lst_insert(*res_lst, &response);
}
