public MessagesController()
        {
            var getCurrencyCommand     = new GetCurrencyCommand();
            var getTotalScoreCommand   = new GetTotalConversationScoreCommand(UserRepository);
            var getScoreForUserCommand = new GetScoreForUserCommand(UserRepository);
            var setScoreForUser        = new SetScoreForUserCommand(UserRepository);
            var incrementScoreForUser  = new IncrementScoreForUserCommand(UserRepository);
            var decrementScoreForUser  = new DecrementScoreForUserCommand(UserRepository);
            var getNowPlayingMovies    = new GetNowPlayingMovies(MovieRepository);
            var getUpcomingMovies      = new GetUpcomingMovies(MovieRepository);
            var getMovieReleaseDate    = new GetMovieReleaseDate(MovieRepository);
            var getTotalStatistics     = new GetTotalStatistics(MessagesRepository);
            var getDailyStatistics     = new GetDailyStatistics(MessagesRepository);

            _botCommands = new AllHandleCommandsAggregator(
                new DuplicatedMemeCommand(MemesRepository, UserRepository),
                new CollectTelemetry(MessagesRepository),
                new FirstHandleCommandAggregator(
                    getCurrencyCommand,
                    getScoreForUserCommand,
                    getTotalScoreCommand,
                    getDailyStatistics,
                    setScoreForUser,
                    incrementScoreForUser,
                    decrementScoreForUser,
                    getNowPlayingMovies,
                    getUpcomingMovies,
                    getMovieReleaseDate,
                    getTotalStatistics,
                    new DetermineWrongLayoutCommand(UserRepository),
                    new HelpComand(
                        getCurrencyCommand,
                        getScoreForUserCommand,
                        getTotalScoreCommand,
                        setScoreForUser,
                        incrementScoreForUser,
                        decrementScoreForUser,
                        getNowPlayingMovies,
                        getUpcomingMovies,
                        getMovieReleaseDate,
                        getTotalStatistics,
                        getDailyStatistics),
                    new RudeAnswerCommand()));
        }
        public UpcomingMoviesViewModel(
            IMovieService movieService   = null,
            IScheduler mainScheduler     = null,
            IScheduler taskPoolScheduler = null,
            IScreen hostScreen           = null)
            : base(hostScreen, mainScheduler, taskPoolScheduler)
        {
            _movieService = movieService ?? Locator.Current.GetService <IMovieService>();

            UrlPathSegment = "Upcoming Movies";

            var canGetMovies = this
                               .WhenAnyValue(
                x => x.SearchTerm,
                term => !string.IsNullOrWhiteSpace(term) && term.Length > 2);

            GetUpcomingMovies = ReactiveCommand
                                .CreateFromObservable <int, IEnumerable <Movie> >(
                page => ClearAndGetUpcomingMovies(page),
                outputScheduler: MainScheduler);

            GetMovies = ReactiveCommand
                        .CreateFromObservable <int, IEnumerable <Movie> >(
                page => ClearAndGetMovies(SearchTerm, page),
                canExecute: canGetMovies,
                outputScheduler: MainScheduler);

            Load = ReactiveCommand
                   .CreateFromObservable <Unit, int>(
                _ => Observable.Create <int>(
                    observer =>
            {
                const int pageSize = 20;

                if (Movies.Count % pageSize == 0)
                {
                    observer.OnNext(Movies.Count + 1);
                }
                observer.OnCompleted();

                return(Disposable.Empty);
            }),
                outputScheduler: MainScheduler);

            var loadRequested = Load
                                .Publish()
                                .RefCount();

            loadRequested
            .Where(page => string.IsNullOrWhiteSpace(SearchTerm))
            .StartWith(1)
            .DistinctUntilChanged()
            .InvokeCommand(GetUpcomingMovies);

            loadRequested
            .Where(page => !string.IsNullOrWhiteSpace(SearchTerm))
            .DistinctUntilChanged()
            .InvokeCommand(GetMovies);

            GetUpcomingMovies
            .IsExecuting
            .Merge(GetMovies.IsExecuting, TaskPoolScheduler)
            .SubscribeOn(TaskPoolScheduler)
            .ToProperty(this, x => x.IsLoading, out _isLoading,
                        scheduler: MainScheduler);

            var moviesChanged = GetUpcomingMovies
                                .Merge(GetMovies, TaskPoolScheduler)
                                .Where(movies => movies != null)
                                .SubscribeOn(TaskPoolScheduler)
                                .ObserveOn(TaskPoolScheduler)
                                .Publish();

            moviesChanged
            .Select(movies => movies.Where(movie => Movies.Any(m => m.Id == movie.Id)))
            .SubscribeOn(TaskPoolScheduler)
            .ObserveOn(MainScheduler)
            .SelectMany(movies => MergeMovies(movies))
            .Subscribe();

            moviesChanged
            .Select(movies => movies.Where(movie => !Movies.Any(m => m.Id == movie.Id)))
            .Select(movies => movies.Select(movie => new MovieCellViewModel(movie)))
            .SubscribeOn(TaskPoolScheduler)
            .ObserveOn(MainScheduler)
            .Subscribe(movies => Movies.AddRange(movies));

            moviesChanged
            .Connect();

            this.WhenAnyValue(x => x.SelectedMovie)
            .Where(selected => selected != null)
            .Select(selected => new MovieDetailsViewModel(selected))
            .SubscribeOn(TaskPoolScheduler)
            .ObserveOn(MainScheduler)
            .InvokeCommand <IRoutableViewModel, IRoutableViewModel>(
                HostScreen.Router.Navigate);

            var searchChanged = this
                                .WhenAnyValue(x => x.SearchTerm)
                                .Throttle(TimeSpan.FromSeconds(1), TaskPoolScheduler)
                                .DistinctUntilChanged()
                                .SubscribeOn(TaskPoolScheduler)
                                .ObserveOn(TaskPoolScheduler)
                                .Publish();

            searchChanged
            .Where(searchTerm => !string.IsNullOrWhiteSpace(searchTerm))
            .Select(_ => 1)
            .SubscribeOn(TaskPoolScheduler)
            .ObserveOn(TaskPoolScheduler)
            .InvokeCommand(GetMovies);

            searchChanged
            .Skip(1)
            .Where(searchTerm => string.IsNullOrWhiteSpace(searchTerm))
            .Select(_ => 1)
            .SubscribeOn(TaskPoolScheduler)
            .ObserveOn(TaskPoolScheduler)
            .InvokeCommand(GetUpcomingMovies);

            searchChanged
            .Connect();

            GetUpcomingMovies
            .ThrownExceptions
            .Merge(GetMovies.ThrownExceptions)
            .Subscribe(ex =>
            {
                Console.WriteLine(ex);
            });
        }