public TimelineViewModel(AudioCanvasViewModel audioCanvasViewModel,
            DescriptionCanvasViewModel descriptionCanvasViewModel,
            MediaViewModel mediaViewModel,
            NumberLineViewModel numberLineViewModel,
            ProjectManager projectManager)
        {
            _audioCanvasViewModel = audioCanvasViewModel;
            _descriptionCanvasViewModel = descriptionCanvasViewModel;
            _mediaViewModel = mediaViewModel;
            _numberLineViewModel = numberLineViewModel;
            _projectManager = projectManager;

            InitCommands();
        }
        public MainWindow()
        {
            var splashscreen = new SplashScreen("../Resources/Images/LiveDescribe-Splashscreen.png");
            splashscreen.Show(true);
            CustomResources.LoadResources();

            if (!Defines.Debug)
                System.Threading.Thread.Sleep(2000);

            Settings.Default.Upgrade();
            Settings.Default.InitializeDefaultValuesIfNull();

            InitializeComponent();

            //check which exporting options are available, depending on build
            if (Defines.Zagga)
            {
                ExportWithVideo.Visibility = Visibility.Visible;
                ExportAudioOnly.Visibility = Visibility.Collapsed;
            }
            else
            {
                ExportWithVideo.Visibility = Visibility.Collapsed;
                ExportAudioOnly.Visibility = Visibility.Visible;
            }

            _videoMedia = MediaControl.VideoMedia;

            var mainWindowViewModel = new MainViewModel(_videoMedia);

            DataContext = mainWindowViewModel;
            _mainViewModel = mainWindowViewModel;

            _mediaViewModel = mainWindowViewModel.MediaViewModel;
            _projectManager = mainWindowViewModel.ProjectManager;
            _intervalInfoListViewModel = mainWindowViewModel.IntervalInfoListViewModel;

            SetRecentDocumentsList();

            #region Event Listeners for VideoMedia
            //if the videomedia's path changes (a video is added)
            //then play and stop the video to load the video so the VideoOpenedRequest event gets fired
            //this is done because the MediaElement does not load the video until it is played
            //therefore you can't know the duration of the video or if it hasn't been loaded properly unless it fails
            //I know this is a little hackish, but it's a consequence of how the MediaElement works
            _videoMedia.PathChangedEvent += (sender, e) =>
                {
                    _videoMedia.Play();
                    _videoMedia.Pause();
                };
            #endregion

            #region Event Listeners For MainViewModel (Pause, Play, Mute)
            //These events are put inside the main control because they will also effect the list
            //of audio descriptions an instance of DescriptionCollectionViewModel is inside the main control
            //and the main control will take care of synchronizing the video, and the descriptions

            //listens for PlayRequested Event
            mainWindowViewModel.PlayRequested += (sender, e) => CommandManager.InvalidateRequerySuggested();

            //listens for PauseRequested Event
            mainWindowViewModel.PauseRequested += (sender, e) => CommandManager.InvalidateRequerySuggested();

            //listens for when the media has gone all the way to the end
            mainWindowViewModel.MediaEnded += (sender, e) =>
            {
                TimelineControl.ResetMarkerPosition();
                //this is to recheck all the graphics states
                CommandManager.InvalidateRequerySuggested();
            };

            mainWindowViewModel.GraphicsTick += Play_Tick;

            mainWindowViewModel.PlayingDescription += (sender, args) =>
            {
                try
                {
                    if (args.Value.IsExtendedDescription)
                        DispatcherHelper.UIDispatcher.Invoke(() =>
                            SpaceAndDescriptionsTabControl.ExtendedDescriptionsListView.ScrollToCenterOfView(args.Value));
                    else
                        DispatcherHelper.UIDispatcher.Invoke(() =>
                       SpaceAndDescriptionsTabControl.DescriptionsListView.ScrollToCenterOfView(args.Value));
                }
                catch (Exception exception)
                {
                    Log.Warn("Task Cancelled exception", exception);
                }
            };
            #endregion

            #region Event Listeners For MediaViewModel

            mainWindowViewModel.MediaViewModel.VideoOpenedRequested += (sender, e) =>
            {
                //Video gets played and paused so you can seek initially when the video gets loaded
                _videoMedia.Play();
                _videoMedia.Pause();
            };

            #endregion

            #region DescriptionCanvas Events
            //If one canvas is clicked, we want to unselect the other canvas' selection
            TimelineControl.DescriptionCanvas.MouseLeftButtonDown += (sender, args) =>
            {
                if (TimelineControl.AudioCanvas.MouseAction == IntervalMouseAction.ItemSelected)
                    TimelineControl.AudioCanvas.ClearMouseSelection();
            };

            TimelineControl.DescriptionCanvas.MouseLeftButtonUp += (sender, args) =>
            {
                if (TimelineControl.DescriptionCanvas.MouseAction == IntervalMouseAction.None)
                    _intervalInfoListViewModel.ClearSelection();
            };
            #endregion

            #region AudioCanvas Events
            TimelineControl.AudioCanvas.MouseLeftButtonDown += (sender, args) =>
            {
                if (TimelineControl.DescriptionCanvas.MouseAction == IntervalMouseAction.ItemSelected)
                    TimelineControl.DescriptionCanvas.ClearMouseSelection();
            };

            TimelineControl.AudioCanvas.MouseLeftButtonUp += (sender, args) =>
            {
                if (TimelineControl.AudioCanvas.MouseAction == IntervalMouseAction.None)
                    _intervalInfoListViewModel.ClearSelection();
            };
            #endregion

            #region Event Handlers for ProjectManager

            //When a description is added, attach an event to the StartInVideo and EndInVideo properties
            //so when those properties change it redraws them
            _projectManager.AllDescriptions.CollectionChanged += (sender, e) =>
            {
                if (e.Action != NotifyCollectionChangedAction.Add)
                    return;

                foreach (Description d in e.NewItems)
                    AddDescriptionEventHandlers(d);
            };

            _projectManager.Spaces.CollectionChanged += (sender, e) =>
            {
                if (e.Action == NotifyCollectionChangedAction.Add)
                {
                    foreach (Space space in e.NewItems)
                        AddSpaceEventHandlers(space);
                }
            };
            #endregion

            #region Event Handlers for Settings
            Settings.Default.RecentProjects.CollectionChanged += (sender, args) => SetRecentDocumentsList();
            #endregion
        }
        public MainViewModel(ILiveDescribePlayer mediaVideo)
        {
            DispatcherHelper.Initialize();

            _undoRedoManager = new UndoRedoManager();
            _loadingViewModel = new LoadingViewModel(100, null, 0, false);
            _projectManager = new ProjectManager(_loadingViewModel, _undoRedoManager);
            _descriptionRecordingViewModel = new DescriptionRecordingViewModel(mediaVideo,
                _projectManager);
            _mediaViewModel = new MediaViewModel(mediaVideo, _projectManager);
            _preferences = new PreferencesViewModel();
            _intervalInfoListViewModel = new IntervalInfoListViewModel(_projectManager, _descriptionRecordingViewModel);
            _markingSpacesViewModel = new MarkingSpacesViewModel(_intervalInfoListViewModel, mediaVideo, _undoRedoManager);
            _audioCanvasViewModel = new AudioCanvasViewModel(mediaVideo, _projectManager, _undoRedoManager);
            _descriptionCanvasViewModel = new DescriptionCanvasViewModel(mediaVideo, _projectManager, _undoRedoManager);
            _numberLineViewModel = new NumberLineViewModel(mediaVideo);
            _timelineViewModel = new TimelineViewModel(_audioCanvasViewModel, _descriptionCanvasViewModel, _mediaViewModel,
                _numberLineViewModel, _projectManager);

            _mediaVideo = mediaVideo;

            DescriptionPlayer = new DescriptionPlayer();
            DescriptionPlayer.DescriptionFinishedPlaying += (sender, e) =>
            {
                try
                {
                    DispatcherHelper.UIDispatcher.Invoke(() =>
                        _mediaViewModel.ResumeFromDescription(e.Value));
                }
                catch (TaskCanceledException exception)
                {
                    Log.Warn("Task Canceled Exception", exception);
                }
            };

            #region Commands
            //Commands
            CloseProject = new RelayCommand(
                canExecute: () => _projectManager.HasProjectLoaded,
                execute: () =>
                {
                    if (_projectManager.IsProjectModified)
                    {
                        var result = MessageBoxFactory.ShowWarningQuestion(
                            string.Format(UiStrings.MessageBox_Format_SaveProjectWarning, _project.ProjectName));

                        if (result == MessageBoxResult.Yes)
                            SaveProject.Execute();
                        else if (result == MessageBoxResult.Cancel)
                            return;
                    }

                    _projectManager.CloseProject();
                });

            NewProject = new RelayCommand(() =>
            {
                var viewModel = DialogShower.SpawnNewProjectView();

                if (viewModel.DialogResult != true)
                    return;

                if (viewModel.CopyVideo)
                    CopyVideoAndSetProject(viewModel.VideoPath, viewModel.Project);
                else
                    SetProject(viewModel.Project);
            });

            OpenProject = new RelayCommand(() =>
            {
                var projectChooser = new OpenFileDialog
                {
                    Filter = string.Format(UiStrings.OpenFileDialog_Format_OpenProject, Project.Names.ProjectExtension)
                };

                bool? dialogSuccess = projectChooser.ShowDialog();
                if (dialogSuccess != true)
                    return;

                OpenProjectPath.Execute(projectChooser.FileName);
            });

            OpenProjectPath = new RelayCommand<string>(path =>
            {
                //Attempt to read project. If object fields are missing, an error window pops up.
                try
                {
                    Project p = FileReader.ReadProjectFile(path);
                    SetProject(p);
                }
                catch (JsonSerializationException)
                {
                    MessageBoxFactory.ShowError(UiStrings.MessageBox_OpenProjectFileMissingError);
                }
                catch (DirectoryNotFoundException e)
                {
                    Log.Warn("Directory not found while trying to open project", e);
                    MessageBoxFactory.ShowError(UiStrings.MessageBox_DirectoryNotFoundError);
                }
                catch (FileNotFoundException e)
                {
                    Log.Warn("FileNotFound while trying to open project", e);
                    MessageBoxFactory.ShowError(string.Format(UiStrings.MessageBox_Format_FileNotFoundError,
                        e.FileName));
                }
            });

            ClearRecentProjects = new RelayCommand(() =>
            {
                Settings.Default.RecentProjects.Clear();
                Settings.Default.Save();
            });

            ShowImportAudioDescription = new RelayCommand(
                canExecute: () => _projectManager.HasProjectLoaded,
                execute: () =>
                {
                    var viewModel = DialogShower.SpawnImportAudioDescriptionView(_projectManager, _mediaVideo.DurationMilliseconds);
                }
               );

            SaveProject = new RelayCommand(
                canExecute: () => _projectManager.IsProjectModified,
                execute: () => _projectManager.SaveProject()
            );

            ExportWithDescriptions = new RelayCommand(
                canExecute: () => _projectManager.HasProjectLoaded,
                execute: () =>
                {
                    var viewModel = DialogShower.SpawnExportWindowView(_project, _mediaVideo.Path,
                        _mediaVideo.DurationSeconds, _projectManager.AllDescriptions.ToList(),
                        _loadingViewModel);

                    if (viewModel.DialogResult != true)
                        return;
                });

            ClearCache = new RelayCommand(
                canExecute: () => _projectManager.HasProjectLoaded,
                execute: () =>
                {
                    var p = _project;

                    CloseProject.Execute();

                    Directory.Delete(p.Folders.Cache, true);

                    SetProject(p);
                });

            ShowPreferences = new RelayCommand(() =>
            {
                _preferences.RetrieveApplicationSettings();
                var preferencesWindow = new PreferencesWindow(_preferences);
                preferencesWindow.ShowDialog();
            });

            FindSpaces = new RelayCommand(
                canExecute: () => _projectManager.HasProjectLoaded,
                execute: () =>
                {
                    var spaces = AudioAnalyzer.FindSpaces(_mediaViewModel.Waveform);
                    _projectManager.Spaces.AddRange(spaces);
                }
            );

            ExportDescriptionsTextToSrt = new RelayCommand(
                canExecute: () => _projectManager.HasProjectLoaded,
                execute: () =>
                {
                    var saveFileDialog = new SaveFileDialog
                    {
                        FileName = Path.GetFileNameWithoutExtension(_mediaViewModel.Path),
                        Filter = UiStrings.SaveFileDialog_ExportToSrt
                    };

                    saveFileDialog.ShowDialog();
                    FileWriter.WriteDescriptionsTextToSrtFile(saveFileDialog.FileName,
                        _projectManager.AllDescriptions);
                }
            );

            ExportSpacesTextToSrt = new RelayCommand(
                canExecute: () => _projectManager.HasProjectLoaded,
                execute: () =>
                {
                    var saveFileDialog = new SaveFileDialog
                    {
                        FileName = Path.GetFileNameWithoutExtension(_mediaViewModel.Path),
                        Filter = UiStrings.SaveFileDialog_ExportToSrt
                    };

                    saveFileDialog.ShowDialog();
                    FileWriter.WriteSpacesTextToSrtFile(saveFileDialog.FileName, _projectManager.Spaces);
                }
            );

            ShowDescriptionFolder = new RelayCommand(
                canExecute: () => _projectManager.HasProjectLoaded,
                execute: () =>
                {
                    var pfi = new ProcessStartInfo("Explorer.exe", _project.Folders.Descriptions.AbsolutePath);
                    Process.Start(pfi);
                }
            );

            ShowAboutInfo = new RelayCommand(DialogShower.SpawnAboutInfoView);
            #endregion

            //If apply requested happens  in the preferences use the new saved microphone in the settings
            _descriptiontimer = new Timer(10);
            _descriptiontimer.Elapsed += Play_Tick;
            _descriptiontimer.AutoReset = true;

            #region MediaViewModel Events
            _mediaViewModel.PlayRequested += (sender, e) =>
            {
                _mediaVideo.Play();
                _descriptiontimer.Start();
                //this Handler should be attached to the view to update the graphics
                OnPlayRequested(sender, e);
            };

            _mediaViewModel.PauseRequested += (sender, e) =>
            {
                _mediaVideo.Pause();
                _descriptiontimer.Stop();
                if (_lastRegularDescriptionPlayed != null && _lastRegularDescriptionPlayed.IsPlaying)
                    DescriptionPlayer.Stop();
                //this Handler should be attached to the view to update the graphics
                OnPauseRequested(sender, e);
            };

            _mediaViewModel.OnPausedForExtendedDescription += (sender, e) =>
            {
                _mediaVideo.Pause();
                _descriptiontimer.Stop();
                CommandManager.InvalidateRequerySuggested();
            };

            _mediaViewModel.MuteRequested += OnMuteRequested;

            _mediaViewModel.MediaEndedEvent += (sender, e) =>
            {
                _descriptiontimer.Stop();
                _mediaVideo.Stop();
                OnMediaEnded(sender, e);
            };
            #endregion

            #region Property Changed Events

            _mediaViewModel.PropertyChanged += PropertyChangedHandler;

            //Update window title based on project name
            PropertyChanged += (sender, args) =>
            {
                if (args.PropertyName == "IsProjectModified")
                    SetWindowTitle();
            };

            #endregion

            #region ProjectManager Events
            _projectManager.ProjectLoaded += (sender, args) =>
            {
                _project = args.Value;

                _mediaViewModel.LoadVideo(_project.Files.Video);

                SetWindowTitle();
            };

            _projectManager.ProjectModifiedStateChanged += (sender, args) => SetWindowTitle();

            _projectManager.ProjectClosed += (sender, args) =>
            {
                TryToCleanUpUnusedDescriptionAudioFiles();
                _project = null;

                SetWindowTitle();
            };
            #endregion

            SetWindowTitle();
        }