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