001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.plugins.streetside;
003
004import java.awt.image.BufferedImage;
005import java.io.File;
006import java.io.IOException;
007import java.text.ParseException;
008import java.util.Calendar;
009
010import javax.imageio.ImageIO;
011
012import org.openstreetmap.josm.data.coor.CachedLatLon;
013import org.openstreetmap.josm.data.coor.LatLon;
014import org.openstreetmap.josm.gui.MapView;
015import org.openstreetmap.josm.gui.layer.geoimage.GeoImageLayer;
016import org.openstreetmap.josm.gui.layer.geoimage.ImageEntry;
017import org.openstreetmap.josm.plugins.streetside.utils.StreetsideUtils;
018
019import org.openstreetmap.josm.plugins.streetside.cubemap.CubemapUtils;
020
021/**
022 * A StreetsideImoprtedImage object represents a picture imported locally.
023 *
024 * @author nokutu
025 *
026 */
027public class StreetsideImportedImage extends StreetsideAbstractImage {
028
029  /** The picture file. */
030  protected File file;
031
032  /**
033   * Creates a new StreetsideImportedImage object using as date the current date.
034   * Using when the EXIF tags doesn't contain that info.
035   *
036   * @param id  The Streetside image id
037   * @param latLon  The latitude and longitude where the picture was taken.
038   * @param ca  Direction of the picture (0 means north).
039   * @param file  The file containing the picture.
040   */
041  public StreetsideImportedImage(final String id, final LatLon latLon, final double ca, final File file) {
042    this(id, latLon, ca, file, Calendar.getInstance().getTimeInMillis());
043  }
044
045  /**
046   * Main constructor of the class.
047   *
048   * @param id  The Streetside image id
049   * @param latLon  Latitude and Longitude where the picture was taken.
050   * @param ca  Direction of the picture (0 means north),
051   * @param file  The file containing the picture.
052   * @param datetimeOriginal  The date the picture was taken.
053   */
054  public StreetsideImportedImage(final String id, final LatLon latLon, final double ca, final File file, final String datetimeOriginal) {
055    this(id, latLon, ca, file, parseTimestampElseCurrentTime(datetimeOriginal));
056  }
057
058  /**
059   * Constructs a new image from an image entry of a {@link GeoImageLayer}.
060   * @param geoImage the {@link ImageEntry}, from which the corresponding fields are taken
061   * @return new image
062   */
063  public static StreetsideImportedImage createInstance(final ImageEntry geoImage) {
064    if (geoImage == null) {
065      return null;
066    }
067    if (geoImage.getFile() == null) {
068      throw new IllegalArgumentException("Can't create an imported image from an ImageEntry without associated file.");
069    }
070    final CachedLatLon cachedCoord = geoImage.getPos();
071    LatLon coord = cachedCoord == null ? null : cachedCoord.getRoundedToOsmPrecision();
072    if (coord == null) {
073      final MapView mv = StreetsidePlugin.getMapView();
074      coord = mv == null ? new LatLon(0, 0) : mv.getProjection().eastNorth2latlon(mv.getCenter());
075    }
076    final double ca = geoImage.getExifImgDir() == null ? 0 : geoImage.getExifImgDir();
077    final long time = geoImage.hasGpsTime()
078      ? geoImage.getGpsTime().getTime()
079      : geoImage.hasExifTime() ? geoImage.getExifTime().getTime() : System.currentTimeMillis();
080    return new StreetsideImportedImage(CubemapUtils.IMPORTED_ID, coord, ca, geoImage.getFile(), time);
081  }
082
083  private static long parseTimestampElseCurrentTime(final String timestamp) {
084    try {
085      return StreetsideUtils.getEpoch(timestamp, "yyyy:MM:dd HH:mm:ss");
086    } catch (ParseException e) {
087      try {
088        return StreetsideUtils.getEpoch(timestamp, "yyyy/MM/dd HH:mm:ss");
089      } catch (ParseException e1) {
090        return StreetsideUtils.currentTime();
091      }
092    }
093  }
094
095  public StreetsideImportedImage(final String id, final LatLon latLon, final double he, final File file, final long ca) {
096    super(id, latLon, he);
097    this.file = file;
098    this.cd = ca;
099  }
100
101  /**
102   * Returns the pictures of the file.
103   *
104   * @return A {@link BufferedImage} object containing the picture, or null if
105   *         the {@link File} given in the constructor was null.
106   * @throws IOException
107   *           If the file parameter of the object isn't an image.
108   */
109  public BufferedImage getImage() throws IOException {
110    if (file != null)
111      return ImageIO.read(file);
112    return null;
113  }
114
115  /**
116   * Returns the {@link File} object where the picture is located.
117   *
118   * @return The {@link File} object where the picture is located.
119   */
120  public File getFile() {
121    return file;
122  }
123
124  @Override
125  public int compareTo(StreetsideAbstractImage image) {
126    if (image instanceof StreetsideImportedImage)
127      return file.compareTo(((StreetsideImportedImage) image).getFile());
128    return hashCode() - image.hashCode();
129  }
130
131  @Override
132  public int hashCode() {
133    final int prime = 31;
134    int result = 1;
135    result = prime * result + ((file == null) ? 0 : file.hashCode());
136    return result;
137  }
138
139  @Override
140  public boolean equals(Object obj) {
141    if (this == obj) {
142      return true;
143    }
144    if (obj == null) {
145      return false;
146    }
147    if (!(obj instanceof StreetsideImportedImage)) {
148      return false;
149    }
150    StreetsideImportedImage other = (StreetsideImportedImage) obj;
151    if (file == null) {
152      if (other.file != null) {
153        return false;
154      }
155    } else if (!file.equals(other.file)) {
156      return false;
157    }
158    return true;
159  }
160}