NAME
    Flickr::Upload::FireEagle - Flickr::Upload subclass to assign location
    information using FireEagle

SYNOPSIS
     use Getopt::Std;
     use Config::Simple;
     use Flickr::Upload::FireEagle;

     # c: path to a config file
     # p: path to a photo

     my %opts = ();
     getopts('c:p:', \%opts);
        
     my $cfg = Config::Simple->new($opts{'c'});

     my %fireeagle_args = ('consumer_key' => $cfg->param('fireeagle.consumer_key'), 
                           'consumer_secret' => $cfg->param('fireeagle.consumer_secret'), 
                           'access_token' => $cfg->param('fireeagle.access_token'), 
                           'access_token_secret' => $cfg->param('fireeagle.access_token_secret'));

     my %flickr_args = ('key' => $cfg->param('flickr.api_key'), 
                        'secret' => $cfg->param('flickr.api_secret'), 
                        'fireeagle' => \%fireeagle_args);

     my $uploadr = Flickr::Upload::FireEagle->new(\%flickr_args);

     my $photo_id = $uploadr->upload('photo' => $opts{'p'},
                                     'auth_token' => $cfg->param('flickr.auth_token'));
                                        
     print "photo : $photo_id\n";

DESCRIPTION
    Flickr::Upload subclass to assign location information using FireEagle
    and if a photo contains relevant GPS information in its EXIF headers
    update your location as well.

