/* 
 * Book Share Timeout Layer
 * 
 * timeout.c
 * 
 * Manages the internal organization of the system timeouts and how should
 * they be handled.
 * 
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <config.h>
#include <timer.h>
#include "storage.h"

#define MAX_NUM_TIMERS 1000


typedef struct {
	char *username;
	char *bookname;
	int id;
} timer_running_t;


static timer_running_t Current_timers[MAX_NUM_TIMERS];

static pthread_mutex_t Timers_mutex = PTHREAD_MUTEX_INITIALIZER;


static void *timeout_reserve_expire(void *context) {
	printf("\33[1m[timeout_reserve_expire]\33[0m timer expired, canceling book.\n");
	
	pthread_mutex_lock(&Timers_mutex);
	
	timer_running_t *cur = (timer_running_t*) context;
	
	if (cur->username != NULL && cur->bookname != NULL) {
		storage_cancel(cur->username, cur->bookname);
		free(cur->username);
		free(cur->bookname);
		cur->username = NULL;
		cur->bookname = NULL;
		cur->id = 0;
	}
	
	pthread_mutex_unlock(&Timers_mutex);
	
	return NULL;
}


int timeout_reserve_start(char *username, char *bookname) {
	pthread_mutex_lock(&Timers_mutex);
	
	for (int i = 0; i < MAX_NUM_TIMERS; i++) {
		if (Current_timers[i].username == NULL && Current_timers[i].bookname == NULL) {
			timer_running_t *cur = &(Current_timers[i]);
			cur->username = username;
			cur->bookname = bookname;
			cur->id = timer_set(TIMEOUT_RESERVE, timeout_reserve_expire, (void *)cur);
			
			pthread_mutex_unlock(&Timers_mutex);
			
			printf("\33[1m[timeout_reserve_start]\33[0m started timer.\n");
			return 0;
		}
	}
	
	pthread_mutex_unlock(&Timers_mutex);
	
	printf("\33[1m[timeout_reserve_start]\33[0m unable to start timer.\n");
	return -1;
}


int timeout_reserve_cancel(char *username, char *bookname) {
	pthread_mutex_lock(&Timers_mutex);
	
	for (int i = 0; i < MAX_NUM_TIMERS; i++) {
		if (Current_timers[i].username != NULL
			&& strcmp(Current_timers[i].username, username) == 0
			&& Current_timers[i].bookname != NULL
			&& strcmp(Current_timers[i].bookname, bookname) == 0) {
			timer_cancel(Current_timers[i].id);
			free(Current_timers[i].username);
			free(Current_timers[i].bookname);
			Current_timers[i].username = NULL;
			Current_timers[i].bookname = NULL;
			Current_timers[i].id = 0;
			
			pthread_mutex_unlock(&Timers_mutex);
			
			printf("\33[1m[timeout_reserve_cancel]\33[0m canceled timer.\n");
			return 0;
		}
	}
	
	pthread_mutex_unlock(&Timers_mutex);
	
	printf("\33[1m[timeout_reserve_cancel]\33[0m unable to cancel timer.\n");
	return -1;
}
