package com.pr0gramm.app.util;

import android.graphics.Bitmap;

import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ImmutableList;
import com.squareup.picasso.Cache;

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

import java.util.List;

import static com.google.common.collect.Iterables.filter;

/**
 * This is a better cache for {@link com.squareup.picasso.Picasso}.
 * Firstly, it uses {@link java.lang.ref.WeakReference}s for the values and secondly,
 * it only caches small images (for the feed).
 * <p>
 * This should prevent further out of memory errors.
 */
public class GuavaPicassoCache implements Cache {
    private static final Logger logger = LoggerFactory.getLogger("GuavaPicassoCache");
    private static final long MAX_CACHE_ITEM_SIZE = 128 * 128 * 4;

    private final com.google.common.cache.Cache<String, Bitmap> cache;
    private final int maxSize;

    public GuavaPicassoCache(int maxSize) {
        logger.info("Initializing cache with about " + maxSize / (1024 * 1024) + "mb");

        this.maxSize = maxSize;
        cache = CacheBuilder.<String, Bitmap>newBuilder()
                .softValues()
                .weigher((String key, Bitmap bitmap) -> bitmap.getByteCount())
                .maximumWeight(maxSize)
                .recordStats()
                .build();
    }

    @Override
    public Bitmap get(String key) {
        return cache.getIfPresent(key);
    }

    @Override
    public void set(String key, Bitmap bitmap) {
        if (bitmap.getByteCount() <= MAX_CACHE_ITEM_SIZE) {
            cache.put(key, bitmap);
        }

        // logger.info("Stats: " + cache.stats());
    }

    @Override
    public int size() {
        int size = 0;
        for (Bitmap bitmap : cache.asMap().values())
            size += bitmap.getByteCount();

        return size;
    }

    @Override
    public int maxSize() {
        return maxSize;
    }

    @Override
    public void clear() {
        cache.invalidateAll();
        cache.cleanUp();
    }

    @Override
    public void clearKeyUri(String keyPrefix) {
        List<String> keys = ImmutableList.copyOf(cache.asMap().keySet());
        Iterable<String> matchingKeys = filter(keys, key -> key.startsWith(keyPrefix));
        cache.invalidateAll(matchingKeys);
    }

    public static GuavaPicassoCache defaultSizedGuavaCache() {
        // go for about 10% of the runtimes memory
        int maxMemory = (int) Runtime.getRuntime().maxMemory() / 10;
        return new GuavaPicassoCache(maxMemory);
    }
}

@@ -56,16 +56,65 @@
 .Bitmap;
+%0Aimport android.support.v4.graphics.BitmapCompat;
 %0A%0Aimport
@@ -1265,28 +1265,24 @@
 p) -%3E bitmap
-.get
 ByteCount())
@@ -1279,16 +1279,22 @@
 teCount(
+bitmap
 ))%0A     
@@ -1384,32 +1384,148 @@
 build();%0A    %7D%0A%0A
+    private int bitmapByteCount(Bitmap bitmap) %7B%0A        return BitmapCompat.getAllocationByteCount(bitmap);%0A    %7D%0A%0A
     @Override%0A  
@@ -1682,28 +1682,24 @@
   if (bitmap
-.get
 ByteCount() 
@@ -1696,16 +1696,22 @@
 teCount(
+bitmap
 ) %3C= MAX
@@ -1974,20 +1974,16 @@
 = bitmap
-.get
 ByteCoun
@@ -1984,16 +1984,22 @@
 teCount(
+bitmap
 );%0A%0A    
@@ -2546,81 +2546,53 @@
     
-// go for about 10%25 of the runtimes memory%0A        int maxMemory =
+int maxMemory = Math.max(1024 * 1024,
  (int) 
+(
 Runt
@@ -2622,18 +2622,21 @@
 ory() / 
-10
+20L))
 ;%0A      

Use less memory for the preview cache as we are now using less memory for the bitmaps.