/*
 * This file is part of the UCB release of Plan 9. It is subject to the license
 * terms in the LICENSE file found in the top-level directory of this
 * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
 * part of the UCB release of Plan 9, including this file, may be copied,
 * modified, propagated, or distributed except according to the terms contained
 * in the LICENSE file.
 */

#include <u.h>
#include <lib9.h>
#include <draw.h>
#include <thread.h>
#include <mouse.h>
#include <keyboard.h>
#include <control.h>

typedef struct Cache Cache;

struct Cache
{
	char		*name;
	CCache	**cache;
	int		ncache;
};

static struct Cache imagecache = {"image"};
static struct Cache fontcache = {"font"};

static CCache*
getcacheitem(Cache *c, char *name)
{
	int i;

	for(i=0; i<c->ncache; i++)
		if(c->cache[i]!=nil && strcmp(c->cache[i]->name, name)==0){
			c->cache[i]->ref++;
			return c->cache[i];
		}
	return nil;
}

static int
namecacheitem(Cache *c, void *image, char *name)
{
	int i, free;
	CCache *cc;

	free = -1;
	for(i=0; i<c->ncache; i++){
		if(c->cache[i] == nil){
			free = i;
			continue;
		}
		if(strcmp(c->cache[i]->name, name) == 0){
			werrstr("%s name %q already in use", c->name, name);
			return -1;
		}
	}
	cc = ctlmalloc(sizeof(CCache));
	cc->image = image;
	cc->name = ctlstrdup(name);
	if(free >= 0){
		cc->index = free;
		c->cache[free] = cc;
	}else{
		cc->index = c->ncache;
		c->cache = ctlrealloc(c->cache, (c->ncache+1)*sizeof(CCache*));
		c->cache[c->ncache++] = cc;
	}
	cc->ref = 1;
	return 1;
}

static int
freecacheitem(Cache *c, char *name)
{
	CCache	*cc;

	cc = getcacheitem(c, name);
	if(cc == nil){
		werrstr("%s name %q not in use", c->name, name);
		return -1;
	}
	cc->ref--;	/* getcacheitem increments ref */
	if(cc->ref-- == 1){
		/* client must free object itself */
		free(cc->name);
		c->cache[cc->index] = nil;
		free(cc);
	}
	return 0;
}

static void
putcacheitem(CCache *cc)
{
	if(cc == nil)
		return;
	cc->ref--;
}

static void
setcacheitemptr(Cache *c, Control *ctl, CCache **cp, char *s)
{
	CCache *ci;

	ci = getcacheitem(c, s);
	if(ci == nil)
		ctlerror("%q: %s name %q not defined", ctl->name, c->name, s);
	putcacheitem(*cp);
	*cp = ci;
}

/* Images */

CImage*
_getctlimage(char *name)
{
	return getcacheitem(&imagecache, name);
}

void
_putctlimage(CImage *c)
{
	putcacheitem(c);
}

int
namectlimage(Image *image, char *name)
{
	return namecacheitem(&imagecache, image, name);
}

int
freectlimage(char *name)
{
	return freecacheitem(&imagecache, name);
}

void
_setctlimage(Control *c, CImage **cp, char *s)
{
	setcacheitemptr(&imagecache, c, cp, s);
}

/* Fonts */

CFont*
_getctlfont(char *name)
{
	return getcacheitem(&fontcache, name);
}

void
_putctlfont(CFont *c)
{
	putcacheitem(c);
}

int
namectlfont(Font *font, char *name)
{
	return namecacheitem(&fontcache, font, name);
}

int
freectlfont(char *name)
{
	return freecacheitem(&fontcache, name);
}

void
_setctlfont(Control *c, CFont **cp, char *s)
{
	setcacheitemptr(&fontcache, c, cp, s);
}
