/*
 * cache.c
 *
 *  Created on: 08.02.2017
 *      Author: hoene
 */

#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "mysofa_export.h"
#include "mysofa.h"
#include "../hdf/reader.h"

static struct MYSOFA_CACHE_ENTRY {
	struct MYSOFA_CACHE_ENTRY *next;
	struct MYSOFA_EASY *easy;
	char *filename;
	float samplerate;
	int count;
} *cache;

static int compare_filenames(const char *a, const char *b)
{
	if(a == NULL && b == NULL)
		return 0;
	if(a == NULL)
		return -1;
	else if(b == NULL)
		return 1;
	return strcmp(a,b);
}

MYSOFA_EXPORT struct MYSOFA_EASY *mysofa_cache_lookup(const char *filename, float samplerate)
{
	struct MYSOFA_CACHE_ENTRY *p;
	struct MYSOFA_EASY *res = NULL;

	p = cache;

	while(p) {
		if(samplerate == p->samplerate && !compare_filenames(filename, p->filename)) {
			res = p->easy;
			p->count++;
			break;
		}
		p=p->next;
	}

	return res;
}

MYSOFA_EXPORT struct MYSOFA_EASY *mysofa_cache_store(struct MYSOFA_EASY *easy, const char *filename, float samplerate)
{
	struct MYSOFA_CACHE_ENTRY *p;

	assert(easy);

	p = cache;

	while(p) {
		if(samplerate == p->samplerate && !compare_filenames(filename, p->filename)) {
			mysofa_close(easy);
			return p->easy;
		}
		p=p->next;
	}

	p = malloc(sizeof(struct MYSOFA_CACHE_ENTRY));
	if(p == NULL) {
		return NULL;
	}
	p->next = cache;
	p->samplerate = samplerate;
	p->filename = NULL;
	if(filename != NULL) {
		p->filename = mysofa_strdup(filename);
		if(p->filename == NULL) {
			free(p);
			return NULL;
		}
	}
	p->easy = easy;
	p->count = 1;
	cache = p;
	return easy;
}

MYSOFA_EXPORT void mysofa_cache_release(struct MYSOFA_EASY *easy)
{
	struct MYSOFA_CACHE_ENTRY **p;
	int count;

	assert(easy);
	assert(cache);

	p = &cache;

	for(count=0;;count++) {
		if((*p)->easy == easy)
			break;
		p = &((*p)->next);
		assert(*p);
	}

	if((*p)->count==1 && (count>0 || (*p)->next != NULL)) {
		struct MYSOFA_CACHE_ENTRY *gone = *p;
		free(gone->filename);
		mysofa_close(easy);
		*p = (*p)->next;
		free(gone);
	}
	else {
		(*p)->count--;
	}
}

MYSOFA_EXPORT void mysofa_cache_release_all()
{
	struct MYSOFA_CACHE_ENTRY *p;

	p = cache;
	while(p) {
		struct MYSOFA_CACHE_ENTRY *gone = p;
		p=p->next;
		free(gone->filename);
		free(gone->easy);
		free(gone);
	}
	cache = NULL;
}

