    001// License: GPL. For details, see LICENSE file.
    002package org.openstreetmap.josm.plugins.streetside.mode;
    003
    004import java.awt.Cursor;
    005import java.awt.Graphics2D;
    006import java.awt.Point;
    007import java.awt.event.MouseAdapter;
    008import java.util.Calendar;
    009
    010import org.openstreetmap.josm.plugins.streetside.StreetsideAbstractImage;
    011import org.openstreetmap.josm.plugins.streetside.StreetsideLayer;
    012import org.openstreetmap.josm.plugins.streetside.io.download.StreetsideDownloader;
    013
    014import org.openstreetmap.josm.data.Bounds;
    015import org.openstreetmap.josm.gui.MainApplication;
    016import org.openstreetmap.josm.gui.MapView;
    017import org.openstreetmap.josm.gui.NavigatableComponent.ZoomChangeListener;
    018
    019/**
    020 * Superclass for all the mode of the {@link StreetsideLayer}.
    021 *
    022 * @author nokutu
    023 * @see StreetsideLayer
    024 */
    025public abstract class AbstractMode extends MouseAdapter implements
    026  ZoomChangeListener {
    027
    028  private static final int DOWNLOAD_COOLDOWN = 2000;
    029  private static SemiautomaticThread semiautomaticThread = new SemiautomaticThread();
    030
    031  /**
    032   * Cursor that should become active when this mode is activated.
    033   */
    034  public int cursor = Cursor.DEFAULT_CURSOR;
    035
    036  protected StreetsideAbstractImage getClosest(Point clickPoint) {
    037    double snapDistance = 10;
    038    double minDistance = Double.MAX_VALUE;
    039    StreetsideAbstractImage closest = null;
    040    for (StreetsideAbstractImage image : StreetsideLayer.getInstance().getData().getImages()) {
    041      Point imagePoint = MainApplication.getMap().mapView.getPoint(image.getMovingLatLon());
    042      imagePoint.setLocation(imagePoint.getX(), imagePoint.getY());
    043      double dist = clickPoint.distanceSq(imagePoint);
    044      if (minDistance > dist && clickPoint.distance(imagePoint) < snapDistance
    045        && image.isVisible()) {
    046        minDistance = dist;
    047        closest = image;
    048      }
    049    }
    050    return closest;
    051  }
    052
    053  /**
    054   * Paint the dataset using the engine set.
    055   *
    056   * @param g {@link Graphics2D} used for painting
    057   * @param mv The object that can translate GeoPoints to screen coordinates.
    058   * @param box Area where painting is going to be performed
    059   */
    060  public abstract void paint(Graphics2D g, MapView mv, Bounds box);
    061
    062  @Override
    063  public void zoomChanged() {
    064    if (StreetsideDownloader.getMode() == StreetsideDownloader.DOWNLOAD_MODE.VISIBLE_AREA) {
    065      if (!semiautomaticThread.isAlive())
    066        semiautomaticThread.start();
    067      semiautomaticThread.moved();
    068    }
    069  }
    070
    071  /**
    072   * Resets the semiautomatic mode thread.
    073   */
    074  public static void resetThread() {
    075    semiautomaticThread.interrupt();
    076    semiautomaticThread = new SemiautomaticThread();
    077  }
    078
    079  private static class SemiautomaticThread extends Thread {
    080
    081    /** If in semiautomatic mode, the last Epoch time when there was a download */
    082    private long lastDownload;
    083
    084    private boolean moved;
    085
    086    @Override
    087    public void run() {
    088      while (true) {
    089        if (this.moved && Calendar.getInstance().getTimeInMillis() - this.lastDownload >= DOWNLOAD_COOLDOWN) {
    090          this.lastDownload = Calendar.getInstance().getTimeInMillis();
    091          StreetsideDownloader.downloadVisibleArea();
    092          this.moved = false;
    093          StreetsideLayer.invalidateInstance();
    094        }
    095        try {
    096          Thread.sleep(100);
    097        } catch (InterruptedException e) {
    098          return;
    099        }
    100      }
    101    }
    102
    103    public void moved() {
    104      this.moved = true;
    105    }
    106  }
    107}