/// <summary>
        /// Removes the calling user from the specified selected course.
        /// If after the removal no other user has selected the course,
        /// the course is removed from the schedule.
        /// </summary>
        /// <remarks>
        /// If the user has not selected the course with the specified ID,
        /// nothing happens.
        /// </remarks>
        /// <param name="courseId">Course ID</param>
        /// <returns></returns>
        public async Task RemoveUserFromCourse(string courseId, bool acquireSemaphore = true)
        {
            using (var errorReporter = new ErrorReporter(s => CallingClient.Errors.ScheduleMessage = s))
            {
                if (PaulRepository.Courses.All(c => c.Id != courseId))
                {
                    errorReporter.Throw(
                        new ArgumentException("Course not found", nameof(courseId)),
                        UserErrorsViewModel.GenericErrorMessage);
                }

                var schedule = CallingClient.SharedScheduleVM.Schedule;

                var selectedCourse = schedule.SelectedCourses
                                     .FirstOrDefault(c => c.CourseId == courseId);

                if (selectedCourse == null)
                {
                    errorReporter.Throw(
                        new ArgumentException("Course not found in the schedule!"),
                        UserErrorsViewModel.GenericErrorMessage);
                }

                var selectedConnectedCourses = schedule.SelectedCourses
                                               .Where(sel => selectedCourse.Course.ConnectedCourses.Any(it => it.Id == sel.CourseId))
                                               .ToList();

                if (acquireSemaphore)
                {
                    await CallingClient.SharedScheduleVM.TimetableHubSemaphore.WaitAsync();
                }
                try
                {
                    var selectedCourseUser = selectedCourse.Users.FirstOrDefault(o => o.User == CallingClient.User);

                    //Find selected Tutorials
                    var selectedTutorials = schedule.SelectedCourses
                                            .Where(sel => selectedCourse.Course.Tutorials
                                                   .Concat(selectedConnectedCourses.SelectMany(s => s.Course.Tutorials))
                                                   .Any(it => it.Id == sel.CourseId))
                                            .ToList();

                    if (selectedCourseUser != null)
                    {
                        // Remove user from selected courses
                        foreach (var sel in selectedConnectedCourses.Concat(selectedTutorials).Concat(new[] { selectedCourse }))
                        {
                            await PaulRepository.RemoveUserFromSelectedCourseAsync(sel, selectedCourseUser);
                        }
                    }

                    if (!selectedCourse.Users.Any())
                    {
                        var firstTutorials = selectedCourse.Course.Tutorials.Take(1)
                                             .Concat(selectedConnectedCourses.SelectMany(s => s.Course.Tutorials.Take(1)));

                        // Remove all Pending Tutorials from all TailoredSchedules
                        foreach (var user in CallingClient.SharedScheduleVM.Users)
                        {
                            foreach (var t in firstTutorials)
                            {
                                user.TailoredScheduleVM.RemovePendingTutorials(t, errorReporter);
                            }
                        }

                        // The course is no longer selected by anyone
                        // -> Remove the whole course from schedule
                        foreach (var sel in selectedConnectedCourses.Concat(selectedTutorials).Concat(new[] { selectedCourse }))
                        {
                            await PaulRepository.RemoveCourseFromScheduleAsync(schedule, sel.CourseId);
                        }
                    }

                    UpdateAddedStateInSearchResultsAndCourseList(selectedCourse.Course, isAdded: false);
                    UpdateTailoredViewModels();
                }
                finally
                {
                    if (acquireSemaphore)
                    {
                        CallingClient.SharedScheduleVM.TimetableHubSemaphore.Release();
                    }
                }
            }
        }
        /// <summary>
        /// RPC-method for removing a course from the schedule
        /// </summary>
        /// <param name="courseId"></param>
        /// <returns></returns>
        public async Task RemoveCourse(string courseId)
        {
            using (var errorReporter = new ErrorReporter(s => CallingClient.Errors.ScheduleMessage = s))
            {
                var course = PaulRepository.Courses.FirstOrDefault(c => c.Id == courseId);

                if (course == null)
                {
                    errorReporter.Throw(
                        new ArgumentException("Course not found", nameof(courseId)),
                        UserErrorsViewModel.GenericErrorMessage);
                }

                var schedule = CallingClient.SharedScheduleVM.Schedule;

                await CallingClient.SharedScheduleVM.TimetableHubSemaphore.WaitAsync();

                try
                {
                    var selectedCourse = schedule.SelectedCourses.FirstOrDefault(c => c.CourseId == courseId);
                    if (selectedCourse != null)
                    {
                        //Find selected Tutorials
                        var selectedTutorials = schedule.SelectedCourses
                                                .Where(sel => selectedCourse.Course.Tutorials.Any(it => it.Id == sel.CourseId))
                                                .Select(s => s.Course)
                                                .ToList();

                        var courses = selectedCourse.Course.ConnectedCourses
                                      .Concat(selectedTutorials)
                                      .Concat(new[] { selectedCourse.Course });

                        foreach (var course1 in courses)
                        {
                            try
                            {
                                if (course1.Tutorials.Any())
                                {
                                    // Remove all pending tutorials from all TailoredSchedules
                                    foreach (var user in CallingClient.SharedScheduleVM.Users)
                                    {
                                        user.TailoredScheduleVM.RemovePendingTutorials(course1.Tutorials.FirstOrDefault(), errorReporter);
                                    }
                                }

                                await PaulRepository.RemoveCourseFromScheduleAsync(schedule, course1.Id);

                                UpdateAddedStateInSearchResultsAndCourseList(course1, isAdded: false);
                            }
                            catch (NullReferenceException e)
                            {
                                // This is just for purposes of compatibility
                                // with development versions. Can be safely removed
                                // after product launch
                                PaulRepository.AddLog(e.Message, FatalityLevel.Normal, typeof(TimetableHub).Name);
                            }
                        }

                        UpdateTailoredViewModels();
                    }
                    else if (course.IsTutorial)
                    {
                        // The user has decided to remove a tutorial before joining one
                        CallingClient.TailoredScheduleVM.RemovePendingTutorials(course, errorReporter);
                        UpdateTailoredViewModels();
                    }
                    else
                    {
                        errorReporter.Throw(
                            new ArgumentException("Course not found in the schedule!"),
                            UserErrorsViewModel.GenericErrorMessage);
                    }
                }
                finally
                {
                    CallingClient.SharedScheduleVM.TimetableHubSemaphore.Release();
                }
            }
        }