public IReadOnlyList <Contact> GetContactsFromGoogle(ICollection <string> ids)
        {
            return(_readOperationExecutor.Execute(
                       new List <Contact>(),
                       ids.Select(id =>
            {
                var contact = new Contact();
                contact.Id = GetContactUrl(id, ContactsQuery.fullProjection).ToString();
                contact.BatchData = new GDataBatchEntryData(contact.Id, GDataBatchOperationType.query);
                return contact;
            }),
                       (contactList, r) =>
            {
                var contactsFeed = _apiOperationExecutor.Execute(f => f.Batch(
                                                                     contactList,
                                                                     _apiOperationExecutor.Execute(g => g.GetContacts()),
                                                                     GDataBatchOperationType.query));

                if (contactsFeed != null)
                {
                    r.AddRange(contactsFeed.Entries);
                }
            }));
        }
        private void RunCreateBatch(Tuple <List <GoogleContactWrapper>, IReadOnlyList <ICreateJob <string, GoogleContactVersion, GoogleContactWrapper> > > requestsAndJobs)
        {
            if (requestsAndJobs.Item1.Count == 0)
            {
                return;
            }

            var responses = _writeOperationExecutor.Execute(
                new List <Contact>(),
                requestsAndJobs.Item1.Select(i => i.Contact),
                (contactList, r) =>
            {
                var contactsFeed = _apiOperationExecutor.Execute(f => f.Batch(
                                                                     contactList,
                                                                     new Uri("https://www.google.com/m8/feeds/contacts/default/full/batch"),
                                                                     GDataBatchOperationType.insert));

                r.AddRange(contactsFeed.Entries);
            });

            var requeryEtagJobs = new Dictionary <string, ICreateJob <string, GoogleContactVersion, GoogleContactWrapper> >(_contactIdComparer);

            for (var i = 0; i < responses.Count; i++)
            {
                var contact = responses[i];

                var createJob = requestsAndJobs.Item2[i];
                var request   = requestsAndJobs.Item1[i];
                if (contact.BatchData.Status.Code == (int)HttpStatusCode.Created)
                {
                    if (UpdatePhoto(contact, request.PhotoOrNull))
                    {
                        requeryEtagJobs.Add(contact.Id, createJob);
                    }
                    else
                    {
                        createJob.NotifyOperationSuceeded(EntityVersion.Create(contact.Id, new GoogleContactVersion {
                            ContactEtag = contact.ETag
                        }));
                    }
                }
                else
                {
                    var sw = new StringWriter();
                    using (var writer = new XmlTextWriter(sw))
                        contact.BatchData.Save(writer);
                    createJob.NotifyOperationFailed(sw.GetStringBuilder().ToString());
                }
            }

            var contacts     = GetContactsFromGoogle(requeryEtagJobs.Keys);
            var contactsById = contacts.ToDictionary(c => c.Id, _contactIdComparer);

            foreach (var requeryEtagJob in requeryEtagJobs)
            {
                Contact contact;
                if (contactsById.TryGetValue(requeryEtagJob.Key, out contact))
                {
                    requeryEtagJob.Value.NotifyOperationSuceeded(EntityVersion.Create(contact.Id, new GoogleContactVersion {
                        ContactEtag = contact.ETag
                    }));
                }
                else
                {
                    requeryEtagJob.Value.NotifyOperationFailed("Could not requery etag");
                }
            }
        }