edu.wpi.khufnagle.webimagemanager.WebImageManager.java Source code

Java tutorial

Introduction

Here is the source code for edu.wpi.khufnagle.webimagemanager.WebImageManager.java

Source

package edu.wpi.khufnagle.webimagemanager;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.io.FileUtils;

/**
 * @author Kevin Hufnagle
 * @date January 22, 2014
 * @description Collects and stores geotagged photographs of lighthouses across
 *              New England. Each of these photographs falls under a Creative
 *              Commons license that allows someone other than the photographer
 *              to modify the image.
 */
// Version history:
//
// 1/22/14 - Initial release
public class WebImageManager {
    /**
     * Defines information for the lighthouses, then runs the
     * photograph-collection process.
     * @param args Command-line arguments for this program (not used in this
     *        implementation)
     */
    // Auto-boxing done "on the fly" to show progress of downloading images
    @SuppressWarnings("boxing")
    public static void main(final String[] args) {
        final long startTime = System.nanoTime();
        System.out.println("***BEGIN PHOTO TRANSFER PROCESS***");

        // Add data for lighthouses (next 375 lines or so)
        final List<LighthouseInfo> lighthouseData = new ArrayList<LighthouseInfo>();
        /*
         * lighthouseData.add(new LighthouseInfo("Statue of Liberty", 40.689348,
         * -74.044726));
         */// Statue of Liberty = 2080 photos w/out restrictions
        lighthouseData.add(new LighthouseInfo("Portland Head Light", 43.623104, -70.207867));
        lighthouseData.add(new LighthouseInfo("Pemaquid Point Light", 43.836970, -69.505997));
        lighthouseData.add(new LighthouseInfo("Five Mile Point (New Haven Harbor) Light", 41.248958, -72.903766));
        lighthouseData.add(new LighthouseInfo("Cape Neddick (Nubble) Light", 43.165211, -70.591102));
        lighthouseData.add(new LighthouseInfo("Portland Breakwater Light", 43.655516, -70.234813));
        lighthouseData.add(new LighthouseInfo("Beavertail Light", 41.449368, -71.399372));
        lighthouseData.add(new LighthouseInfo("Bass Harbor Head Light", 44.221976, -68.337214));
        lighthouseData.add(new LighthouseInfo("Nobska Point Light", 41.515792, -70.655116));
        lighthouseData.add(new LighthouseInfo("Spring Point Ledge Light", 43.652108, -70.223922));
        lighthouseData.add(new LighthouseInfo("Gay Head Light", 41.348450, -70.834956));
        lighthouseData.add(new LighthouseInfo("Derby Wharf Light", 42.516566, -70.883536));
        lighthouseData.add(new LighthouseInfo("Rockland Breakwater Light", 44.104006, -69.077453));
        lighthouseData.add(new LighthouseInfo("Sandy Neck Light", 41.722647, -70.280927));
        lighthouseData.add(new LighthouseInfo("Marblehead Light", 42.505411, -70.833708));
        lighthouseData.add(new LighthouseInfo("Portsmouth Harbor Light", 43.071061, -70.708634));
        lighthouseData.add(new LighthouseInfo("Highland Light", 42.039122, -70.062025));
        lighthouseData.add(new LighthouseInfo("Cape Elizabeth Light", 43.566058, -70.200042));
        lighthouseData.add(new LighthouseInfo("Marshall Point Light", 43.917406, -69.261222));
        lighthouseData.add(new LighthouseInfo("Chatham Light", 41.671407, -69.949884));
        lighthouseData.add(new LighthouseInfo("Block Island Southeast Light", 41.153412, -71.552117));
        lighthouseData.add(new LighthouseInfo("Edgartown Light", 41.390863, -70.503057));
        lighthouseData.add(new LighthouseInfo("Watch Hill Light", 41.303884, -71.858575));
        lighthouseData.add(new LighthouseInfo("Nauset Light", 41.858305, -69.951631));
        lighthouseData
                .add(new LighthouseInfo("Fayerweather Island (Black Rock Harbor) Light", 41.142380, -73.217409));
        lighthouseData.add(new LighthouseInfo("Owls Head Light", 44.092138, -69.044105));
        lighthouseData.add(new LighthouseInfo("Point Judith Light", 41.361035, -71.481402));
        lighthouseData.add(new LighthouseInfo("Sankaty Head Light", 41.284379, -69.966244));
        lighthouseData.add(new LighthouseInfo("Eastern Point Light", 42.580229, -70.664537));
        lighthouseData.add(new LighthouseInfo("Fort Pickering Light", 42.526473, -70.866465));
        lighthouseData.add(new LighthouseInfo("Wood Island Light", 43.456788, -70.328976));
        lighthouseData.add(new LighthouseInfo("Stonington Harbor Light", 41.328780, -71.905486));
        lighthouseData.add(new LighthouseInfo("West Quoddy Head Light", 44.815073, -66.950742));
        lighthouseData.add(new LighthouseInfo("Fort Point Light", 44.467265, -68.811717));
        lighthouseData.add(new LighthouseInfo("Annisquam Light", 42.661874, -70.681488));
        lighthouseData.add(new LighthouseInfo("Newport Harbor Light", 41.493299, -71.327038));
        lighthouseData.add(new LighthouseInfo("Long Point Light", 42.033117, -70.168651));
        lighthouseData.add(new LighthouseInfo("Castle Hill Light", 41.462116, -71.362919));
        lighthouseData.add(new LighthouseInfo("Brant Point Light", 41.289918, -70.090287));
        lighthouseData.add(new LighthouseInfo("Stratford Point Light", 41.151984, -73.103276));
        lighthouseData.add(new LighthouseInfo("Boston Light", 42.327925, -70.890101));
        lighthouseData.add(new LighthouseInfo("Lynde Point Light", 41.271452, -72.343142));
        lighthouseData.add(new LighthouseInfo("Scituate Light", 42.204748, -70.715814));
        lighthouseData.add(new LighthouseInfo("Prospect Harbor Light", 44.403285, -68.012922));
        lighthouseData.add(new LighthouseInfo("Wood End Light", 42.021223, -70.193502));
        lighthouseData.add(new LighthouseInfo("Rose Island Light", 41.495477, -71.342742));
        lighthouseData.add(new LighthouseInfo("Saybrook Breakwater Light", 41.263158, -72.342813));
        lighthouseData.add(new LighthouseInfo("Great Point Light", 41.390096, -70.048234));
        lighthouseData.add(new LighthouseInfo("Cape Poge Light", 41.418798, -70.451923));
        lighthouseData.add(new LighthouseInfo("Monhegan Light", 43.764779, -69.316204));
        lighthouseData.add(new LighthouseInfo("Hendricks Head Light", 43.822589, -69.689761));
        lighthouseData.add(new LighthouseInfo("Egg Rock Light", 44.354050, -68.138166));
        lighthouseData.add(new LighthouseInfo("New London Ledge Light", 41.305826, -72.077448));
        lighthouseData.add(new LighthouseInfo("Avery Point Lighthouse", 41.315245, -72.063579));
        lighthouseData.add(new LighthouseInfo("Palmers Island Light", 41.626936, -70.909109));
        lighthouseData.add(new LighthouseInfo("Cuckolds Light", 43.779663, -69.649982));
        lighthouseData.add(new LighthouseInfo("Gull Rocks Light", 41.502451, -71.333140));
        lighthouseData.add(new LighthouseInfo("Goat Island Light", 43.357826, -70.425109));
        lighthouseData.add(new LighthouseInfo("East Chop Light", 41.470245, -70.567439));
        lighthouseData.add(new LighthouseInfo("Neds Point Light", 41.650859, -70.795638));
        lighthouseData.add(new LighthouseInfo("Sakonnet Point Light", 41.453090, -71.202382));
        lighthouseData.add(new LighthouseInfo("Narrows (Bug) Light", 42.323137, -70.919158));
        lighthouseData.add(new LighthouseInfo("Plum Island Light", 42.815119, -70.818981));
        lighthouseData.add(new LighthouseInfo("Block Island North Light", 41.227639, -71.575811));
        lighthouseData.add(new LighthouseInfo("Mount Desert Rock Light", 43.968582, -68.128306));
        lighthouseData.add(new LighthouseInfo("Duxbury Pier Light", 41.987375, -70.648498));
        lighthouseData.add(new LighthouseInfo("Long Island Head Light", 42.330197, -70.957712));
        lighthouseData.add(new LighthouseInfo("Prudence Island Light", 41.605881, -71.303535));
        lighthouseData.add(new LighthouseInfo("Plum Beach Light", 41.530248, -71.405202));
        lighthouseData.add(new LighthouseInfo("Doubling Point Light", 43.882503, -69.806792));
        lighthouseData.add(new LighthouseInfo("Dice Head Light", 44.382732, -68.819022));
        lighthouseData.add(new LighthouseInfo("Ram Island Ledge Light", 43.631457, -70.187366));
        lighthouseData.add(new LighthouseInfo("New London Harbor Light", 41.316619, -72.089743));
        lighthouseData.add(new LighthouseInfo("Lime Rock Light", 41.477536, -71.325924));
        lighthouseData.add(new LighthouseInfo("Ten Pound Island Light", 42.601865, -70.665556));
        lighthouseData.add(new LighthouseInfo("Bristol Ferry Light", 41.642842, -71.260319));
        lighthouseData.add(new LighthouseInfo("Musselbed Shoals Light", 41.636261, -71.259958));
        lighthouseData.add(new LighthouseInfo("Conimicut Light", 41.716969, -71.345106));
        lighthouseData.add(new LighthouseInfo("Tongue Point Light", 41.166590, -73.177497));
        lighthouseData.add(new LighthouseInfo("Bass River Light", 41.651746, -70.169473));
        lighthouseData.add(new LighthouseInfo("Hospital Point Light", 42.546413, -70.856164));
        lighthouseData.add(new LighthouseInfo("Newburyport Range Light", 42.811524, -70.864838));
        lighthouseData.add(new LighthouseInfo("Dutch Island Light", 41.496702, -71.404299));
        lighthouseData.add(new LighthouseInfo("Heron Neck Light", 44.025216, -68.861966));
        lighthouseData.add(new LighthouseInfo("Pumpkin Island Light", 44.309166, -68.742876));
        lighthouseData.add(new LighthouseInfo("Whaleback Light", 43.058744, -70.696306));
        lighthouseData.add(new LighthouseInfo("Hyannis Harbor Light", 41.636267, -70.288439));
        lighthouseData.add(new LighthouseInfo("Stage Harbor Light", 41.658692, -69.983689));
        lighthouseData.add(new LighthouseInfo("Lovells Island Range Light", 42.332440, -70.930214));
        lighthouseData.add(new LighthouseInfo("Hog Island Shoal Light", 41.632338, -71.273198));
        lighthouseData.add(new LighthouseInfo("Ram Island Light", 43.803935, -69.599349));
        lighthouseData.add(new LighthouseInfo("Bridgeport Harbor Light", 41.156718, -73.179950));
        lighthouseData.add(new LighthouseInfo("Straitsmouth Island Light", 42.662236, -70.588157));
        lighthouseData.add(new LighthouseInfo("Squirrel Point Light", 43.816520, -69.802402));
        lighthouseData.add(new LighthouseInfo("Mayos Beach Light", 41.930755, -70.032097));
        lighthouseData.add(new LighthouseInfo("Race Point Light", 42.062314, -70.243084));
        lighthouseData.add(new LighthouseInfo("Point Gammon Light", 41.609647, -70.266196));
        lighthouseData.add(new LighthouseInfo("Wings Neck Light", 41.680235, -70.661250));
        lighthouseData.add(new LighthouseInfo("West Chop Light", 41.480806, -70.599796));
        lighthouseData.add(new LighthouseInfo("Bird Island Light", 41.669295, -70.717341));
        lighthouseData.add(new LighthouseInfo("Clarks Point Light", 41.593176, -70.901416));
        lighthouseData.add(new LighthouseInfo("Thacher Island Light", 42.639168, -70.574759));
        lighthouseData.add(new LighthouseInfo("White Island Light", 42.967228, -70.623249));
        lighthouseData.add(new LighthouseInfo("Wickford Harbor Light", 41.572618, -71.436831));
        lighthouseData.add(new LighthouseInfo("Whale Rock Light", 41.444597, -71.423584));
        lighthouseData.add(new LighthouseInfo("Burnt Island Light", 43.825133, -69.640262));
        lighthouseData.add(new LighthouseInfo("Rockland Harbor Southwest Light", 44.082720, -69.096310));
        lighthouseData.add(new LighthouseInfo("Saddleback Ledge Light", 44.014232, -68.726461));
        lighthouseData.add(new LighthouseInfo("Grindle Point Light", 44.281451, -68.942967));
        lighthouseData.add(new LighthouseInfo("Winter Harbor Light", 44.361421, -68.087742));
        lighthouseData.add(new LighthouseInfo("Peck's Ledge Light", 41.077298, -73.369811));
        lighthouseData.add(new LighthouseInfo("Sheffield Island Light", 41.048251, -73.419931));
        lighthouseData.add(new LighthouseInfo("Whitlocks Mill Light", 45.162793, -67.227395));
        lighthouseData.add(new LighthouseInfo("Boon Island Light", 43.121183, -70.475845));
        lighthouseData.add(new LighthouseInfo("Southwest Ledge Light", 41.234443, -72.912092));
        lighthouseData.add(new LighthouseInfo("Broad Sound Channel Inner Range Light", 42.326933, -70.984649));
        lighthouseData.add(new LighthouseInfo("Spectacle Island Light", 42.326898, -70.984772));
        lighthouseData.add(new LighthouseInfo("Deer Island Light", 42.339836, -70.954525));
        lighthouseData.add(new LighthouseInfo("Nayatt Point Light", 41.725120, -71.338926));
        lighthouseData.add(new LighthouseInfo("Doubling Point Range Lights", 43.882860, -69.795652));
        lighthouseData.add(new LighthouseInfo("Burkehaven Light", 43.371669, -72.065869));
        lighthouseData.add(new LighthouseInfo("Loon Island Light", 43.392123, -72.059977));
        lighthouseData.add(new LighthouseInfo("Curtis Island Light", 44.201372, -69.048865));
        lighthouseData.add(new LighthouseInfo("Butler Flats Light", 41.603775, -70.894556));
        lighthouseData.add(new LighthouseInfo("Graves Light", 42.365098, -70.869191));
        lighthouseData.add(new LighthouseInfo("Stamford Harbor Light", 41.013643, -73.542577));
        lighthouseData.add(new LighthouseInfo("Billingsgate Light", 41.871624, -70.068982));
        lighthouseData.add(new LighthouseInfo("Monomoy Point Light", 41.559310, -69.993650));
        lighthouseData.add(new LighthouseInfo("Bishop & Clerks Light", 41.574154, -70.249963));
        lighthouseData.add(new LighthouseInfo("Plymouth Light", 42.003737, -70.600565));
        lighthouseData.add(new LighthouseInfo("Cleveland Ledge Light", 41.630927, -70.694201));
        lighthouseData.add(new LighthouseInfo("Tarpaulin Cove Light", 41.468822, -70.757514));
        lighthouseData.add(new LighthouseInfo("Minots Ledge Light", 42.269678, -70.759136));
        lighthouseData.add(new LighthouseInfo("Dumpling Rock Light", 41.538167, -70.921427));
        lighthouseData.add(new LighthouseInfo("Bakers Island Light", 42.536470, -70.785995));
        lighthouseData.add(new LighthouseInfo("Cuttyhunk Light", 41.414391, -70.949558));
        lighthouseData.add(new LighthouseInfo("Egg Rock Light", 42.433346, -70.897386));
        lighthouseData.add(new LighthouseInfo("Ipswich Range Light", 42.685360, -70.766128));
        lighthouseData.add(new LighthouseInfo("Borden Flats Light", 41.704450, -71.174395));
        lighthouseData.add(new LighthouseInfo("Bullocks Point Light", 41.737740, -71.364179));
        lighthouseData.add(new LighthouseInfo("Pomham Rocks Light", 41.777618, -71.369594));
        lighthouseData.add(new LighthouseInfo("Sabin Point Light", 41.762010, -71.374234));
        lighthouseData.add(new LighthouseInfo("Fuller Rock Light", 41.794055, -71.379720));
        lighthouseData.add(new LighthouseInfo("Gould Island Light", 41.537826, -71.344804));
        lighthouseData.add(new LighthouseInfo("Warwick Light", 41.667111, -71.378413));
        lighthouseData.add(new LighthouseInfo("Sassafras Point Light", 41.802496, -71.390272));
        lighthouseData.add(new LighthouseInfo("Conanicut Light", 41.573484, -71.371767));
        lighthouseData.add(new LighthouseInfo("Poplar Point Light", 41.571053, -71.439189));
        lighthouseData.add(new LighthouseInfo("Halfway Rock Light", 43.655873, -70.037402));
        lighthouseData.add(new LighthouseInfo("Seguin Island Light", 43.707554, -69.758118));
        lighthouseData.add(new LighthouseInfo("Pond Island Light", 43.740031, -69.770273));
        lighthouseData.add(new LighthouseInfo("Perkins Island Light", 43.786764, -69.785256));
        lighthouseData.add(new LighthouseInfo("Latimer Reef Light", 41.304503, -71.933292));
        lighthouseData.add(new LighthouseInfo("Morgan Point Light", 41.316669, -71.989327));
        lighthouseData.add(new LighthouseInfo("Franklin Island Light", 43.892184, -69.374842));
        lighthouseData.add(new LighthouseInfo("Matinicus Rock Light", 43.783605, -68.854898));
        lighthouseData.add(new LighthouseInfo("Tenants Harbor Light", 43.961107, -69.184877));
        lighthouseData.add(new LighthouseInfo("Whitehead Light", 43.978706, -69.124285));
        lighthouseData.add(new LighthouseInfo("Two Bush Island Light", 43.964239, -69.073942));
        lighthouseData.add(new LighthouseInfo("Indian Island Light", 44.165470, -69.061004));
        lighthouseData.add(new LighthouseInfo("Browns Head Light", 44.111774, -68.909482));
        lighthouseData.add(new LighthouseInfo("Goose Rocks Light", 44.135394, -68.830526));
        lighthouseData.add(new LighthouseInfo("Sperry Light", 41.221221, -72.423110));
        lighthouseData.add(new LighthouseInfo("Isle au Haut Light", 44.064733, -68.651339));
        lighthouseData.add(new LighthouseInfo("Deer Island Thorofare Light", 44.134338, -68.703202));
        lighthouseData.add(new LighthouseInfo("Herrick Cove Light", 43.411136, -72.041706));
        lighthouseData.add(new LighthouseInfo("Eagle Island Light", 44.217634, -68.767743));
        lighthouseData.add(new LighthouseInfo("Burnt Coat Harbor Light", 44.134176, -68.447258));
        lighthouseData.add(new LighthouseInfo("Faulkner's Island Light", 41.211612, -72.655088));
        lighthouseData.add(new LighthouseInfo("Blue Hill Bay Light", 44.248746, -68.497880));
        lighthouseData.add(new LighthouseInfo("Great Duck Island Light", 44.142193, -68.245836));
        lighthouseData.add(new LighthouseInfo("Bear Island Light", 44.283485, -68.269858));
        lighthouseData.add(new LighthouseInfo("Baker Island Light", 44.241266, -68.198923));
        lighthouseData.add(new LighthouseInfo("Crabtree Ledge Light", 44.475613, -68.199383));
        lighthouseData.add(new LighthouseInfo("Statford Shoal Light", 41.059557, -73.101394));
        lighthouseData.add(new LighthouseInfo("Petit Manan Light", 44.367574, -67.864129));
        lighthouseData.add(new LighthouseInfo("Penfield Reef Light", 41.117101, -73.222070));
        lighthouseData.add(new LighthouseInfo("Narraguagus Light", 44.462467, -67.837844));
        lighthouseData.add(new LighthouseInfo("Nash Island Light", 44.464305, -67.747299));
        lighthouseData.add(new LighthouseInfo("Moose Peak Light", 44.474244, -67.533471));
        lighthouseData.add(new LighthouseInfo("Green's Ledge Light", 41.041551, -73.443974));
        lighthouseData.add(new LighthouseInfo("Libby Island Light", 44.568236, -67.367339));
        lighthouseData.add(new LighthouseInfo("Great Captain Island Light", 40.982478, -73.623706));
        lighthouseData.add(new LighthouseInfo("Avery Rock Light", 44.654358, -67.344137));
        lighthouseData.add(new LighthouseInfo("Little River Light", 44.650873, -67.192325));
        lighthouseData.add(new LighthouseInfo("Lubec Channel Light", 44.841955, -66.976731));
        lighthouseData.add(new LighthouseInfo("St. Croix River Light", 45.128762, -67.133594));

        /*
         * "Clean out" photo directories before beginning photo transfer process.
         */
        final File photosDir = new File("photos");
        final File[] photoLighthouseDirsToDelete = photosDir.listFiles();
        if (photoLighthouseDirsToDelete != null) {
            for (final File photoLighthouseDir : photoLighthouseDirsToDelete) {
                // Use Apache Commons IO (again) to recursively delete the directory
                // and all of the files within it
                if (photoLighthouseDir.exists() && photoLighthouseDir.isDirectory()) {
                    try {
                        FileUtils.deleteDirectory(photoLighthouseDir);
                        System.out.println("Deleted directory \"" + photoLighthouseDir + "\" successfully.");
                    } catch (final IOException ioe) {
                        System.err.println(
                                "Could not delete directory: \"" + photoLighthouseDir + "\" successfully!");
                    }
                }
            }
        }

        // Keep track of elapsed time
        long estimatedTime = System.nanoTime() - startTime;
        String elapsedTime = WebImageManager.calculateElapsedTime(estimatedTime);

        System.out.println("Estimated elapsed time: " + elapsedTime + ".");

        System.out.println();

        /*
         * Keep track of total number of photographs transferred from Flickr
         * websites to disks across _all_ lighthouses
         */
        int totalNumPhotosTransferred = 0;

        /*
         * Keep track of total number of photographs that _should_ be transferred
         * from Flickr for _all_ lighthouses
         */
        int totalNumPhotos = 0;

        for (final LighthouseInfo lighthousePieceOfData : lighthouseData) {
            System.out.println("Processing photos of " + lighthousePieceOfData.getName() + "...");

            /*
             * URL for accessing Flickr APIs. For a given lighthouse, this URL
             * provides an XML file in response that lists information about every
             * geotagged, Creative Commons-enabled photograph for that lighthouse
             * on Flickr.
             */
            // GET Parameter Explanation:
            // method - Use the "search photos" method for the Flickr APIs
            //
            // api_key - A unique key that I use to get the results
            //
            // text - Find all lighthouses whose title, tags, or description
            // contains the word "lighthouse"
            //
            // license - Find all photos with a Creative Commons license _except_
            // those that do not allow for modification on my part
            //
            // content_type - Find photos only (no videos)
            //
            // has_geo - Implicitly set to true; implies that all photos are
            // geotagged
            //
            // lat - The latitude of the center of the "search circle"
            //
            // lon - The longitude of the center of the "search circle"
            //
            // radius - The radius of the "search circle," in _kilometers_ (NOT
            // miles)
            //
            // extras - Also include a URL to the "raw" photo (small version)
            final String inputURLText = "http://ycpi.api.flickr.com/services/rest/?" + "method=flickr.photos.search"
                    + "&api_key=3ea8366b020383eb91f170c6f41748f5" + "&text=lighthouse" + "&license=1,2,4,5,7"
                    + "&content_type=1" + "&has_geo" + "&lat=" + lighthousePieceOfData.getLatitude() + "&lon="
                    + lighthousePieceOfData.getLongitude() + "&radius=1" + "&extras=url_s";
            // Output file where XML web response will be stored temporarily
            final String outputFileName = "output.xml";

            /*
             * Convert the name of the lighthouse to a "computer friendly" version
             * with all lower-case letters and underscores replacing spaces,
             * apostrophes, and parenthesis
             */
            String lighthouseName = lighthousePieceOfData.getName();
            lighthouseName = lighthouseName.toLowerCase();
            lighthouseName = lighthouseName.replace(' ', '_');
            lighthouseName = lighthouseName.replace('\'', '_');
            lighthouseName = lighthouseName.replace('(', '_');
            lighthouseName = lighthouseName.replace(')', '_');

            // Will contain the textual links to each "raw" photo website
            Set<String> rawPhotoURLs = new HashSet<String>();

            // Make sure file for XML output does not exist at first
            // (don't want to use an old, incorrect version accidentally)
            final File outputXMLFile = new File(outputFileName);
            if (outputXMLFile.exists()) {
                outputXMLFile.delete();
            }
            System.out.println("Cleaned output XML file containing photo URLs on disk successfully.");

            /*
             * Access the list of photographs for a given lighthouse and copy them
             * to the XML file on disk
             */
            final WebDataExtractor extractor = new WebDataExtractor(inputURLText, outputFileName);
            System.out.println("Looking for XML file containing lighthosue photo information...");
            extractor.transferURLToFile();
            System.out.println("Found XML file containing lighthouse photo URLs.");

            /*
             * Object for extracting the "raw" URLs from each piece of photo data
             * in the XML file
             */
            final XMLParser parser = new FlickrXMLOutputParser(outputFileName);

            // Complete the extraction process
            rawPhotoURLs = parser.parseFile("//photo/@url_s");

            final int numPhotos = rawPhotoURLs.size();
            totalNumPhotos += numPhotos;
            int i = 0; // Counter for keeping track of progress

            /*
             * Keep track of photos transferred successfully (which might be less
             * than the total number of photos defined int the XML output from
             * Flickr, especially if connection issues occur
             */
            int numPhotosTransferred = 0;
            for (final String photoURL : rawPhotoURLs) {
                System.out.print("Transferring photos...");
                i++;

                /*
                 * Go to a website containing a "raw" JPEG image file and save it
                 * accordingly on disk in the photo folder corresponding to the
                 * lighthouse name
                 */
                final WebDataExtractor rawPhotoExtractor = new WebDataExtractor(photoURL,
                        "photos/" + lighthouseName + "/lighthouse_photo_" + Integer.toString(i) + ".jpg");
                final boolean transferSuccessful = rawPhotoExtractor.transferURLToFile();
                if (transferSuccessful) {
                    numPhotosTransferred++;
                }

                // Simple progress tracker
                System.out.printf("%d of %d (%.1f%%) complete.\n", i, numPhotos, i * 1.0 / numPhotos * 100.0);
            }

            // Indicate number of photos successfully transferred to disk
            if (numPhotosTransferred == numPhotos && numPhotos > 0) {
                System.out.println("All photos transferred to disk successfully!");
            } else if (numPhotos == 0) {
                System.out.println("It appears there are no photos available for this lighthouse...");
            } else if (numPhotosTransferred == 1 && numPhotos > 1) {
                System.out.println("1 photo transferred to disk successfully.");
            } else if (numPhotosTransferred == 1 && numPhotos == 1) {
                System.out.println("The photo transferred to disk successfully!");
            } else {
                System.out.println(numPhotosTransferred + " photos transferred to disk successfully.");
            }

            // Keep track of elapsed time
            estimatedTime = System.nanoTime() - startTime;
            elapsedTime = WebImageManager.calculateElapsedTime(estimatedTime);
            System.out.println("Estimated elapsed time: " + elapsedTime + ".");

            // Add extra line in between lighthouses in output stream
            System.out.println();

            /*
             * Keep track of total number of photos transferred so far across
             * _all_lighthouses
             */
            totalNumPhotosTransferred += numPhotosTransferred;

        }

        // Display "grand" total (which is hopefully greater than 0)
        System.out.println("***GRAND TOTAL: " + totalNumPhotosTransferred + " OF " + totalNumPhotos
                + " PHOTOS TRANSFERRED SUCCESSFULLY***");
        estimatedTime = System.nanoTime() - startTime;
        elapsedTime = WebImageManager.calculateElapsedTime(estimatedTime);
        System.out.println("TOTAL ELAPSED TIME: " + elapsedTime.toUpperCase());
    }

    private static String calculateElapsedTime(final long estimatedTime) {
        String output = "";
        final double numSecondsPrecise = estimatedTime / 1000000000.0;
        int numSeconds = (int) (numSecondsPrecise + 0.5);
        int numMinutes = 0;
        numMinutes = numSeconds / 60;
        numSeconds = numSeconds % 60;

        if (numMinutes > 0) {
            if (numMinutes == 1) {
                output = output.concat("1 minute");
            } else {
                output = output.concat(numMinutes + " minutes");
            }
        }

        // At "even" minute markers (exactly 2 minutes), don't record seconds
        // value
        if (numMinutes == 0 || numMinutes > 0 && numSeconds != 0) {
            if (numSeconds == 1) {
                output = output.concat(" 1 second");
            } else {
                output = output.concat(" " + numSeconds + " seconds");
            }
        }
        return output;
    }
}