001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.plugins.streetside.cubemap; 003 004import java.awt.image.BufferedImage; 005import java.io.IOException; 006import java.text.MessageFormat; 007import java.util.ArrayList; 008import java.util.List; 009import java.util.Objects; 010import java.util.concurrent.Callable; 011import java.util.concurrent.CopyOnWriteArrayList; 012 013import javax.imageio.ImageIO; 014 015import org.apache.log4j.Logger; 016import org.openstreetmap.josm.plugins.streetside.cache.StreetsideCache; 017import org.openstreetmap.josm.plugins.streetside.utils.StreetsideProperties; 018import org.openstreetmap.josm.plugins.streetside.utils.StreetsideURL; 019 020import us.monoid.web.Resty; 021 022public class TileDownloadingTask implements Callable<List<String>> { 023 024 final static Logger logger = Logger.getLogger(TileDownloadingTask.class); 025 026 private String tileId; 027 private StreetsideCache cache; 028 protected CubemapBuilder cb; 029 030 /** 031 * Listeners of the class. 032 */ 033 private final List<ITileDownloadingTaskListener> listeners = new CopyOnWriteArrayList<>(); 034 035 boolean cancelled = false; 036 037 public TileDownloadingTask(String id) { 038 tileId = id; 039 cb = CubemapBuilder.getInstance(); 040 addListener(CubemapBuilder.getInstance()); 041 } 042 043 /** 044 * Adds a new listener. 045 * 046 * @param lis Listener to be added. 047 */ 048 public final void addListener(final ITileDownloadingTaskListener lis) { 049 listeners.add(lis); 050 } 051 052 /** 053 * @return the tileId 054 */ 055 public String getId() { 056 return tileId; 057 } 058 059 /** 060 * @param id the tileId to set 061 */ 062 public void setId(String id) { 063 tileId = id; 064 } 065 066 /** 067 * @return the cache 068 */ 069 public StreetsideCache getCache() { 070 return cache; 071 } 072 073 /** 074 * @param cache the cache to set 075 */ 076 public void setCache(StreetsideCache cache) { 077 this.cache = cache; 078 } 079 080 /** 081 * @return the cb 082 */ 083 public CubemapBuilder getCb() { 084 return cb; 085 } 086 087 /** 088 * @param cb the cb to set 089 */ 090 public void setCb(CubemapBuilder cb) { 091 this.cb = cb; 092 } 093 094 /** 095 * @param cancelled the cancelled to set 096 */ 097 public void setCancelled(boolean cancelled) { 098 this.cancelled = cancelled; 099 } 100 101 @Override 102 public List<String> call() throws Exception { 103 104 List<String> res = new ArrayList<>(); 105 106 if (StreetsideProperties.DOWNLOAD_CUBEFACE_TILES_TOGETHER.get()) { 107 // download all imagery for each cubeface at once 108 if (!StreetsideProperties.SHOW_HIGH_RES_STREETSIDE_IMAGERY.get()) { 109 // download low-res imagery 110 int tileNr = 0; 111 for (int j = 0; j < CubemapUtils.getMaxCols(); j++) { 112 for (int k = 0; k < CubemapUtils.getMaxRows(); k++) { 113 String quadKey = String.valueOf(tileId + Integer.valueOf(tileNr++).toString()); 114 res.add(downloadTile(quadKey)); 115 } 116 } 117 // download high-res imagery 118 } else { 119 for (int j = 0; j < CubemapUtils.getMaxCols(); j++) { 120 for (int k = 0; k < CubemapUtils.getMaxRows(); k++) { 121 String quadKey = String 122 .valueOf(tileId + String.valueOf(Integer.valueOf(j).toString() + Integer.valueOf(k).toString())); 123 res.add(downloadTile(quadKey)); 124 } 125 } 126 } 127 // task downloads just one tile 128 } else { 129 res.add(downloadTile(tileId)); 130 } 131 return res; 132 } 133 134 private String downloadTile(String tileId) { 135 BufferedImage img; 136 137 long startTime = System.currentTimeMillis(); 138 139 try { 140 img = ImageIO 141 .read(new Resty().bytes(StreetsideURL.VirtualEarth.streetsideTile(tileId, false).toExternalForm()).stream()); 142 143 if (img == null) { 144 logger.error("Download of BufferedImage " + tileId + " is null!"); 145 } 146 147 CubemapBuilder.getInstance().getTileImages().put(tileId, img); 148 149 fireTileAdded(tileId); 150 151 if (StreetsideProperties.DEBUGING_ENABLED.get()) { 152 long endTime = System.currentTimeMillis(); 153 long runTime = (endTime - startTime) / 1000; 154 logger.debug(MessageFormat.format("Loaded image for {0} in {1} seconds.", tileId, runTime)); 155 } 156 } catch (IOException e) { 157 logger.error(MessageFormat.format("Error downloading image for tileId {0}", tileId)); 158 return null; 159 } 160 return tileId; 161 } 162 163 private void fireTileAdded(String id) { 164 listeners.stream().filter(Objects::nonNull).forEach(lis -> lis.tileAdded(id)); 165 } 166}