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

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

            InitializeComponent();

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

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

            _videoMedia = MediaControl.VideoMedia;

            var mainWindowViewModel = new MainWindowViewModel(_videoMedia);

            DataContext = mainWindowViewModel;
            _mainWindowViewModel = mainWindowViewModel;

            _mediaControlViewModel = mainWindowViewModel.MediaControlViewModel;
            _projectManager = mainWindowViewModel.ProjectManager;
            _descriptionInfoTabViewModel = mainWindowViewModel.DescriptionInfoTabViewModel;

            _audioCanvas = AudioCanvasControl.AudioCanvas;
            _audioCanvas.UndoRedoManager = mainWindowViewModel.UndoRedoManager;

            _descriptionCanvas = DescriptionCanvasControl.DescriptionCanvas;
            _descriptionCanvas.UndoRedoManager = mainWindowViewModel.UndoRedoManager;

            _marker = MarkerControl.Marker;

            _millisecondsTimeConverter = new MillisecondsTimeConverterFormatter();

            SetRecentDocumentsList();

            #region TimeLineScrollViewer Event Listeners
            TimeLineScrollViewer.ScrollChanged += (sender, e) =>
            {
                DrawWaveForm();
                AddLinesToNumberTimeLine();
            };
            #endregion

            #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 MainWindowViewModel (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) =>
                {
                    UpdateMarkerPosition(-MarkerOffset);
                    //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 MediaControlViewModel

            //listens for VideoOpenedRequested event
            //this event only gets thrown when if the MediaFailed event doesn't occur
            //and as soon as the video is loaded when play is pressed
            mainWindowViewModel.MediaControlViewModel.VideoOpenedRequested += (sender, e) =>
                {
                    _videoDuration = _videoMedia.NaturalDuration.TimeSpan.TotalMilliseconds;
                    AudioCanvasControl.AudioCanvas.VideoDuration = _videoDuration;
                    DescriptionCanvasControl.DescriptionCanvas.VideoDuration = _videoDuration;
                    _canvasWidth = CalculateWidth();
                    _marker.IsEnabled = true;

                    //Video gets played and paused so you can seek initially when the video gets loaded
                    _videoMedia.Play();
                    _videoMedia.Pause();

                    SetTimeline();

                    foreach (var desc in _projectManager.AllDescriptions)
                        DrawDescribableInterval(desc);

                    foreach (var space in _projectManager.Spaces)
                        DrawDescribableInterval(space);
                };

            //captures the mouse when a mousedown request is sent to the Marker
            mainWindowViewModel.MediaControlViewModel.OnMarkerMouseDownRequested += (sender, e) => _marker.CaptureMouse();

            //updates the video position when the mouse is released on the Marker
            mainWindowViewModel.MediaControlViewModel.OnMarkerMouseUpRequested += (sender, e) => _marker.ReleaseMouseCapture();

            //updates the canvas and video position when the Marker is moved
            mainWindowViewModel.MediaControlViewModel.OnMarkerMouseMoveRequested += (sender, e) =>
                {
                    if (!_marker.IsMouseCaptured) return;

                    if (ScrollRightIfCanForGraphicsThread(Canvas.GetLeft(_marker)))
                        return;

                    if (ScrollLeftIfCanForGraphicsThread(Canvas.GetLeft(_marker)))
                        return;

                    var xPosition = Mouse.GetPosition(_audioCanvas).X;
                    var middleOfMarker = xPosition - MarkerOffset;

                    //make sure the middle of the marker doesn't go below the beginning of the canvas
                    if (xPosition < -MarkerOffset)
                    {
                        Canvas.SetLeft(_marker, -MarkerOffset);
                        UpdateVideoPosition(0);
                        return;
                    }

                    var newPositionInVideo = (xPosition / _canvasWidth) * _videoDuration;
                    if (newPositionInVideo >= _videoDuration)
                    {
                        var newPositionOfMarker = (_canvasWidth / _videoDuration) * (_videoDuration);
                        Canvas.SetLeft(_marker, newPositionOfMarker - MarkerOffset);
                        UpdateVideoPosition((int)(_videoDuration));
                        return;
                    }
                    Canvas.SetLeft(_marker, middleOfMarker);
                    UpdateVideoPosition((int)newPositionInVideo);
                };

            #endregion

            #region Event Listeners For AudioCanvasViewModel
            AudioCanvasViewModel audioCanvasViewModel = mainWindowViewModel.AudioCanvasViewModel;
            audioCanvasViewModel.AudioCanvasMouseDownEvent += AudioCanvas_OnMouseDown;
            audioCanvasViewModel.AudioCanvasMouseRightButtonDownEvent += AudioCanvas_RecordRightClickPosition;

            _mainWindowViewModel.AudioCanvasViewModel.RequestSpaceTime += (sender, args) =>
            {
                var space = args.Value;

                double middle = _rightClickPointOnAudioCanvas.X;  // going to be the middle of the space
                double middleTime = (_videoDuration / _audioCanvas.Width) * middle;  // middle of the space in milliseconds
                double starttime = middleTime - (DefaultSpaceLengthInMilliSeconds / 2);
                double endtime = middleTime + (DefaultSpaceLengthInMilliSeconds / 2);

                //Bounds checking when creating a space
                if (starttime >= 0 && endtime <= _videoDuration)
                {
                    space.StartInVideo = starttime;
                    space.EndInVideo = endtime;
                }
                else if (starttime < 0 && endtime > _videoDuration)
                {
                    space.StartInVideo = 0;
                    space.EndInVideo = _videoDuration;
                }
                else if (starttime < 0)
                {
                    space.StartInVideo = 0;
                    space.EndInVideo = endtime;
                }
                else if (endtime > _videoDuration)
                {
                    space.StartInVideo = starttime;
                    space.EndInVideo = _videoDuration;
                }
            };
            #endregion

            #region Event Listeners For DescriptionCanvasViewModel
            DescriptionCanvasViewModel descriptionCanvasViewModel = mainWindowViewModel.DescriptionCanvasViewModel;
            descriptionCanvasViewModel.DescriptionCanvasMouseDownEvent += DescriptionCanvas_MouseDown;
            #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);
                }
            };

            _projectManager.ProjectLoaded += (sender, e) => SetTimeline();

            _projectManager.ProjectClosed += (sender, e) =>
            {
                _audioCanvas.Children.Clear();
                NumberTimeline.Children.Clear();

                UpdateMarkerPosition(-MarkerOffset);
                _marker.IsEnabled = false;
            };
            #endregion

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

            _undoRedoManager = new UndoRedoManager();
            _loadingViewModel = new LoadingViewModel(100, null, 0, false);
            _projectManager = new ProjectManager(_loadingViewModel, _undoRedoManager);
            _descriptionRecordingControlViewModel = new DescriptionRecordingControlViewModel(mediaVideo,
                _projectManager);
            _mediaControlViewModel = new MediaControlViewModel(mediaVideo, _projectManager);
            _preferences = new PreferencesViewModel();
            _descriptionInfoTabViewModel = new DescriptionInfoTabViewModel(_projectManager, _descriptionRecordingControlViewModel);
            _markingSpacesControlViewModel = new MarkingSpacesControlViewModel(_descriptionInfoTabViewModel, mediaVideo, _undoRedoManager);
            _audioCanvasViewModel = new AudioCanvasViewModel(mediaVideo, _projectManager);
            _descriptionCanvasViewModel = new DescriptionCanvasViewModel(mediaVideo, _projectManager);

            _mediaVideo = mediaVideo;

            DescriptionPlayer = new DescriptionPlayer();
            DescriptionPlayer.DescriptionFinishedPlaying += (sender, e) =>
            {
                try
                {
                    DispatcherHelper.UIDispatcher.Invoke(() =>
                        _mediaControlViewModel.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(_mediaControlViewModel.Waveform);
                    _projectManager.Spaces.AddRange(spaces);
                }
            );

            ExportDescriptionsTextToSrt = new RelayCommand(
                canExecute: () => _projectManager.HasProjectLoaded,
                execute: () =>
                {
                    var saveFileDialog = new SaveFileDialog
                    {
                        FileName = Path.GetFileNameWithoutExtension(_mediaControlViewModel.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(_mediaControlViewModel.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 MediaControlViewModel Events
            _mediaControlViewModel.PlayRequested += (sender, e) =>
            {
                _mediaVideo.Play();
                _descriptiontimer.Start();
                //this Handler should be attached to the view to update the graphics
                OnPlayRequested(sender, e);
            };

            _mediaControlViewModel.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);
            };

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

            _mediaControlViewModel.MuteRequested += OnMuteRequested;

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

            #region Property Changed Events

            _mediaControlViewModel.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;

                _mediaControlViewModel.LoadVideo(_project.Files.Video);

                SetWindowTitle();
            };

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

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

                SetWindowTitle();
            };
            #endregion

            SetWindowTitle();
        }