#include "ftptool.h"

#ifdef USE_PROTOTYPES
int dircache_add(struct dircache *dcache, char *name, struct dirlist *dlist)
#else
int dircache_add(dcache, name, dlist)
struct dircache *dcache;
char	*name;
struct dirlist *dlist;
#endif
{
	struct dirlist_header *new_header;
	struct dirlist_header *last;

	if (dircache_size != 0 && dircache_size == dcache->ndirs) {
		last = dcache->last;
		if (dcache->ndirs == 1) {
			dcache->first = NULL;
			dcache->last = NULL;
		} else {
			dcache->last = dcache->last->prev;
			dcache->last->next = NULL;
		}
		free_dirlist_header(last);
		dcache->ndirs--;
	}
	new_header = new_dirlist_header(name, dlist);
	if (new_header == NULL)
		return ENOMEM;
	if (dcache->ndirs == 0) {
		dcache->first = new_header;
		dcache->last = new_header;
		new_header->next = NULL;
		new_header->prev = NULL;
	} else {
		new_header->prev = NULL;
		new_header->next = dcache->first;
		dcache->first->prev = new_header;
		dcache->first = new_header;
	}

	dcache->ndirs++;

	return 0;
}

#ifdef USE_PROTOTYPES
void dircache_delete(struct dircache *dcache, char *name)
#else
void dircache_delete(dcache, name)
struct dircache *dcache;
char	*name;
#endif
{
	struct dirlist_header *first;

	if (cache_lookup(dcache, name) == NULL)
		return;
	/* now at top of list */
	first = dcache->first;
	if (dcache->ndirs == 1) {
		dcache->first = NULL;
		dcache->last = NULL;
	} else {
		dcache->first = first->next;
		dcache->first->prev = NULL;
	}
	free_dirlist_header(first);

	dcache->ndirs--;

	return;
}

#ifdef USE_PROTOTYPES
void dircache_shrink(struct dircache *dcache, int newsize)
#else
void dircache_shrink(dcache, newsize)
struct dircache *dcache;
int	newsize;
#endif
{
	struct dirlist_header *last;

	if (newsize == 0) 
		return;
	while (dcache->ndirs > newsize) {
		last = dcache->last;
		dcache->last = dcache->last->prev;
		dcache->last->next = NULL;
		free_dirlist_header(last);
		dcache->ndirs--;
	} 
}

#ifdef USE_PROTOTYPES
void free_dircache(struct dircache *dcache)
#else
void free_dircache(dcache)
struct dircache *dcache;
#endif
{
	struct dirlist_header *next;
	struct dirlist_header *tmp;

	for (tmp = dcache->first; tmp != NULL;) {
		next = tmp->next;
		free_dirlist_header(tmp);
		tmp = next;
	}
	dcache->ndirs = 0;
	dcache->first = NULL;
	dcache->last = NULL;
}

#ifdef USE_PROTOTYPES
struct dirlist *cache_lookup(struct dircache *dcache, char *dirname)
#else
struct dirlist *cache_lookup(dcache, dirname)
struct dircache *dcache;
char	*dirname;
#endif
{
	struct dirlist_header *tmp;

	for (tmp = dcache->first; tmp != NULL; tmp=tmp->next) 
		if (!strcmp(tmp->name, dirname)) {
			/* match! move to top of cache */
			if (tmp == dcache->first) {
				/* nothing to do */
				return tmp->dlist;
			} else if (tmp == dcache->last) {
				/* at least 2 */
				/* off list */
				dcache->last = dcache->last->prev;
				dcache->last->next = NULL;
			} else {
				/* in the middle */
				/* off list */
				tmp->prev->next = tmp->next;
				tmp->next->prev = tmp->prev;
			}
			/* now add to front */
			tmp->next = dcache->first;
			tmp->prev = NULL;
			dcache->first->prev = tmp;
			dcache->first = tmp;
			
			return tmp->dlist;
		}
	/* no match */
	return NULL;
}

#ifdef USE_PROTOTYPES
struct dirlist_header *new_dirlist_header(char *name, struct dirlist *dlist)
#else
struct dirlist_header *new_dirlist_header(name, dlist)
char	*name;
struct dirlist *dlist;
#endif
{
	struct dirlist_header *tmp;

	tmp = (struct dirlist_header *)malloc(sizeof(struct dirlist_header));
	if (tmp == NULL)
		return NULL;
	bzero((char *)tmp, sizeof(struct dirlist_header));
	tmp->name = strdup(name);
	if (tmp->name == NULL) {
		free((char *)tmp);
		return NULL;
	}
	tmp->next = NULL;
	tmp->prev = NULL;
	tmp->dlist = dlist;
	return tmp;
}

#ifdef USE_PROTOTYPES
void free_dirlist_header(struct dirlist_header *head)
#else
void free_dirlist_header(head)
struct dirlist_header *head;
#endif
{
	free_dirlist(head->dlist);
	free(head->name);
	free((char *)head);
}

#ifdef notdef

#ifdef USE_PROTOTYPES
void show_dircache(struct dircache *dcache)
#else
void show_dircache(dcache)
struct dircache *dcache;
#endif
{
	struct dirlist_header *tmp;

	printf("cache contains\n");
	printf("--------------\n");
	for (tmp = dcache->first; tmp != NULL; tmp=tmp->next) {
		printf("%s\n", tmp->name);
	}
	printf("--------------\n");
}

#endif
