public Task<IEnumerable<Achievement>> Process(User user, IEnumerable<Workout> workouts, CancellationToken cancel = default(CancellationToken))
 {
     return Task.FromResult(Enumerable.Empty<Achievement>());
 }
        public async Task<IEnumerable<Achievement>> Process(User user, IEnumerable<Workout> workouts, CancellationToken cancel = default(CancellationToken))
        {
            var achievements = new List<Achievement>();

            foreach (var workout in workouts)
            {
                var tasks = _providers.Select(achievement => achievement.Execute(workout)).ToList();
                var staleAchievements = (await _database.GetAchievements(workout.Id)).ToList();

                while (tasks.Count > 0)
                {
                    var task = await Task.WhenAny(tasks);

                    foreach (var freshAchievement in task.Result)
                    {
                        var matchingAchievements = staleAchievements
                            .Where(achievement => achievement.Type == freshAchievement.Type &&
                                                  achievement.Group == freshAchievement.Group &&
                                                  achievement.Activity == freshAchievement.Activity)
                            .ToList();

                        if (matchingAchievements.Count == 0)
                        {
                            freshAchievement.WorkoutId = workout.Id;
                            _database.Insert(freshAchievement);

                            if (workout.Date > user.InsertDate.AddDays(-7))
                            {
                                achievements.Add(freshAchievement);
                            }
                        }
                        else
                        {
                            var staleAchievement = matchingAchievements.FirstOrDefault(achievement => !freshAchievement.HasChanges(achievement));
                            if (staleAchievement == null)
                            {
                                staleAchievement = matchingAchievements[0];
                                freshAchievement.Id = staleAchievement.Id;
                                freshAchievement.WorkoutId = workout.Id;
                                _database.Update(freshAchievement);

                                if (freshAchievement.CommentText != staleAchievement.CommentText ||
                                    (freshAchievement.IsPropped && !staleAchievement.IsPropped))
                                {
                                    achievements.Add(freshAchievement);
                                }
                            }
                            staleAchievements.Remove(staleAchievement);
                        }
                    }

                    tasks.Remove(task);
                }

                foreach (var staleAchievement in staleAchievements)
                {
                    _database.Delete(staleAchievement);

                    if (staleAchievement.CommentId != null)
                    {
                        staleAchievement.CommentText = null;
                        achievements.Add(staleAchievement);
                    }
                }

                cancel.ThrowIfCancellationRequested();
            }

            return achievements;
        }
        public async Task<IEnumerable<Workout>> Pull(User user, CancellationToken cancel = default(CancellationToken))
        {
            var changes = Enumerable.Repeat(new {workout = default(Workout), operation = default(byte)}, 0).ToList();
            const byte none = 0;
            const byte insert = 1;
            const byte updateDeep = 2;
            const byte updateShallow = 3;
            const byte delete = 4;

            var offset = 0;
            var processedIds = new HashSet<long>();
            var toDate = DateTime.MaxValue;
            var deletedWorkouts = new List<Workout>();
            while (true)
            {
                var freshWorkouts = await _fitocracy.GetWorkouts(user.Id, offset);
                var freshLookup = freshWorkouts.ToLookup(workout => workout.Id);

                foreach (var workout in deletedWorkouts.Where(workout => !freshLookup[workout.Id].Any()))
                {
                    changes.Add(new {workout, operation = delete});
                }

                if (freshWorkouts.Count == 0)
                {
                    _database.DeleteWorkoutsBefore(user.Id, toDate);
                    break;
                }
                offset += freshWorkouts.Count;

                freshWorkouts = freshWorkouts.Where(workout => processedIds.Add(workout.Id)).ToList();
                if (freshWorkouts.Count == 0)
                {
                    continue;
                }

                var fromDate = freshWorkouts.Min(workout => workout.Date);
                var staleWorkouts = (await _database.GetWorkouts(user.Id, fromDate, toDate)).ToList();
                toDate = fromDate;

                var staleLookup = staleWorkouts.ToLookup(workout => workout.Id);
                changes.AddRange(freshWorkouts
                                     .Select(workout =>
                                         {
                                             workout.ActivitiesHash = ComputeActivitiesHashCode(workout.Activities);
                                             foreach (var activity in workout.Activities)
                                             {
                                                 activity.Group = _grouping.GetActvityGroup(activity.Name);
                                             }
                                             var staleWorkout = staleLookup[workout.Id].FirstOrDefault() ?? deletedWorkouts.FirstOrDefault(item => item.Id == workout.Id);
                                             return new
                                                 {
                                                     workout,
                                                     operation = staleWorkout != null
                                                                     ? workout.HasChanges(staleWorkout)
                                                                           ? staleWorkout.ActivitiesHash != workout.ActivitiesHash
                                                                                 ? updateDeep
                                                                                 : updateShallow
                                                                           : none
                                                                     : insert
                                                 };
                                         }));
                deletedWorkouts = staleWorkouts.Where(workout => !freshLookup[workout.Id].Any()).ToList();

                if (deletedWorkouts.Count == 0 && changes[changes.Count - 1].operation == none)
                {
                    break;
                }

                cancel.ThrowIfCancellationRequested();
            }

            changes.Reverse();
            changes.Sort((left, right) => left.workout.Date.CompareTo(right.workout.Date));

            foreach (var item in changes)
            {
                switch (item.operation)
                {
                    case insert:
                        _database.Insert(item.workout);
                        break;
                    case updateDeep:
                    case updateShallow:
                        _database.Update(item.workout, item.operation == updateDeep);
                        break;
                    case delete:
                        _database.Delete(item.workout);
                        break;
                }
            }

            return changes.Where(item => item.operation != delete)
                          .SkipWhile(item => item.operation == none)
                          .Select(item => item.workout)
                          .ToList();
        }
Example #4
0
 public bool HasChanges(User user)
 {
     return Username != user.Username;
 }