HOW DOES IT WORK?
    Well. It's a bit involved.

    The first thing that happens is the photo you're trying to upload is
    poked for EXIF data, specifically any GPS information and when it was
    taken (the using *DateTimeOrginal* field).

    If there is no date information, the current time is assumed.

    If there is GPS data then the date is tested to see if the photo was
    taken falls within an allowable window of time. By default, this is (1)
    hour from "right now". An alternate value may be set by passing an
    *offset_gps* argument, measured in seconds, to the *upload* method.

    If the GPS information was added recently enough then FireEagle is
    queried for your most recent location hierarchy. If the GPS information
    is more recent than the data stored in the hierarchy (the location with
    the "best guess" of being correct) then FireEagle is updated with the
    latitude and longitude recorded in the photo.

    Moving right along, whether or not we've just updated FireEagle the
    service is queried for your current location (again).

    Once the hierarchy has been retrieved, the next step is to try and
    retrieve a "context" node. Whereas when testing GPS information the
    "best guess" node is assumed this is not necessarily the case when
    trying to use FireEagle to add tags.

    The context node is determined by comparing the photo's date against the
    *located-at* (or date recorded) attribute for specific items in the
    FireEagle hierarchy. Since most cameras still don't record GPS
    information it is necessary to do some work to gues^H^H^H I mean infer
    how "close" you are to the last recorded location.

    For example, if it's been more than a couple of hours since you last
    updated FireEagle you might still be in the same neighbourhood but if
    it's been more than half a day chances are good that you're been on the
    move but are still in the same city.

    (It goes without saying that there are lots of edge cases some of which
    will try to be addressed in the as-yet unwritten
    Flickr::Upload::FireDopplr.)

    The following tests are applied :

    * First a "best guess" location is queried
        If it is present and its *located-at* date is less than or equal to
        an hour, it is the context node.

        An alternate value may be set by passing a *offset_fireeagle_exact*
        argument, measured in seconds, to the *upload* method.

    * Next a location of type "neighborhood" is queried
        If it is present and its *located-at* date is less than or equal to
        two hours, it is the context node.

        An alternate value may be set by passing a
        *offset_fireeagle_neighbourhood* (or neighborhood) argument,
        measured in seconds, to the *upload* method.

    * Next a location of type "locality" is queried
        If it is present and its *located-at* date is less than or equal to
        twelve hours, it is the context node.

        An alternate value may be set by passing a
        *offset_fireeagle_locality* argument, measured in seconds, to the
        *upload* method.

    * If none of those tests pass then...
        ...there is no context node.

    Assuming that a context node has been identified *and* there is GPS
    information stored in the photo, the *flickr.places.findByLatLon* method
    is called (passing the photo's latitude and longitude) to ensure that
    the (Flickr) places IDs for both the response and the context node
    match.

    If they *don't* match then the context node is destroyed and the
    following tags are added : places:PLACETYPE=PLACEID; woe:id=WOEID; the
    name of the location (formatted according to the object's "tagify"
    rules).

    On the other hand, if the context node is still around, after all that,
    then it is used to add tags.

    At a minimum a fireeagle:id=CONTEXTNODEID tag is added. If the place
    type for the context node is equal to or more precise than a
    neighbourhood, the neighbourhood's name is added as a tag. If the place
    type for the context node is equal to or more precise than a locality,
    the locality's name is added as a tag as well as fireeagle:id=ID,
    places:locality=PLACEID and woe:id=WOEID tags.

    We're almost done : Assuming a context node and no GPS information in
    the photo, the nodes latitude and longitude are calculated to use as
    arguments when calling the *flickr.photos.geo.setLocation* method.

    The coordinates are "calculated" because not every location in the
    FireEagle hierarchy has a centroid. If no centroid is present then the
    node's bounding box is used and the centroid is assumed to be the center
    of the box. The photo's "accuracy" (in Flickr terms) is determined
    according to the node's place type.

    Finally, the photo is uploaded (and geotagged if necessary).

    No really.

ERROR HANDLING
    Flickr::Upload::FireEagle subclasses Error.pm to catch and throw
    exceptions. Although this is still a mostly un-Perl-ish way of doing
    things, it seemed like the most sensible way to handle the variety of
    error cases. I don't love it but we'll see.

    This means that the library will throw fatal exceptions and you will
    need to code around it using either *eval* or - even better - *try* and
    *catch* blocks.

    There are four package specific exception handlers :

    * FUFEException
        An error condition specific to *Flickr::Upload::FireEagle* was
        triggered.

    * FlickrUploadException
        An error condition specific to *Flickr::Upload* was triggered.

    * FlickrAPIException
        An error condition specific to calling the Flickr API (read :
        *Flickr::API*) was triggered.

        This is the only exception handler that defines its own additional
        methods. They are :

        * error_code
            The numeric error code returned by the Flickr API.

        * error_message
            The textual error message returned by the Flickr API.

    * NetFireEagleException
        An error condition specific to *Net::FireEagle* was triggered.

CAVEATS
    *   Asynchronous uploads are not support and will trigger an exception.

PACKAGE METHODS
  __PACKAGE__->new(\%args)
    All the same arguments required by the *Flickr::Upload* constructor plus
    the following :

    * fireeagle
        A hash reference containing the following keys :

        * consumer_key
            String. *required*

            A valid FireEagle consumer key.

        * consumer_secret
            String. *required*

            A valid FireEagle consumer secret.

        * access_token
            String. *required*

            A valid FireEagle access token.

        * access_token_secret
            String. *required*

            A valid FireEagle access token secret.

        * tagify
            String.

            An optional flag to format tags for cities, specific to a
            service. Valid services are :

            * delicious
                City names are lower-cased and spaces are removed.

            * flickr
                City names are wrapped in double-quotes if they contain
                spaces.

            The default value is *flickr*

    Returns a *Flickr::Upload::FireEagle* object.

OBJECT METHODS YOU SHOULD CARE ABOUT
  $obj->upload(%args)
    Valid arguments are anything you would pass the Flickr::Upload *upload*
    method except the *async* flag which is not honoured yet. I'm working on
    it.

    In additional, you may pass the following optional parameters :

    * geo
        This must be a hash reference with the following keys :

        * perms
            Hash reference.

            A hash reference containing is_public, is_contact, is_family and
            is_friend keys and their boolean values to set the geo
            permissions on your uploaded photo.

            If this is not defined then your default viewing settings for
            geo data will be left in place.

    * offset_gps
        Int.

        The maximum amount of time (in seconds) between the time of your
        last FireEagle update and the date on which the photo was taken in
        which a photo can be considered reliable for updating your location
        in FireEagle.

        The default is 3600 (seconds, or 1 hour).

    * offset_fireeagle_exact
        The maximum amount of time (in seconds) between the time of your
        last FireEagle update and the date on which the photo was taken in
        which FireEagle can be considered reliable for updating your
        location in FireEagle at street level.

        The default is 3600 (seconds, or 1 hour).

    * offset_fireeagle_neighbourhood (or offset_fireeagle_neighborhood)
        The maximum amount of time (in seconds) between the time of your
        last FireEagle update and the date on which the photo was taken in
        which FireEagle can be considered reliable for updating your
        location in FireEagle at the neighbourhood level.

        The default is 7200 (seconds, or 2 hours).

    * offset_fireeagle_locality
        The maximum amount of time (in seconds) between the time of your
        last FireEagle update and the date on which the photo was taken in
        which FireEagle can be considered reliable for updating your
        location in FireEagle at the locality (city) level.

        The default is 43200 (seconds, or 12 hours).

    Returns a photo ID!

VERSION
    0.1

DATE
    $Date: 2008/04/22 07:01:19 $

AUTHOR
    Aaron Straup Cope <ascope@cpan.org>

NOTES
    Aside from requiring your own Flickr API key, secret and authentication
    token you will also need similar FireEagle (OAuth) credentials. Since
    Flickr::Upload::FireEagle already requires that you install the
    excellent *Net::FireEagle* you should just use the command line
    *fireeagle* client for authorizing yourself with FireEagle.

SEE ALSO
    Net::FireEagle

    Flickr::Upload

    Flickr::Upload::Dopplr

    Flickr::API

    Error

    <http://www.fireeagle.com/>

    <http://fireeagle.yahoo.net/developer>

    <http://laughingmeme.org/2008/01/18/flickr-place-ids/>

    <http://oauth.net/>

BUGS
    Sure, why not.

    Please report all bugs via http://rt.cpan.org/

LICENSE
    Copyright (c) 2007-2008 Aaron Straup Cope. All Rights Reserved.

    This is free software. You may redistribute it and/or modify it under
    the same terms as Perl itself.

