/*------------------------------------------------------------------------------
 src/bin/djview/imageCache.cxx

 Copyright (c) 2004-2006 Darby Johnston.
 All rights reserved.
 Use is subject to license terms.
------------------------------------------------------------------------------*/

//#define DJ_DBG
#include "imageCache.h"
#include "app.h"
#include <djImageOp.h>

namespace djview {

ImageRef::ImageRef(Image * in, const Str & key) :
  _image(in), _key(key)
{}

ImageRef::~ImageRef()
{
  delete _image;
}

void ImageRef::key(const Str & in)
{
  _key = in;
}

void ImageRef::del()
{
  djviewApp->imageCache().purge();
}

ImageCache::ImageCache(int max) :
  _cacheMax(max * megabyte), _cacheSize(0)
{
  DJ_DBG_FNC("ImageCache::ImageCache");
}

ImageCache::~ImageCache()
{
  DJ_DBG_FNC("~ImageCache::ImageCache");
# ifdef DJ_DBG
  dbg();
# endif
  
  for (ListIt<ImageRef *> it = _itemList; it.isValid(); ++it)
    delete it();
}

ImageRef * ImageCache::create(Image * image, const Str & key)
{
  DJ_DBG_FNC("ImageCache::create");
  DJ_DBG_PRN("image = " << *image);
  DJ_DBG_PRN("key = " << key);
# ifdef DJ_DBG
  dbg();
# endif

  ImageRef * out = new ImageRef(image, key);
  _itemList += out;
  _cacheSize += imageSize(*out->get());

# ifdef DJ_DBG
  dbg();
# endif
  return out;
}

ImageRef * ImageCache::get(const Str & key)
{
  DJ_DBG_FNC("ImageCache::get");
  DJ_DBG_PRN("key = " << key);
# ifdef DJ_DBG
  dbg();
# endif

  ImageRef * out = 0;
  for (ListIt<ImageRef *> it = _itemList.end(); it.isValid(); --it) {
    if (key == it()->key()) {
      out = it();
      out->ref();
      break;
    }
  }
  if (! out) DJ_DBG_PRN("not found");

# ifdef DJ_DBG
  dbg();
# endif

  return out;
}

const Str ImageCache::key(
  const Str & fileName,
  int proxy,
  int pixelFormat, int pixelType,
  int frame
) {
  return Str("%1 %2 %3 %4 %5").
    arg(fileName).
    arg(proxy).
    arg(pixelFormat).
    arg(pixelType).
    arg(frame);
}

void ImageCache::max(int in)
{
  DJ_DBG_FNC("ImageCache::max");
  DJ_DBG_PRN("in = " << in);
# ifdef DJ_DBG
  dbg();
# endif
  
  _cacheMax = in * megabyte;
  purge();
  
# ifdef DJ_DBG
  dbg();
# endif
}

int ImageCache::max() const
{
  return _cacheMax / megabyte;
}

void ImageCache::del(const Str & base)
{
  DJ_DBG_FNC("ImageCache::del");
  DJ_DBG_PRN("base = " << base);
# ifdef DJ_DBG
  dbg();
# endif

  for (ListIt<ImageRef *> it = _itemList; it.isValid(); ++it)
    if (compare(base, it()->key(), base.size()))
      it()->key(Str("null ") + it()->key());
  
# ifdef DJ_DBG
  dbg();
# endif
}

void ImageCache::del()
{
  DJ_DBG_FNC("ImageCache::del");
# ifdef DJ_DBG
  dbg();
# endif

  for (int i = 0; i < _itemList.size();)
    if (! _itemList[i]->count()) {
      ImageRef * tmp = _itemList.del(i);
      _cacheSize -= imageSize(*tmp->get());
      delete tmp;
    } else
      ++i;

# ifdef DJ_DBG
  dbg();
# endif
}

void ImageCache::purge()
{
  DJ_DBG_FNC("ImageCache::purge");
# ifdef DJ_DBG
  dbg();
# endif

  for (int i = 0; _cacheSize > _cacheMax && i < _itemList.size();)
    if (! _itemList[i]->count()) {
      ImageRef * tmp = _itemList.del(i);
      _cacheSize -= imageSize(*tmp->get());
      delete tmp;
    } else
      ++i;

# ifdef DJ_DBG
  dbg();
# endif
}

void ImageCache::dbg()
{
  DJ_DBG_FNC("ImageCache::dbg");
  DJ_DBG_PRN("items = " << _itemList.size());
  DJ_DBG_PRN("cache max = " << (_cacheMax / megabyte));
  DJ_DBG_PRN("cache size = " << (_cacheSize  / megabyte));
  
  for (ListIt<ImageRef *> it = _itemList; it.isValid(); ++it)
    DJ_DBG_PRN("item (ref = " << it()->count() << ") = " << it()->key());
}

}
