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}