/// <summary>
        /// Add a comment to a photo
        /// </summary>
        /// <param name="photoID"></param>
        /// <param name="albumID"></param>
        /// <param name="access_token"></param>
        /// <param name="cep"></param>
        /// <returns></returns>
        public bool AddCommentToPhoto(string photoID, string albumID, string access_token, Picasa.CommentEntryPost cep)
        {
            //POST https://picasaweb.google.com/data/feed/api/user/default/albumid/albumID/photoid/photoID
            string insertURI = string.Format("{0}{1}{2}"
                                            , GoogleUtilityConstants.PICASA_FEED_BASE_URI_NO_HTTPS
                                            , GetAlbumURI(albumID)
                                            , GetPhotoURI(photoID));

            GoogleTCPRequestor tcpr = new GoogleTCPRequestor(Requestor.Operation.POST
                                                            , Requestor.HTTPFormat.FORMAT_1_1
                                                            , Requestor.ContentType.ATOM_XML
                                                            , GoogleUtilityConstants.GOOGLE_PICASA_HOST
                                                            , insertURI
                                                            , cep.toXmlPostString()
                                                            , access_token
                                                            , true);

            //submit the request:
            return tcpr.SubmitRequest(true, false, Requestor.ResponseTerminatorAction.CONTAINS_HTTP_1_1_201_CREATED);
        }
        /// <summary>
        /// Create an album and return the ID for the album.
        /// </summary>
        /// <param name="aep">The album entry xml to post</param>
        /// <param name="access_token">The user accss token</param>
        /// <returns></returns>
        public string CreateAlbum(Picasa.AlbumEntryPost aep, string access_token)
        {
            GoogleTCPRequestor tcpr = new GoogleTCPRequestor(Requestor.Operation.POST
                                                                , Requestor.HTTPFormat.FORMAT_1_1
                                                                , Requestor.ContentType.ATOM_XML
                                                                , GoogleUtilityConstants.GOOGLE_PICASA_HOST
                                                                , GoogleUtilityConstants.PICASA_FEED_BASE_URI_NO_HTTPS
                                                                , aep.toXmlPostString()
                                                                , access_token
                                                                , true);
            string response = tcpr.SubmitRequest(true, Requestor.ResponseTerminatorAction.READ_TO_END);

            string match1 = "<gphoto:id>";
            string match2 = "</gphoto:id>";
            string albumID = response.Substring(response.IndexOf(match1), response.IndexOf(match2) - response.IndexOf(match1));
            albumID = albumID.Replace(match1, "");
            albumID = albumID.Replace("<", "");
            albumID = albumID.Replace("/", "");
            return albumID;
        }
        /// <summary>
        /// Delete an album By ID:
        /// </summary>
        /// <param name="albumID"></param>
        /// <param name="access_token"></param>
        /// <returns></returns>
        public bool DeleteAlbum(string albumID, string access_token)
        {
            GoogleTCPRequestor tcpr = new GoogleTCPRequestor(Requestor.Operation.DELETE
                                                                , Requestor.HTTPFormat.FORMAT_1_1
                                                                , Requestor.ContentType.NO_CONTENT_TYPE
                                                                , GoogleUtilityConstants.GOOGLE_PICASA_HOST
                                                                , string.Format("{0}{1}"
                                                                                , GoogleUtilityConstants.PICASA_ENTRY_BASE_URI_NO_HTTPS
                                                                                , string.Format(GoogleUtilityConstants.PICASA_ALBUMID_URI, albumID))
                                                                , null
                                                                , access_token
                                                                , true);
            tcpr.CustomHeaders.Add(GoogleUtilityConstants.CONTENT_IF_MATCH_ALL);
            string response = tcpr.SubmitRequest(false, Requestor.ResponseTerminatorAction.READ_TO_END);

            return (response.Contains("HTTP/1.1 200 OK"));
        }
        /// <summary>
        /// Update a photo metadata by atom entry.
        /// </summary>
        /// <param name="photoEntry">The entry containing the modified information</param>
        /// <param name="access_token">user access token</param>
        /// <returns>true on success else false</returns>
        public bool UpdatePhotoMetadataByEntry(SyndicationItem photoEntry, string access_token)
        {
            // PUT https://picasaweb.google.com/data/entry/api/user/default/albumid/albumID/photoid/photoID
            string photoID = string.Empty;
            string albumID = string.Empty;

            //get the photoid and albumid from the photoentry'
            SyndicationElementExtension ext = null;
            ext = photoEntry.ElementExtensions.Where(x => x.OuterName.ToLower().Equals("id")).First();
            photoID = ext.GetReader().ReadInnerXml();
            ext = photoEntry.ElementExtensions.Where(x => x.OuterName.ToLower().Equals("albumid")).First();
            albumID = ext.GetReader().ReadInnerXml();

            string updateURI = string.Format("{0}{1}{2}"
                                                , GoogleUtilityConstants.PICASA_ENTRY_BASE_URI_NO_HTTPS
                                                , GetAlbumURI(albumID)
                                                , GetPhotoURI(photoID));

            var output = new StringBuilder();
            var formatter = new Atom10ItemFormatter(photoEntry);

            using (var writer = XmlWriter.Create(output))
            {
                formatter.WriteTo(writer);
            }

            //var contentAsBytes = Encoding.ASCII.GetBytes(output.ToString());

            GoogleTCPRequestor tcpr = new GoogleTCPRequestor(Requestor.Operation.PUT
                                                            , Requestor.HTTPFormat.FORMAT_1_1
                                                            , Requestor.ContentType.ATOM_XML
                                                            , GoogleUtilityConstants.GOOGLE_PICASA_HOST
                                                            , updateURI
                                                            , output.ToString()
                                                            , access_token
                                                            , true);

            //submit the request:
            return tcpr.SubmitRequest(true, false, Requestor.ResponseTerminatorAction.CONTAINS_HTTP_1_1_200_OK);
        }
        /// <summary>
        /// Update the album by entry
        /// </summary>
        /// <param name="albumEntry"></param>
        /// <param name="access_token"></param>
        /// <returns></returns>
        public bool UpdateAlbum(SyndicationItem albumEntry, string access_token)
        {
            //get the album id
            string albumID = string.Empty;
            SyndicationElementExtension ext = albumEntry.ElementExtensions.Where(x => x.OuterName.ToLower().Equals("id")).First();
            albumID = ext.GetReader().ReadInnerXml();

            //create the URI
            string updateURI = string.Format("{0}{1}"
                                            , GoogleUtilityConstants.PICASA_ENTRY_BASE_URI_NO_HTTPS
                                            , string.Format(GoogleUtilityConstants.PICASA_ALBUMID_URI, albumID));
            //create the content body string
            var output = new StringBuilder();
            var formatter = new Atom10ItemFormatter(albumEntry);
            using (var writer = XmlWriter.Create(output))
            {
                formatter.WriteTo(writer);
            }

            //create the requestor
            GoogleTCPRequestor tcpr = new GoogleTCPRequestor(Requestor.Operation.PUT
                                                            , Requestor.HTTPFormat.FORMAT_1_1
                                                            , Requestor.ContentType.ATOM_XML
                                                            , GoogleUtilityConstants.GOOGLE_PICASA_HOST
                                                            , updateURI
                                                            , output.ToString()
                                                            , access_token
                                                            , true);

            //get the output
            string response = tcpr.SubmitRequest(true, Requestor.ResponseTerminatorAction.READ_TO_END);

            return response.Contains("HTTP/1.1 200 OK");
        }
        /// <summary>
        /// Get the last n comments for a user (enter 0 to get all, sparingly)
        /// </summary>
        /// <param name="maxNumberOfCommentsToRetrieve">0 for all (use sparingly), recommend 10-15-20, etc</param>
        /// <returns></returns>
        public SyndicationFeed GetUserCommentsByLimiter(int maxNumberOfCommentsToRetrieve, string access_token)
        {
            string commentFeedURI = string.Format("{0}?kind=comment"
                                                    , GoogleUtilityConstants.PICASA_FEED_BASE_URI_NO_HTTPS);
            if (maxNumberOfCommentsToRetrieve > 0)
            {
                commentFeedURI = string.Format("{0}&max-results={1}", commentFeedURI, maxNumberOfCommentsToRetrieve);
            }

            GoogleTCPRequestor tcpr = new GoogleTCPRequestor(Requestor.Operation.GET
                                                                , Requestor.HTTPFormat.FORMAT_1_1
                                                                , Requestor.ContentType.NO_CONTENT_TYPE
                                                                , GoogleUtilityConstants.GOOGLE_PICASA_HOST
                                                                , commentFeedURI
                                                                , null
                                                                , access_token
                                                                , true);

            String response = tcpr.SubmitRequest(false, Requestor.ResponseTerminatorAction.FEED_TERMINATOR);
            return getFeedFromResponse(response);
        }
        /// <summary>
        /// Get the user albums as a list of utility album type
        /// </summary>
        /// <param name="access_token"></param>
        /// <returns></returns>
        public List<Picasa.Album> GetUserAlbums(string access_token)
        {
            List<Picasa.Album> retAlbums = new List<Picasa.Album>();

            GoogleTCPRequestor tcpr = new GoogleTCPRequestor(Requestor.Operation.GET
                                                            , Requestor.HTTPFormat.FORMAT_1_1
                                                            , Requestor.ContentType.NO_CONTENT_TYPE
                                                            , GoogleUtilityConstants.GOOGLE_PICASA_HOST
                                                            , GoogleUtilityConstants.PICASA_FEED_BASE_URI_NO_HTTPS
                                                            , null
                                                            , access_token
                                                            , true);
            //get the response
            string response = tcpr.SubmitRequest(false, Requestor.ResponseTerminatorAction.FEED_TERMINATOR);
            SyndicationFeed sf = getFeedFromResponse(response);
            if (response != null)
            {
                var items = sf.Items;
                foreach (var item in items)
                {
                    //each 'item' is a new album to handle, so put it in the feed
                    Picasa.Album a = GetUtilityAlbumFromAlbumEntry(item);
                    retAlbums.Add(a);
                }
            }
            return retAlbums;
        }
        /// <summary>
        /// Get Tags by User
        /// </summary>
        /// <param name="access_token"></param>
        /// <returns></returns>
        public SyndicationFeed GetTagsByUser(string access_token)
        {
            string feedURI = string.Format("{0}?kind=tag",
                                            GoogleUtilityConstants.PICASA_FEED_FULL_URI_INCL_HTTPS);

            //https://picasaweb.google.com/data/feed/api/user/userID?kind=tag
            GoogleTCPRequestor tcpr = new GoogleTCPRequestor(Requestor.Operation.GET
                                                            , Requestor.HTTPFormat.FORMAT_1_1
                                                            , Requestor.ContentType.ATOM_XML
                                                            , GoogleUtilityConstants.GOOGLE_PICASA_HOST
                                                            , feedURI
                                                            , null
                                                            , access_token
                                                            , true);

            string response = tcpr.SubmitRequest(false, Requestor.ResponseTerminatorAction.FEED_TERMINATOR);
            return getFeedFromResponse(response);
        }
        /// <summary>
        /// Get a list of tags by photo
        /// </summary>
        /// <param name="albumID"></param>
        /// <param name="photoID"></param>
        /// <param name="access_token"></param>
        /// <returns></returns>
        public SyndicationFeed GetTagsByPhoto(string albumID, string photoID, string access_token)
        {
            //https://picasaweb.google.com/data/feed/api/user/default/albumid/albumID/photoid/photoID?kind=tag
            string feedURI = string.Format("{0}{1}{2}?kind=tag",
                                                GoogleUtilityConstants.PICASA_FEED_FULL_URI_INCL_HTTPS
                                                , GetAlbumURI(albumID)
                                                , GetPhotoURI(photoID));

            GoogleTCPRequestor tcpr = new GoogleTCPRequestor(Requestor.Operation.GET
                                                            , Requestor.HTTPFormat.FORMAT_1_1
                                                            , Requestor.ContentType.ATOM_XML
                                                            , GoogleUtilityConstants.GOOGLE_PICASA_HOST
                                                            , feedURI
                                                            , null
                                                            , access_token
                                                            , true);

            string response = tcpr.SubmitRequest(false, Requestor.ResponseTerminatorAction.FEED_TERMINATOR);
            return getFeedFromResponse(response);
        }
        /// <summary>
        /// Find matching photos by tag
        /// </summary>
        /// <param name="tags">comma separated list of all tags to search for</param>
        /// <param name="access_token"></param>
        /// <returns></returns>
        public SyndicationFeed GetPhotosByTag(string tags, string access_token)
        {
            //https://picasaweb.google.com/data/feed/api/user/default?kind=photo&tag=cyclone%2Cfootball
            tags = tags.Replace(",", "%2C");

            string feedURI = string.Format("{0}?kind=photo&tag={1}",
                                                GoogleUtilityConstants.PICASA_FEED_FULL_URI_INCL_HTTPS
                                                , tags);

            GoogleTCPRequestor tcpr = new GoogleTCPRequestor(Requestor.Operation.GET
                                                            , Requestor.HTTPFormat.FORMAT_1_1
                                                            , Requestor.ContentType.ATOM_XML
                                                            , GoogleUtilityConstants.GOOGLE_PICASA_HOST
                                                            , feedURI
                                                            , null
                                                            , access_token
                                                            , true);

            string response = tcpr.SubmitRequest(false, Requestor.ResponseTerminatorAction.FEED_TERMINATOR);
            return getFeedFromResponse(response);
        }
        /// <summary>
        /// Get a photo feed by the feed URL and access token
        /// </summary>
        /// <param name="feedURL">URL to the photo feed</param>
        /// <param name="token">access token</param>
        /// <returns>Single Photo Feed item</returns>
        public SyndicationFeed GetPhotoFeed(string feedURL, string access_token)
        {
            string feedURI = feedURL.Replace("https://", "");
            feedURI = feedURI.Replace(GoogleUtilityConstants.GOOGLE_PICASA_HOST, "");

            GoogleTCPRequestor gctpr = new GoogleTCPRequestor(Requestor.Operation.GET
                                                                , Requestor.HTTPFormat.FORMAT_1_1
                                                                , Requestor.ContentType.NO_CONTENT_TYPE
                                                                , GoogleUtilityConstants.GOOGLE_PICASA_HOST
                                                                , feedURI
                                                                , null
                                                                , access_token
                                                                , true);

            string response = gctpr.SubmitRequest(false, Requestor.ResponseTerminatorAction.FEED_TERMINATOR);
            return getFeedFromResponse(response);
        }
        /// <summary>
        /// Delete a tag from a photo
        /// </summary>
        /// <param name="tagID"></param>
        /// <param name="photoID"></param>
        /// <param name="albumID"></param>
        /// <param name="access_token"></param>
        /// <returns></returns>
        public bool DeleteTagFromPhoto(string tagID, string photoID, string albumID, string access_token)
        {
            //uri = DELETE https://picasaweb.google.com/data/entry/api/user/userID/albumid/albumID/photoid/photoID/tag/tagID

            string deleteURI = string.Format("{0}{1}{2}{3}"
                                        , GoogleUtilityConstants.PICASA_ENTRY_FULL_URI_INCL_HTTPS
                                        , GetAlbumURI(albumID)
                                        , GetPhotoURI(photoID)
                                        , GetTagURI(tagID));

            GoogleTCPRequestor tcpr = new GoogleTCPRequestor(Requestor.Operation.DELETE
                                                            , Requestor.HTTPFormat.FORMAT_1_1
                                                            , Requestor.ContentType.ATOM_XML
                                                            , GoogleUtilityConstants.GOOGLE_PICASA_HOST
                                                            , deleteURI
                                                            , null
                                                            , access_token
                                                            , true);
            return tcpr.SubmitRequest(false, false, Requestor.ResponseTerminatorAction.CONTAINS_HTTP_1_1_200_OK);
        }
        /// <summary>
        /// Delete a photo by feedURI and access_token
        /// </summary>
        /// <param name="photoFeedURI"></param>
        /// <param name="access_token"></param>
        /// <notes>If using full URI, you must make sure to replace userID in the feed with 'default' -- not the ID of the user</notes>
        /// <returns></returns>
        public bool DeletePhoto(string photoFeedURI, string access_token)
        {
            if (photoFeedURI.Contains("https://"))
            {
                photoFeedURI = photoFeedURI.Replace("https://", "");
            }
            if (photoFeedURI.Contains(GoogleUtilityConstants.GOOGLE_PICASA_HOST))
            {
                photoFeedURI = photoFeedURI.Replace(GoogleUtilityConstants.GOOGLE_PICASA_HOST, "");
            }

            GoogleTCPRequestor tcpr = new GoogleTCPRequestor(Requestor.Operation.DELETE
                                                               , Requestor.HTTPFormat.FORMAT_1_1
                                                               , Requestor.ContentType.IF_MATCH_ALL
                                                               , GoogleUtilityConstants.GOOGLE_PICASA_HOST
                                                               , photoFeedURI
                                                               , null
                                                               , access_token
                                                               , true);
            return tcpr.SubmitRequest(false, true, Requestor.ResponseTerminatorAction.CONTAINS_HTTP_1_1_200_OK);
        }
        /// <summary>
        /// Post the photo tag
        /// </summary>
        /// <param name="albumID"></param>
        /// <param name="photoID"></param>
        /// <param name="tep"></param>
        /// <param name="access_token"></param>
        /// <returns></returns>
        private bool PostTagToPhoto(string albumID, string photoID, Picasa.TagEntryPost tep, string access_token)
        {
            string updateURI = string.Format("{0}{1}{2}"
                                            , GoogleUtilityConstants.PICASA_FEED_BASE_URI_NO_HTTPS
                                            , GetAlbumURI(albumID)
                                            , GetPhotoURI(photoID));

            GoogleTCPRequestor tcpr = new GoogleTCPRequestor(Requestor.Operation.POST
                                                            , Requestor.HTTPFormat.FORMAT_1_1
                                                            , Requestor.ContentType.ATOM_XML
                                                            , GoogleUtilityConstants.GOOGLE_PICASA_HOST
                                                            , updateURI
                                                            , tep.toXmlPostString()
                                                            , access_token
                                                            , true);

            //submit the request:
            return tcpr.SubmitRequest(true, false, Requestor.ResponseTerminatorAction.CONTAINS_HTTP_1_1_201_CREATED);
        }