/* 
 * Storage Layer
 * 
 * storage.c
 *
 * Interface to the storage layer.
 * 
 */

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


/*
 * storage_filename: the file name that stores the books data
 */
static char storage_filename[MAX_FILENAME_SIZE];
static pthread_mutex_t Titles_dat_mutex;

int storage_new(char *filename) {
	FILE *fp = NULL;
	char temp_bookname[MAX_BOOKNAME_SIZE];
	
	strncpy(storage_filename, filename, MAX_FILENAME_SIZE - 1);
	
	fp = fopen(storage_filename, "r+");

	if (fp == NULL) {
		return -1;
	}
	
	for (long p = ftell(fp);
		fseek(fp, p, SEEK_SET) != -1 && fscanf(fp, "%s", temp_bookname) != EOF;
		p += MAX_BOOKNAME_SIZE + 11 + 2 * auth_total_users() * 11) {
		
		for (int i = 0; i < 2 * auth_total_users(); i++) {
			fseek(fp, p + MAX_BOOKNAME_SIZE + 11 + i * 11, SEEK_SET);
			fprintf(fp, "%10d", 0);
		}
	}
	
	fclose(fp);
	
	printf("\33[1m[storage_new]\33[0m '%s' loaded.\n", filename);
	return 0;
}


void storage_give(char *bookname) {
	pthread_mutex_lock(&Titles_dat_mutex);
	
	FILE *fp = fopen(storage_filename, "r+");
	char temp_bookname[MAX_BOOKNAME_SIZE];
	int temp_quantity;
	
	for (long p = ftell(fp);
		fseek(fp, p, SEEK_SET) != -1 && fscanf(fp, "%s\t%d", temp_bookname, &temp_quantity) != EOF;
		p += MAX_BOOKNAME_SIZE + 11 + 2 * auth_total_users() * 11) {
				
		if (strncmp(bookname, temp_bookname, MAX_BOOKNAME_SIZE - 1) == 0) {

			fseek(fp, p + MAX_BOOKNAME_SIZE, SEEK_SET);
			fprintf(fp, "%10d", temp_quantity + 1);
			fclose(fp);
			
			pthread_mutex_unlock(&Titles_dat_mutex);
			return;
		}
	}
	
	/* If there's no bookname adds one book with that name */
	fseek(fp, 0L, SEEK_END);
	fprintf(fp, "%s\t%10d", bookname, 1);
	
	for (int i = 0; i < 2 * auth_total_users(); i++) {
		fprintf(fp, "\t%10d", 0);
	}
	
	fprintf(fp, "\n");
	fclose(fp);
	pthread_mutex_unlock(&Titles_dat_mutex);
}


int storage_search(char *username, char *password, char *bookname) {
	pthread_mutex_lock(&Titles_dat_mutex);
	
	int id = auth_login(username, password);
	FILE *fp = fopen(storage_filename, "r+");
	char temp_bookname[MAX_BOOKNAME_SIZE];
	int temp_quantity;
	
	if (id == 0) {
		fclose(fp);
		
		pthread_mutex_unlock(&Titles_dat_mutex);
		return -1;
	}
	
	for (long p = ftell(fp);
		fseek(fp, p, SEEK_SET) != -1 && fscanf(fp, "%s\t%d", temp_bookname, &temp_quantity) != EOF;
		p += MAX_BOOKNAME_SIZE + 11 + 2 * auth_total_users() * 11) {
		
		if (strncmp(bookname, temp_bookname, MAX_BOOKNAME_SIZE - 1) == 0) {
			
			if (temp_quantity == 0) {
				fclose(fp);
				
				pthread_mutex_unlock(&Titles_dat_mutex);
				return -2;
			}
			
			fseek(fp, p + MAX_BOOKNAME_SIZE, SEEK_SET);
			fprintf(fp, "%10d", temp_quantity - 1);
			
			fseek(fp, p + MAX_BOOKNAME_SIZE + 11 + 2 * (id - 1) * 11, SEEK_SET);
			fscanf(fp, "%d", &temp_quantity);
			
			fseek(fp, p + MAX_BOOKNAME_SIZE + 11 + 2 * (id - 1) * 11, SEEK_SET);
			fprintf(fp, "%10d", temp_quantity + 1);
			
			fclose(fp);
			
			pthread_mutex_unlock(&Titles_dat_mutex);
			return 0;
		}
	}
	
	fclose(fp);
	
	pthread_mutex_unlock(&Titles_dat_mutex);
	return -2;
}


