#!/usr/bin/python
#
# Given one tracklog and one or more JPEG files, correlate the
# timestamps between tracklog and EXIF data and write the
# corresponding GPS data in the JPEG files.
#
# Seth Golub  http://www.aigeek.com/geo/
#
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# I don't bother to provide a copy of the GNU General Public License
# along with this program, but you can get one from the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA


import sys
from time import strftime,gmtime,mktime
from optparse import OptionParser
from image import Image
from tracklog import TrackLog
from geoexif import GeoExif

def geocode_jpeg(track, jpeg, tzoffset_secs, datum, limit):
  if type(jpeg) is str:
    jpegfile = jpeg
    image = Image(jpegfile)
  elif isinstance(jpeg, Image):
    image = jpeg
    jpegfile = image.filename
  else:
    raise TypeError('jpeg argument to geocode_jpeg must be an Image or a string (the filename)')

  point = track.find_nearest_in_time(image.image_time() - tzoffset_secs)
  did_something = 0
  data = GeoExif()
  data.set('datum', datum)
  data.set('latitude', point.lat)
  data.set('longitude', point.lon)
  data.set('timestamp', strftime('%H%M%S', gmtime(point.time)))
  if point.__dict__.has_key('elevation'):
    data.set('altitude', point.elevation)
  if limit < 0 or abs((image.image_time() - tzoffset_secs) - point.time) <= limit:
    did_something = 1
    data.apply_to_file(jpegfile)
  return (data, point, did_something)


def main():
  usage = "usage: %prog [opts] track.gpx file1.jpg [more jpegs]"
  optparser = OptionParser(usage)
  optparser.add_option('-e', '--exivbin', type='string', help='location of exiv2 binary', default='exiv2')
  optparser.add_option('-v', '--verbose', action='store_true', default=False)
  optparser.add_option('-l', '--limit', type='int', default=-1, help='Limit in seconds of absolute time difference between trackpoint and image. Images lacking a trackpoint within this limit will not be geocoded. The default is a negative number, which means no limit.')
  optparser.add_option('-d', '--datum', type='string', default='WGS-84')
  optparser.add_option('-t', '--tzoffset', type='float', default=0.0,
                       help='jpegs\' hours off UTC (e.g. -8 for PST)')
  (options, args) = optparser.parse_args()
  GeoExif.exivbin = options.exivbin

  tzoffset_secs = options.tzoffset * 60 * 60
  sys.stderr.write('Reading track log\n')
  track = TrackLog(args[0])
  sys.stderr.write('Processing photos\n')
  import time
  for jpegfile in args[1:]:
    jpeg = Image(jpegfile)
    (data, trackpoint, did_something) = geocode_jpeg(track, jpeg, tzoffset_secs, options.datum, options.limit)
    if options.verbose:
      print '%(file)s\t%(result)s\t%(lat)s,%(lon)s\t%(imgtime)s (TZ=%(tz)s)\t%(pointtime)s\t%(timediff)d' % {
        'file' : jpegfile,
        'imgtime' : time.asctime(time.localtime(jpeg.image_time())),
        'pointtime' : trackpoint.time_str,
        'lat' : str(data.get('latitude')),
        'lon' : str(data.get('longitude')),
        'result' : (did_something and 'yes' or 'no'),
        'timediff' : abs((jpeg.image_time() - tzoffset_secs) - trackpoint.time),
        'tz' : str(options.tzoffset),
      }

if __name__ == '__main__':
  main()
