Update java library versions
[fw/altos] / altoslib / AltosMapCache.java
1 /*
2  * Copyright © 2010 Anthony Towns <aj@erisian.com.au>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 package org.altusmetrum.altoslib_9;
19
20 import java.io.*;
21 import java.net.*;
22
23 public class AltosMapCache implements AltosMapCacheListener {
24
25         /* An entry in the MapCache */
26         class MapCacheElement implements AltosMapStoreListener {
27
28                 AltosMapTile            tile;           /* Notify when image has been loaded */
29                 AltosImage              image;
30                 AltosMapStore           store;
31                 long                    used;
32
33                 class loader implements Runnable {
34                         public void run() {
35                                 if (image != null)
36                                         tile.notify_image(image);
37                                 try {
38                                         image = map_interface.load_image(store.file);
39                                 } catch (Exception ex) {
40                                 }
41                                 if (image == null)
42                                         tile.set_status(AltosMapTile.failed);
43                                 else
44                                         tile.set_status(AltosMapTile.success);
45                                 tile.notify_image(image);
46                         }
47                 }
48
49                 private void load() {
50                         loader  l = new loader();
51                         Thread  lt = new Thread(l);
52                         lt.start();
53                 }
54
55                 public void flush() {
56                         if (image != null) {
57                                 image.flush();
58                                 image = null;
59                         }
60                 }
61
62                 public boolean has_map() {
63                         return store.status() == AltosMapTile.success;
64                 }
65
66                 public synchronized void notify_store(AltosMapStore store, int status) {
67                         switch (status) {
68                         case AltosMapTile.loading:
69                                 break;
70                         case AltosMapTile.success:
71                                 load();
72                                 break;
73                         default:
74                                 tile.set_status(status);
75                                 tile.notify_image(null);
76                         }
77                 }
78
79                 public MapCacheElement(AltosMapTile tile, AltosMapStore store) throws IOException {
80                         this.tile = tile;
81                         this.image = null;
82                         this.store = store;
83                         this.used = 0;
84
85                         int status = store.status();
86                         switch (status) {
87                         case AltosMapTile.loading:
88                                 store.add_listener(this);
89                                 break;
90                         case AltosMapTile.success:
91                                 load();
92                                 break;
93                         default:
94                                 tile.set_status(status);
95                                 tile.notify_image(null);
96                                 break;
97                         }
98                 }
99         }
100
101         int                     min_cache_size;         /* configured minimum cache size */
102         int                     cache_size;             /* current cache size */
103         int                     requested_cache_size;   /* cache size computed by application */
104
105         private Object          fetch_lock = new Object();
106         private Object          cache_lock = new Object();
107
108         AltosMapInterface       map_interface;
109
110         MapCacheElement[]       elements = new MapCacheElement[cache_size];
111
112         long                    used;
113
114         public void set_cache_size(int new_size) {
115
116                 requested_cache_size = new_size;
117
118                 if (new_size < min_cache_size)
119                         new_size = min_cache_size;
120
121                 if (new_size == cache_size)
122                         return;
123
124                 synchronized(cache_lock) {
125                         MapCacheElement[]       new_elements = new MapCacheElement[new_size];
126
127                         for (int i = 0; i < cache_size; i++) {
128                                 if (i < new_size)
129                                         new_elements[i] = elements[i];
130                                 else if (elements[i] != null)
131                                         elements[i].flush();
132                         }
133                         elements = new_elements;
134                         cache_size = new_size;
135                 }
136         }
137
138         public AltosImage get(AltosMapTile tile, AltosMapStore store, int width, int height) {
139                 int             oldest = -1;
140                 long            age = used;
141
142                 synchronized(cache_lock) {
143                         MapCacheElement element = null;
144                         for (int i = 0; i < cache_size; i++) {
145                                 element = elements[i];
146
147                                 if (element == null) {
148                                         oldest = i;
149                                         break;
150                                 }
151                                 if (store.equals(element.store)) {
152                                         element.used = used++;
153                                         return element.image;
154                                 }
155                                 if (element.used < age) {
156                                         oldest = i;
157                                         age = element.used;
158                                 }
159                         }
160
161                         try {
162                                 element = new MapCacheElement(tile, store);
163                                 element.used = used++;
164                                 if (elements[oldest] != null)
165                                         elements[oldest].flush();
166
167                                 elements[oldest] = element;
168
169                                 if (element.image == null)
170                                         tile.set_status(AltosMapTile.loading);
171                                 else
172                                         tile.set_status(AltosMapTile.success);
173
174                                 return element.image;
175                         } catch (IOException e) {
176                                 tile.set_status(AltosMapTile.failed);
177                                 return null;
178                         }
179                 }
180         }
181
182         public void map_cache_changed(int map_cache) {
183                 min_cache_size = map_cache;
184
185                 set_cache_size(requested_cache_size);
186         }
187
188         public void dispose() {
189                 AltosPreferences.unregister_map_cache_listener(this);
190
191                 for (int i = 0; i < cache_size; i++) {
192                         MapCacheElement element = elements[i];
193
194                         if (element != null)
195                             element.flush();
196                 }
197         }
198
199         public AltosMapCache(AltosMapInterface map_interface) {
200                 this.map_interface = map_interface;
201                 min_cache_size = AltosPreferences.map_cache();
202
203                 set_cache_size(0);
204
205                 AltosPreferences.register_map_cache_listener(this);
206         }
207 }