public SelectedToolViewModel(UIView toolboxView, AvailableToolsContainerViewController container, MeetingViewModel meeting, IReactiveList<IToolViewModel> selectedTools, NavigationPaneViewModel navigationPane)
            {
                SelectedTools = selectedTools;

                IsEmpty = SelectedTools.Count == 0;
                SelectedTools.Changed.ObserveOn(RxApp.MainThreadScheduler)
                             .Subscribe(p =>
                                        {
                                            IsEmpty = SelectedTools.Count == 0;
                                        });

                var showAvailableToolsCommand = new ReactiveCommand();
                showAvailableToolsCommand.ObserveOn(RxApp.MainThreadScheduler).Subscribe(_ =>
                {
                    UIView.BeginAnimations(null);
                    UIView.SetAnimationDuration(0.25);
                    toolboxView.Alpha = 1.0f;
                    UIView.CommitAnimations();
                });

                container.CloseToolboxRequested += (s, e) =>
                                                   {
                                                       UIView.BeginAnimations(null);
                                                       UIView.SetAnimationDuration(0.25);
                                                       toolboxView.Alpha = 0.0f;
                                                       UIView.CommitAnimations();
                                                   };
                ShowAvailableToolsCommand = showAvailableToolsCommand;
                navigationPane.ShowToolLibraryAction = () => ShowAvailableToolsCommand.Execute(null);

                var setActiveToolsCommand = new ReactiveCommand();
                setActiveToolsCommand.ObserveOn(RxApp.MainThreadScheduler)
                    .Subscribe(tool => meeting.ActiveTool = (IToolViewModel)tool);
                SetActiveToolCommand = setActiveToolsCommand;
            }
        public AgentMeetingViewModel(
            IAgentConnection agentConnection, 
            ISharedDataService sharedDataService,
            INavigationService navigation,
            IViewModelLocator locator,
            IPlatformServices platformServices)
        {
            _sharedDataService = sharedDataService;
            _agentConnection = agentConnection;
            NavigationPane = locator.NavigationPaneViewModel;

            var startcmd = new ReactiveCommand(this.WhenAnyValue(vm => vm.MeetingStarted, vm => vm.Meeting.VideoConf.VideoInitCompleted, vm => vm.Meeting, (started, video, mtg) => !started && mtg != null));
            _startMeetingSub = startcmd.RegisterAsyncTask(async _ =>
                                                                {
                                    MeetingStarted = true;
                                    Meeting.VideoConf.Config = await _agentConnection.StartMeeting(Meeting.Id);
                                }).Subscribe();

            var endcmd = new ReactiveCommand(this.WhenAnyValue(vm => vm.MeetingStarted, vm => vm.Meeting.VideoConf.VideoInitCompleted, (meetingStarted, videoStarted) => meetingStarted && videoStarted));
            _endMeetingSub = endcmd.RegisterAsyncAction(_ => navigation.BackCommand.Execute(null)).Subscribe();

            StartMeetingCommand = startcmd;
            EndMeetingCommand = endcmd;

            _agentConnection.ClientInMeeting.ToProperty(this, t => t.IsClientInMeeting, out _isClientInMeeting);

            
            var savePdfCmd = new ReactiveCommand(this.WhenAnyValue(vm => vm.MeetingStarted, vm => vm.Meeting.VideoConf.VideoInitCompleted, (meetingStarted, videoStarted) => meetingStarted && videoStarted));
            _pdfSub = savePdfCmd.RegisterAsyncTask(async _ =>
                                                         {
                                                            await _agentConnection.GenerateIllustration(Meeting.Id, _sharedDataService.Person);
                                               }).Subscribe();

            _pdfAvailableSub = _agentConnection.PdfAvailable.ObserveOn(RxApp.MainThreadScheduler).Subscribe(async p =>
                                                    {
                                                        var result = await _agentConnection.GetIllustrationPdfAsync(p);
                                                        await platformServices.SaveAndLaunchFile(new System.IO.MemoryStream(result), "pdf");
                                                    });

            SavePdfCommand = savePdfCmd;


            _titleSub = this.WhenAnyValue(
                vm => vm.Meeting.Client,
                (client) =>
                string.Format("Meeting with {0}",
                              client.FullName)
                )
                            .ObserveOn(RxApp.MainThreadScheduler)
                            .Subscribe(t => Title = t);

            MeetingStatus = GetMeetingStatusString(IsClientInMeeting, MeetingStarted);
            _meetingStatusSub = this.WhenAnyValue(
                         vm => vm.MeetingStarted,
                         vm => vm.IsClientInMeeting,
                         (started, clientIn) => GetMeetingStatusString(clientIn, started))
                         .ObserveOn(RxApp.MainThreadScheduler)
                         .Subscribe(t => MeetingStatus = t);

            //_titleSub = this.WhenAnyValue(
            //             vm => vm.Meeting.Client,
            //             vm => vm.MeetingStarted,
            //             vm => vm.IsClientInMeeting,
            //             (client, started, clientIn) =>
            //                 string.Format("Meeting with {0}. Started: {1} Client Joined: {2}",
            //                    client.FullName, started, clientIn)
            //             )
            //             .ObserveOn(RxApp.MainThreadScheduler)
            //             .Subscribe(t => Title = t);


            // When the meeting's active tool changes, set the Tool and page number
            // into the shared state so it'll be propagated.

            // Get an observable for the currently set tool
            var activeToolObs = this.WhenAnyValue(vm => vm.Meeting.ActiveTool)
                .Where(t => t != null);

            // Every time the tool changes, watch the new tool's CurrentPageNumber
            // for changes.
            //
            // When we get a change, convert that into a ToolIdAndPageNumber, bringing in
            // the owning tool id.
            var pageChangedObs = activeToolObs
                 .Select(t => t.WhenAnyValue(v => v.CurrentPageNumber, 
                                    p => new ToolIdAndPageNumber { ToolId = t.ToolId, PageNumber = p})
                        )
                 .Switch() // Only listen to the most recent sequence of property changes (active tool)
                 .Log(this, "Current Page Changed", t => string.Format("Tool: {0}, Page: {1}", t.ToolId, t.PageNumber));
         
            // Every time the tool changes, select the tool id and current page number
            var toolChangedObs = activeToolObs
                .Select(t => new ToolIdAndPageNumber { ToolId = t.ToolId, PageNumber = t.CurrentPageNumber })
                .Log(this, "Tool Changed", t => string.Format("Tool: {0}, Page: {1}", t.ToolId, t.PageNumber));

            
            // Merge them together - tool changes and current page of the tool
            _meetingStateSub = toolChangedObs
                .Merge(pageChangedObs)
                .Subscribe(t => sharedDataService.MeetingState.State = t);

        }
        public AgentMeetingViewModel(
            IAgentConnection agentConnection,
            ISharedDataService sharedDataService,
            INavigationService navigation,
            IViewModelLocator locator,
            IPlatformServices platformServices)
        {
            _sharedDataService = sharedDataService;
            _agentConnection   = agentConnection;
            NavigationPane     = locator.NavigationPaneViewModel;

            var startcmd = new ReactiveCommand(this.WhenAnyValue(vm => vm.MeetingStarted, vm => vm.Meeting.VideoConf.VideoInitCompleted, vm => vm.Meeting, (started, video, mtg) => !started && mtg != null));

            _startMeetingSub = startcmd.RegisterAsyncTask(async _ =>
            {
                MeetingStarted           = true;
                Meeting.VideoConf.Config = await _agentConnection.StartMeeting(Meeting.Id);
            }).Subscribe();

            var endcmd = new ReactiveCommand(this.WhenAnyValue(vm => vm.MeetingStarted, vm => vm.Meeting.VideoConf.VideoInitCompleted, (meetingStarted, videoStarted) => meetingStarted && videoStarted));

            _endMeetingSub = endcmd.RegisterAsyncAction(_ => navigation.BackCommand.Execute(null)).Subscribe();

            StartMeetingCommand = startcmd;
            EndMeetingCommand   = endcmd;

            _agentConnection.ClientInMeeting.ToProperty(this, t => t.IsClientInMeeting, out _isClientInMeeting);


            var savePdfCmd = new ReactiveCommand(this.WhenAnyValue(vm => vm.MeetingStarted, vm => vm.Meeting.VideoConf.VideoInitCompleted, (meetingStarted, videoStarted) => meetingStarted && videoStarted));

            _pdfSub = savePdfCmd.RegisterAsyncTask(async _ =>
            {
                await _agentConnection.GenerateIllustration(Meeting.Id, _sharedDataService.Person);
            }).Subscribe();

            _pdfAvailableSub = _agentConnection.PdfAvailable.ObserveOn(RxApp.MainThreadScheduler).Subscribe(async p =>
            {
                var result = await _agentConnection.GetIllustrationPdfAsync(p);
                await platformServices.SaveAndLaunchFile(new System.IO.MemoryStream(result), "pdf");
            });

            SavePdfCommand = savePdfCmd;


            _titleSub = this.WhenAnyValue(
                vm => vm.Meeting.Client,
                (client) =>
                string.Format("Meeting with {0}",
                              client.FullName)
                )
                        .ObserveOn(RxApp.MainThreadScheduler)
                        .Subscribe(t => Title = t);

            MeetingStatus     = GetMeetingStatusString(IsClientInMeeting, MeetingStarted);
            _meetingStatusSub = this.WhenAnyValue(
                vm => vm.MeetingStarted,
                vm => vm.IsClientInMeeting,
                (started, clientIn) => GetMeetingStatusString(clientIn, started))
                                .ObserveOn(RxApp.MainThreadScheduler)
                                .Subscribe(t => MeetingStatus = t);

            //_titleSub = this.WhenAnyValue(
            //             vm => vm.Meeting.Client,
            //             vm => vm.MeetingStarted,
            //             vm => vm.IsClientInMeeting,
            //             (client, started, clientIn) =>
            //                 string.Format("Meeting with {0}. Started: {1} Client Joined: {2}",
            //                    client.FullName, started, clientIn)
            //             )
            //             .ObserveOn(RxApp.MainThreadScheduler)
            //             .Subscribe(t => Title = t);


            // When the meeting's active tool changes, set the Tool and page number
            // into the shared state so it'll be propagated.

            // Get an observable for the currently set tool
            var activeToolObs = this.WhenAnyValue(vm => vm.Meeting.ActiveTool)
                                .Where(t => t != null);

            // Every time the tool changes, watch the new tool's CurrentPageNumber
            // for changes.
            //
            // When we get a change, convert that into a ToolIdAndPageNumber, bringing in
            // the owning tool id.
            var pageChangedObs = activeToolObs
                                 .Select(t => t.WhenAnyValue(v => v.CurrentPageNumber,
                                                             p => new ToolIdAndPageNumber {
                ToolId = t.ToolId, PageNumber = p
            })
                                         )
                                 .Switch() // Only listen to the most recent sequence of property changes (active tool)
                                 .Log(this, "Current Page Changed", t => string.Format("Tool: {0}, Page: {1}", t.ToolId, t.PageNumber));

            // Every time the tool changes, select the tool id and current page number
            var toolChangedObs = activeToolObs
                                 .Select(t => new ToolIdAndPageNumber {
                ToolId = t.ToolId, PageNumber = t.CurrentPageNumber
            })
                                 .Log(this, "Tool Changed", t => string.Format("Tool: {0}, Page: {1}", t.ToolId, t.PageNumber));


            // Merge them together - tool changes and current page of the tool
            _meetingStateSub = toolChangedObs
                               .Merge(pageChangedObs)
                               .Subscribe(t => sharedDataService.MeetingState.State = t);
        }