/**
 *  GraphTFT plugin for the Video Disk Recorder 
 * 
 *  cache.h - A plugin for the Video Disk Recorder
 *
 *  (c) 2004 Lars Tegeler, Sascha Volkenandt  
 *
 * This code is distributed under the terms and conditions of the
 * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
 *
 * $Id: cache.h,v 1.2 2004/05/08 18:55:45 tegeler Exp $
 *
 **/
#ifndef __GTFT_CACHE_H
#define __GTFT_CACHE_H

#include <map>
#include "common.h"

// template class generic cache

template<class K,class D>
class DataCache {
private:
	struct Item {
		K      _key;
		D      _data;
		time_t _lastUsed;

		Item  *_next;
		Item  *_prev;

		Item() { _next = _prev = NULL; }
	};

	typedef std::map <K,Item*> DataMap;

	DataMap _items;
	int     _maxItems;
	Item   *_first;
	Item   *_last;
		
	void Unlink(Item *item);
	void Update(Item *item);
	void Delete(Item *item);
	void Delete(K &key, D &data);

public:
	DataCache(int maxItems);
	~DataCache();

	bool Contains(const K &key);
	D &operator[](const K &key);
	void Clear();
};

template<class K,class D>
inline void DataCache<K,D>::Unlink(Item *item) {
	if (item == _first) {
		_first = item->_next;
		if (_first)
			_first->_prev = NULL;
		else
			_last = NULL;
	} else if (item == _last) {
		_last = item->_prev;
		_last->_next = NULL;
	} else {
		item->_prev->_next = item->_next;
		item->_next->_prev = item->_prev;
	}
}

template<class K,class D>
inline void DataCache<K,D>::Update(Item *item) {
	item->_lastUsed = time_ms();
	if (item->_next != NULL || item->_prev != NULL)
		Unlink(item);

	item->_next = NULL;
	item->_prev = _last;
	if (_last)
		_last->_next = item;
	_last = item;
	if (!_first)
		_first = item;

	while ((int)_items.size() > _maxItems) {
		Item *aged = _first;
		_items.erase(aged->_key);
		Unlink(aged);
		Delete(aged);
	}
}

template<class K,class D>
inline void DataCache<K,D>::Delete(Item *item) {
	Delete(item->_key, item->_data);
	delete item;
}

template<class K,class D>
inline void DataCache<K,D>::Delete(K &key, D &Data) {
}

template<class K,class D>
inline bool DataCache<K,D>::Contains(const K &key) {
	return (_items.find(key) != _items.end());
}

template<class K,class D>
DataCache<K,D>::DataCache(int maxItems) {
	_maxItems = maxItems;
	_first = _last = NULL;
}

template<class K,class D>
DataCache<K,D>::~DataCache() {
}

template<class K,class D>
D &DataCache<K,D>::operator[](const K &key) {
	Item *item;
	if (Contains(key)) {
		item = _items[key];
	} else {
		item = new Item;
		item->_key = key;
		_items[key] = item;
	}
	Update(item);
	return item->_data;
}

template<class K,class D>
void DataCache<K,D>::Clear() {
	Item *item = _first;
	while (item) {
		Item *next = item->_next;
		Delete(item);
		item = next;
	}
	_first = _last = NULL;
	_items.clear();
}

#include <directfb.h>
#include <string>
#include <memory>

// instantiation of image cache

typedef DataCache<std::string,IDirectFBSurface*> ImageCache;

template<>
inline void ImageCache::Delete(std::string &key, IDirectFBSurface *&data) {
	data->Release(data);
}

extern ImageCache imageCache;

// instantiation of font cache

typedef std::pair<std::string,int> FontFaceSize;
typedef DataCache<FontFaceSize,IDirectFBFont*> FontCache;

template<>
inline void FontCache::Delete(FontFaceSize &key, IDirectFBFont *&data) {
	data->Release(data);
}

extern FontCache fontCache;

#endif // __GTFT_CACHE_H
