/*******************************************************************************

  Copyright(c) 2003-2004 Aurelien Reynaud.

  This program is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by the Free
  Software Foundation; either version 2 of the License, or (at your option)
  any later version.

  This program is distributed in the hope that it will be useful, but WITHOUT
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  more details.

  You should have received a copy of the GNU General Public License along with
  this program; if not, write to the Free Software Foundation, Inc., 59
  Temple Place - Suite 330, Boston, MA  02111-1307, USA.

  The full GNU General Public License is included in this distribution in the
  file called COPYING.

*******************************************************************************/

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "ggiterm.h"
#include "debug.h"


extern int (*backend_cache_load)(void *, wchar_t, int, int, int);

cached_glyph_t *cache_head;


void* cache_get(wchar_t charcode, int fgcol, int bgcol, int underline)
{
	cached_glyph_t *current = cache_head, *prev, *prevprev;
	int i = 0;

	debug(DEBUG_FUNCTION,
	      "called with args (charcode=0x%X, fg=%d, bg=%d, underline=%d",
	      (wint_t)charcode, fgcol, bgcol, underline);
	
	while (current != NULL) {
		if (current->charcode  == charcode &&
		    current->fgcolor   == fgcol &&
		    current->bgcolor   == bgcol &&
		    current->underline == underline) {
			   if (current != cache_head) {
			   	prev->next    = current->next;
			   	current->next = cache_head;
			   	cache_head    = current;
			   }
			   /*debug(DEBUG_INIT, "Cache hit at position %d", i);*/
			   return cache_head->boxptr;
		}
		prevprev = prev;
		prev     = current;	   
		current  = current->next;
		i++;
	}
	
	/* The glyph isn't cached, let's load it */
	/*debug (DEBUG_INIT, "Cache miss!");*/
	prev->charcode  = charcode;
	prev->fgcolor   = fgcol;
	prev->bgcolor   = bgcol;
	prev->underline = underline;
	backend_cache_load(prev->boxptr, charcode, fgcol, bgcol, underline);
	prevprev->next = NULL;
	prev->next     = cache_head;
	cache_head     = prev;

	debug(DEBUG_FUNCTION, "Leaving");
	return cache_head->boxptr;
}

void cache_exit()
{
	cached_glyph_t *dummy;

	while (cache_head != NULL) {
		dummy = cache_head->next;
		free(cache_head->boxptr);
		free(cache_head);
		cache_head = dummy;
	}
}

int cache_init(long box_size)
{
	int i = 0;
	long used_mem = 0;
	cached_glyph_t *current;

	cache_head = NULL;
	do {
		current = malloc(sizeof (cached_glyph_t));
		if (current != NULL) {
			current->boxptr = malloc(box_size);
			if (current->boxptr != NULL) {
				current->charcode  = 0;
				current->underline = 0;
				current->bgcolor   = 0;
				current->fgcolor   = 0;
				current->next      = cache_head;
				cache_head = current;
				used_mem += sizeof (cached_glyph_t) + box_size;
				i++;
			} else {
				free(current);
				break;
			}
		} else {
			break;
		}
	} while (i < 2 ||
	        used_mem + sizeof (cached_glyph_t) + box_size <= CACHE_MAX_SIZE);
	
	/* the linked list must have at least 2 elements */
	if (i < 2) {
		cache_exit();
		return 1;
	}

	debug(DEBUG_INIT, "cache size: %ld bytes (%d glyphs)", used_mem, i);
	return 0;
}
