1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.gallery3d.filtershow.cache;
18
19import android.graphics.Bitmap;
20
21import com.android.gallery3d.filtershow.imageshow.ImageShow;
22import com.android.gallery3d.filtershow.presets.ImagePreset;
23
24import java.util.Vector;
25
26public class DirectPresetCache implements Cache {
27
28    private static final String LOGTAG = "DirectPresetCache";
29    private Bitmap mOriginalBitmap = null;
30    private final Vector<ImageShow> mObservers = new Vector<ImageShow>();
31    private final Vector<CachedPreset> mCache = new Vector<CachedPreset>();
32    private int mCacheSize = 1;
33    private final Bitmap.Config mBitmapConfig = Bitmap.Config.ARGB_8888;
34    private long mGlobalAge = 0;
35    private ImageLoader mLoader = null;
36
37    protected class CachedPreset {
38        private Bitmap mBitmap = null;
39        private ImagePreset mPreset = null;
40        private long mAge = 0;
41        private boolean mBusy = false;
42
43        public void setBusy(boolean value) {
44            mBusy = value;
45        }
46
47        public boolean busy() {
48            return mBusy;
49        }
50    }
51
52    public DirectPresetCache(ImageLoader loader, int size) {
53        mLoader = loader;
54        mCacheSize = size;
55    }
56
57    @Override
58    public void setOriginalBitmap(Bitmap bitmap) {
59        mOriginalBitmap = bitmap;
60        notifyObservers();
61    }
62
63    public void notifyObservers() {
64        mLoader.getActivity().runOnUiThread(mNotifyObserversRunnable);
65    }
66
67    private final Runnable mNotifyObserversRunnable = new Runnable() {
68        @Override
69        public void run() {
70            for (int i = 0; i < mObservers.size(); i++) {
71                ImageShow imageShow = mObservers.elementAt(i);
72                imageShow.invalidate();
73                imageShow.updateImage();
74            }
75        }
76    };
77
78    @Override
79    public void addObserver(ImageShow observer) {
80        if (!mObservers.contains(observer)) {
81            mObservers.add(observer);
82        }
83    }
84
85    private CachedPreset getCachedPreset(ImagePreset preset) {
86        for (int i = 0; i < mCache.size(); i++) {
87            CachedPreset cache = mCache.elementAt(i);
88            if (cache.mPreset == preset) {
89                return cache;
90            }
91        }
92        return null;
93    }
94
95    @Override
96    public Bitmap get(ImagePreset preset) {
97        // Log.v(LOGTAG, "get preset " + preset.name() + " : " + preset);
98        CachedPreset cache = getCachedPreset(preset);
99        if (cache != null && !cache.mBusy) {
100            return cache.mBitmap;
101        }
102        // Log.v(LOGTAG, "didn't find preset " + preset.name() + " : " + preset
103        // + " we have " + mCache.size() + " elts / " + mCacheSize);
104        return null;
105    }
106
107    @Override
108    public void reset(ImagePreset preset) {
109        CachedPreset cache = getCachedPreset(preset);
110        if (cache != null && !cache.mBusy) {
111            cache.mBitmap = null;
112            willCompute(cache);
113        }
114    }
115
116    private CachedPreset getOldestCachedPreset() {
117        CachedPreset found = null;
118        for (int i = 0; i < mCache.size(); i++) {
119            CachedPreset cache = mCache.elementAt(i);
120            if (cache.mBusy) {
121                continue;
122            }
123            if (found == null) {
124                found = cache;
125            } else {
126                if (found.mAge > cache.mAge) {
127                    found = cache;
128                }
129            }
130        }
131        return found;
132    }
133
134    protected void willCompute(CachedPreset cache) {
135        if (cache == null) {
136            return;
137        }
138        cache.mBusy = true;
139        compute(cache);
140        didCompute(cache);
141    }
142
143    protected void didCompute(CachedPreset cache) {
144        cache.mBusy = false;
145        notifyObservers();
146    }
147
148    protected void compute(CachedPreset cache) {
149        cache.mBitmap = null;
150        cache.mBitmap = mOriginalBitmap.copy(mBitmapConfig, true);
151        float scaleFactor = (float) cache.mBitmap.getWidth() / (float) mLoader.getOriginalBounds().width();
152        if (scaleFactor < 1.0f) {
153            cache.mPreset.setIsHighQuality(false);
154        }
155        cache.mPreset.setScaleFactor(scaleFactor);
156        cache.mBitmap = cache.mPreset.apply(cache.mBitmap);
157        cache.mAge = mGlobalAge++;
158    }
159
160    @Override
161    public void prepare(ImagePreset preset) {
162        // Log.v(LOGTAG, "prepare preset " + preset.name() + " : " + preset);
163        CachedPreset cache = getCachedPreset(preset);
164        if (cache == null || (cache.mBitmap == null && !cache.mBusy)) {
165            if (cache == null) {
166                if (mCache.size() < mCacheSize) {
167                    cache = new CachedPreset();
168                    mCache.add(cache);
169                } else {
170                    cache = getOldestCachedPreset();
171                }
172            }
173            if (cache != null) {
174                cache.mPreset = preset;
175                willCompute(cache);
176            }
177        }
178
179    }
180
181}
182