int storage_take(char *username, char *bookname) {
	pthread_mutex_lock(&Titles_dat_mutex);
	
	int id = auth_lookup(username);
	FILE *fp = fopen(storage_filename, "r+");
	char temp_bookname[MAX_BOOKNAME_SIZE];
	int temp_quantity;
	
	if (id == 0) {
		fclose(fp);
		
		pthread_mutex_unlock(&Titles_dat_mutex);
		return -1;
	}
	
	for (long p = ftell(fp);
		fseek(fp, p, SEEK_SET) != -1 && fscanf(fp, "%s", temp_bookname) != EOF;
		p += MAX_BOOKNAME_SIZE + 11 + 2 * auth_total_users() * 11) {
		
		if (strncmp(bookname, temp_bookname, MAX_BOOKNAME_SIZE - 1) == 0) {
			
			fseek(fp, p + MAX_BOOKNAME_SIZE + 11 + 2 * (id - 1) * 11, SEEK_SET);
			fscanf(fp, "%d", &temp_quantity);
			
			if (temp_quantity == 0) {
				fclose(fp);
				
				pthread_mutex_unlock(&Titles_dat_mutex);
				return -2;
			}
			
			fseek(fp, p + MAX_BOOKNAME_SIZE + 11 + 2 * (id - 1) * 11, SEEK_SET);
			fprintf(fp, "%10d", temp_quantity - 1);
			
			fseek(fp, p + MAX_BOOKNAME_SIZE + 11 + 2 * (id - 1) * 11 + 11, SEEK_SET);
			fscanf(fp, "%d", &temp_quantity);
			
			fseek(fp, p + MAX_BOOKNAME_SIZE + 11 + 2 * (id - 1) * 11 + 11, SEEK_SET);
			fprintf(fp, "%10d", temp_quantity + 1);
			
			fclose(fp);
			
			pthread_mutex_unlock(&Titles_dat_mutex);
			return 0;
		}
	}
	
	fclose(fp);
	
	pthread_mutex_unlock(&Titles_dat_mutex);
	return -2;
}


int storage_cancel(char *username, char *bookname) {
	pthread_mutex_lock(&Titles_dat_mutex);
	
	int id = auth_lookup(username);
	FILE *fp = fopen(storage_filename, "r+");
	char temp_bookname[MAX_BOOKNAME_SIZE];
	int temp_quantity;
	
	if (id == 0) {
		fclose(fp);
		
		pthread_mutex_unlock(&Titles_dat_mutex);
		return -1;
	}
	
	for (long p = ftell(fp);
		fseek(fp, p, SEEK_SET) != -1 && fscanf(fp, "%s", temp_bookname) != EOF;
		p += MAX_BOOKNAME_SIZE + 11 + 2 * auth_total_users() * 11) {
		
		if (strncmp(bookname, temp_bookname, MAX_BOOKNAME_SIZE - 1) == 0) {
			
			fseek(fp, p + MAX_BOOKNAME_SIZE + 11 + 2 * (id - 1) * 11, SEEK_SET);
			fscanf(fp, "%d", &temp_quantity);
			
			if (temp_quantity == 0) {
				fclose(fp);
				
				pthread_mutex_unlock(&Titles_dat_mutex);
				return -2;
			}
			
			fseek(fp, p + MAX_BOOKNAME_SIZE + 11 + 2 * (id - 1) * 11, SEEK_SET);
			fprintf(fp, "%10d", temp_quantity - 1);
			
			fseek(fp, p + MAX_BOOKNAME_SIZE, SEEK_SET);
			fscanf(fp, "%d", &temp_quantity);
			
			fseek(fp, p + MAX_BOOKNAME_SIZE, SEEK_SET);
			fprintf(fp, "%10d", temp_quantity + 1);
			
			fclose(fp);
			
			pthread_mutex_unlock(&Titles_dat_mutex);
			return 0;
		}
	}
	
	fclose(fp);
	
	pthread_mutex_unlock(&Titles_dat_mutex);
	return -2;
}


int storage_release(char *username, char *bookname, int makeavailable) {
	pthread_mutex_lock(&Titles_dat_mutex);
	
	int id = auth_lookup(username);
	FILE *fp = fopen(storage_filename, "r+");
	char temp_bookname[MAX_BOOKNAME_SIZE];
	int temp_quantity;
	
	if (id == 0) {
		fclose(fp);
		
		pthread_mutex_unlock(&Titles_dat_mutex);
		return -1;
	}
	
	for (long p = ftell(fp);
		fseek(fp, p, SEEK_SET) != -1 && fscanf(fp, "%s", temp_bookname) != EOF;
		p += MAX_BOOKNAME_SIZE + 11 + 2 * auth_total_users() * 11) {
		
		if (strncmp(bookname, temp_bookname, MAX_BOOKNAME_SIZE - 1) == 0) {
			
			fseek(fp, p + MAX_BOOKNAME_SIZE + 11 + 2 * (id - 1) * 11 + 11, SEEK_SET);
			fscanf(fp, "%d", &temp_quantity);
			
			if (temp_quantity == 0) {
				fclose(fp);
				
				pthread_mutex_unlock(&Titles_dat_mutex);
				return -2;
			}
			
			fseek(fp, p + MAX_BOOKNAME_SIZE + 11 + 2 * (id - 1) * 11 + 11, SEEK_SET);
			fprintf(fp, "%10d", temp_quantity - 1);
			
			if (makeavailable) {
				fseek(fp, p + MAX_BOOKNAME_SIZE, SEEK_SET);
				fscanf(fp, "%d", &temp_quantity);
				
				fseek(fp, p + MAX_BOOKNAME_SIZE, SEEK_SET);
				fprintf(fp, "%10d", temp_quantity + 1);
			}
			
			fclose(fp);
			
			pthread_mutex_unlock(&Titles_dat_mutex);
			return 0;
		}
	}
	
	fclose(fp);
	
	pthread_mutex_unlock(&Titles_dat_mutex);
	return -2;
}


void storage_dump() {
	FILE *fp = fopen(storage_filename, "r");
	int c;
	
	printf("Titles:\n");
	
	while ((c = fgetc(fp)) != EOF) {
		printf("%c", c);
	}
	
	fclose(fp);
}
