using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Linq; using System.Threading.Tasks; using BinaryObjectScanner; using MPF.Frontend.ComboBoxItems; using MPF.Frontend.Tools; using SabreTools.RedumpLib.Data; namespace MPF.Frontend.ViewModels { /// /// Constructor /// public class CheckDumpViewModel : INotifyPropertyChanged { #region Fields /// /// Access to the current options /// public Frontend.Options Options { get => _options; } private readonly Frontend.Options _options; /// /// Indicates if SelectionChanged events can be executed /// public bool CanExecuteSelectionChanged { get; private set; } = false; /// public event PropertyChangedEventHandler? PropertyChanged; #endregion #region Properties /// /// Currently selected system value /// public RedumpSystem? CurrentSystem { get => _currentSystem; set { _currentSystem = value; TriggerPropertyChanged(nameof(CurrentSystem)); } } private RedumpSystem? _currentSystem; /// /// Indicates the status of the system type combo box /// public bool SystemTypeComboBoxEnabled { get => _systemTypeComboBoxEnabled; set { _systemTypeComboBoxEnabled = value; TriggerPropertyChanged(nameof(SystemTypeComboBoxEnabled)); } } private bool _systemTypeComboBoxEnabled; /// /// Currently selected media type value /// public MediaType? CurrentMediaType { get => _currentMediaType; set { _currentMediaType = value; TriggerPropertyChanged(nameof(CurrentMediaType)); } } private MediaType? _currentMediaType; /// /// Indicates the status of the media type combo box /// public bool MediaTypeComboBoxEnabled { get => _mediaTypeComboBoxEnabled; set { _mediaTypeComboBoxEnabled = value; TriggerPropertyChanged(nameof(MediaTypeComboBoxEnabled)); } } private bool _mediaTypeComboBoxEnabled; /// /// Currently provided input path /// public string? InputPath { get => _inputPath; set { _inputPath = value; TriggerPropertyChanged(nameof(InputPath)); } } private string? _inputPath; /// /// Indicates the status of the input path text box /// public bool InputPathTextBoxEnabled { get => _inputPathTextBoxEnabled; set { _inputPathTextBoxEnabled = value; TriggerPropertyChanged(nameof(InputPathTextBoxEnabled)); } } private bool _inputPathTextBoxEnabled; /// /// Indicates the status of the input path browse button /// public bool InputPathBrowseButtonEnabled { get => _inputPathBrowseButtonEnabled; set { _inputPathBrowseButtonEnabled = value; TriggerPropertyChanged(nameof(InputPathBrowseButtonEnabled)); } } private bool _inputPathBrowseButtonEnabled; /// /// Currently selected dumping program /// public InternalProgram CurrentProgram { get => _currentProgram; set { _currentProgram = value; TriggerPropertyChanged(nameof(CurrentProgram)); } } private InternalProgram _currentProgram; /// /// Indicates the status of the dumping program combo box /// public bool DumpingProgramComboBoxEnabled { get => _dumpingProgramComboBoxEnabled; set { _dumpingProgramComboBoxEnabled = value; TriggerPropertyChanged(nameof(DumpingProgramComboBoxEnabled)); } } private bool _dumpingProgramComboBoxEnabled; /// /// Indicates the status of the check dump button /// public bool CheckDumpButtonEnabled { get => _checkDumpButtonEnabled; set { _checkDumpButtonEnabled = value; TriggerPropertyChanged(nameof(CheckDumpButtonEnabled)); } } private bool _checkDumpButtonEnabled; /// /// Indicates the status of the cancel button /// public bool CancelButtonEnabled { get => _cancelButtonEnabled; set { _cancelButtonEnabled = value; TriggerPropertyChanged(nameof(CancelButtonEnabled)); } } private bool _cancelButtonEnabled; #endregion #region List Properties /// /// Current list of supported media types /// public List>? MediaTypes { get => _mediaTypes; set { _mediaTypes = value; TriggerPropertyChanged(nameof(MediaTypes)); } } private List>? _mediaTypes; /// /// Current list of supported system profiles /// public List Systems { get => _systems; set { _systems = value; TriggerPropertyChanged(nameof(Systems)); } } private List _systems; /// /// List of available internal programs /// public List> InternalPrograms { get => _internalPrograms; set { _internalPrograms = value; TriggerPropertyChanged(nameof(InternalPrograms)); } } private List> _internalPrograms; #endregion /// /// Constructor for pure view model /// public CheckDumpViewModel() { _options = OptionsLoader.LoadFromConfig(); _internalPrograms = []; _inputPath = string.Empty; _systems = []; SystemTypeComboBoxEnabled = true; InputPathTextBoxEnabled = true; InputPathBrowseButtonEnabled = true; MediaTypeComboBoxEnabled = true; DumpingProgramComboBoxEnabled = true; CheckDumpButtonEnabled = false; CancelButtonEnabled = true; MediaTypes = []; Systems = RedumpSystemComboBoxItem.GenerateElements().ToList(); InternalPrograms = []; PopulateMediaType(); PopulateInternalPrograms(); EnableEventHandlers(); } #region Property Updates /// /// Trigger a property changed event /// private void TriggerPropertyChanged(string propertyName) { // Disable event handlers temporarily bool cachedCanExecuteSelectionChanged = CanExecuteSelectionChanged; DisableEventHandlers(); // If the property change event is initialized PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); // Reenable event handlers, if necessary if (cachedCanExecuteSelectionChanged) EnableEventHandlers(); } #endregion #region UI Commands /// /// Change the currently selected system /// public void ChangeSystem() { PopulateMediaType(); this.CheckDumpButtonEnabled = ShouldEnableCheckDumpButton(); } /// /// Change the currently selected media type /// public void ChangeMediaType() { this.CheckDumpButtonEnabled = ShouldEnableCheckDumpButton(); } /// /// Change the currently selected dumping program /// public void ChangeDumpingProgram() { this.CheckDumpButtonEnabled = ShouldEnableCheckDumpButton(); } /// /// Change the currently selected input path /// public void ChangeInputPath() { this.CheckDumpButtonEnabled = ShouldEnableCheckDumpButton(); } #endregion #region UI Control /// /// Enables all UI elements that should be enabled /// private void EnableUIElements() { SystemTypeComboBoxEnabled = true; InputPathTextBoxEnabled = true; InputPathBrowseButtonEnabled = true; DumpingProgramComboBoxEnabled = true; PopulateMediaType(); CheckDumpButtonEnabled = ShouldEnableCheckDumpButton(); CancelButtonEnabled = true; } /// /// Disables all UI elements /// private void DisableUIElements() { SystemTypeComboBoxEnabled = false; InputPathTextBoxEnabled = false; InputPathBrowseButtonEnabled = false; MediaTypeComboBoxEnabled = false; DumpingProgramComboBoxEnabled = false; CheckDumpButtonEnabled = false; CancelButtonEnabled = false; } #endregion #region Population /// /// Populate media type according to system type /// private void PopulateMediaType() { // Disable other UI updates bool cachedCanExecuteSelectionChanged = CanExecuteSelectionChanged; DisableEventHandlers(); if (this.CurrentSystem != null) { var mediaTypeValues = this.CurrentSystem.MediaTypes(); int index = mediaTypeValues.FindIndex(m => m == this.CurrentMediaType); MediaTypes = mediaTypeValues.Select(m => new Element(m ?? MediaType.NONE)).ToList(); this.MediaTypeComboBoxEnabled = MediaTypes.Count > 1; this.CurrentMediaType = (index > -1 ? MediaTypes[index] : MediaTypes[0]); } else { this.MediaTypeComboBoxEnabled = false; this.MediaTypes = null; this.CurrentMediaType = null; } // Reenable event handlers, if necessary if (cachedCanExecuteSelectionChanged) EnableEventHandlers(); } /// /// Populate media type according to system type /// private void PopulateInternalPrograms() { // Disable other UI updates bool cachedCanExecuteSelectionChanged = CanExecuteSelectionChanged; DisableEventHandlers(); // Get the current internal program InternalProgram internalProgram = this.Options.InternalProgram; // Create a static list of supported Check programs, not everything var internalPrograms = new List { InternalProgram.Redumper, InternalProgram.Aaru, InternalProgram.DiscImageCreator, InternalProgram.CleanRip, InternalProgram.PS3CFW, InternalProgram.UmdImageCreator, InternalProgram.XboxBackupCreator }; InternalPrograms = internalPrograms.Select(ip => new Element(ip)).ToList(); // Select the current default dumping program int currentIndex = InternalPrograms.FindIndex(m => m == internalProgram); this.CurrentProgram = (currentIndex > -1 ? InternalPrograms[currentIndex].Value : InternalPrograms[0].Value); // Reenable event handlers, if necessary if (cachedCanExecuteSelectionChanged) EnableEventHandlers(); } #endregion #region UI Functionality private bool ShouldEnableCheckDumpButton() { return this.CurrentSystem != null && this.CurrentMediaType != null && !string.IsNullOrEmpty(this.InputPath); } /// /// Enable all textbox and combobox event handlers /// private void EnableEventHandlers() { CanExecuteSelectionChanged = true; } /// /// Disable all textbox and combobox event handlers /// private void DisableEventHandlers() { CanExecuteSelectionChanged = false; } #endregion #region MPF.Check /// /// Performs MPF.Check functionality /// /// An error message if failed, otherwise string.Empty/null public async Task CheckDump(ProcessUserInfoDelegate processUserInfo) { if (string.IsNullOrEmpty(InputPath)) return "Invalid Input path"; if (!File.Exists(this.InputPath!.Trim('"'))) return "Input Path is not a valid file"; // Disable UI while Check is running DisableUIElements(); bool cachedCanExecuteSelectionChanged = CanExecuteSelectionChanged; DisableEventHandlers(); // Populate an environment var env = new DumpEnvironment(Options, Path.GetFullPath(this.InputPath.Trim('"')), null, this.CurrentSystem, this.CurrentMediaType, this.CurrentProgram, parameters: null); // Make new Progress objects var resultProgress = new Progress(); var protectionProgress = new Progress(); // Finally, attempt to do the output dance var result = await env.VerifyAndSaveDumpOutput(resultProgress, protectionProgress, processUserInfo); // Reenable UI and event handlers, if necessary EnableUIElements(); if (cachedCanExecuteSelectionChanged) EnableEventHandlers(); return result.Message; } #endregion } }