package dhm.imageserver.imagestore;

import dhm.imageserver.Cache;
import dhm.imageserver.cache.NullCache;
import dhm.imageserver.util.IO;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * An ImageStore that uses a cache. Both 'gets' and 'puts' will cache the image data. The cache is an instance
 * of dhm.imageserver.Cache.
 * This implementation only caches the original (untransformed) image. (A more aggressive implementation could
 * be implemented to use the request parameters as part of the cache key, to cache any transformed version of the image.)
 */
public class CachingImageStore extends BasicImageStore {
    private static final Logger logger = LoggerFactory.getLogger(CachingImageStore.class);

    private Cache cache;

    public CachingImageStore() {
        this(new NullCache());
    }

    public CachingImageStore(Cache cache) {
        logger.info("Construct {}", getClass().getName());
        this.cache = cache;
    }

    public void setCache(Cache cache) {
        this.cache = cache;
    }

    @Override
    protected InputStream get(String key) throws Exception {
        byte[] data = cache.get(key);
        if (data != null) {
            logger.info("cache hit key: {} size: {} B", key, data.length);
        } else {
            logger.info("Cache miss: key {}", key);
            InputStream str = super.get(key);
            if (str == null) {
                logger.info("key {} not found", key);
                return null;
            }

            logger.debug("Value for {} found, saving to cache", key);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            IO.stream(str, bos);
            data = bos.toByteArray();
            cache.put(key, data);
        }
        return new ByteArrayInputStream(data);
    }

    public void put(String key, long contentLength, InputStream value) throws Exception {
        logger.info("caching value for key ", key);
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        IO.stream(value, bos);
        byte[] data = bos.toByteArray();
        cache.put(key, data);
        super.put(key, data.length, new ByteArrayInputStream(data));
    }
}
