#if !(NET20 || NET35 || NET40)
using System;
#endif
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
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 Options Options
{
get => _options;
}
private readonly 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 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;
///
/// Currently displayed status
///
public string Status
{
get => _status;
set
{
_status = value;
TriggerPropertyChanged(nameof(Status));
TriggerPropertyChanged(nameof(StatusFirstLine));
}
}
private string _status;
///
/// Currently displayed status trimmed to one line
///
public string StatusFirstLine
{
get
{
if (string.IsNullOrEmpty(Status))
return string.Empty;
var statusLines = Status.Split('\n');
if (statusLines.Length > 1)
return statusLines[0] + " (...)";
return statusLines[0];
}
}
///
/// 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 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 = [];
_status = string.Empty;
SystemTypeComboBoxEnabled = true;
InputPathTextBoxEnabled = true;
InputPathBrowseButtonEnabled = true;
DumpingProgramComboBoxEnabled = true;
CheckDumpButtonEnabled = false;
CancelButtonEnabled = true;
Systems = RedumpSystemComboBoxItem.GenerateElements();
InternalPrograms = [];
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()
{
CheckDumpButtonEnabled = ShouldEnableCheckDumpButton();
}
///
/// Change the currently selected dumping program
///
public void ChangeDumpingProgram()
{
CheckDumpButtonEnabled = ShouldEnableCheckDumpButton();
}
///
/// Change the currently selected input path
///
public void ChangeInputPath()
{
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;
CheckDumpButtonEnabled = ShouldEnableCheckDumpButton();
CancelButtonEnabled = true;
}
///
/// Disables all UI elements
///
private void DisableUIElements()
{
SystemTypeComboBoxEnabled = false;
InputPathTextBoxEnabled = false;
InputPathBrowseButtonEnabled = false;
DumpingProgramComboBoxEnabled = false;
CheckDumpButtonEnabled = false;
CancelButtonEnabled = false;
}
#endregion
#region Population
///
/// 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 = Options.InternalProgram;
// Create a static list of supported Check programs, not everything
var internalPrograms = new List
{
InternalProgram.Redumper,
InternalProgram.Aaru,
InternalProgram.DiscImageCreator,
// InternalProgram.Dreamdump,
InternalProgram.CleanRip,
InternalProgram.PS3CFW,
InternalProgram.UmdImageCreator,
InternalProgram.XboxBackupCreator
};
InternalPrograms = internalPrograms.ConvertAll(ip => new Element(ip));
// Select the current default dumping program
int currentIndex = InternalPrograms.FindIndex(m => m == internalProgram);
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 CurrentSystem is not null && !string.IsNullOrEmpty(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 ResultEventArgs.Failure("Invalid Input path");
if (!File.Exists(InputPath!.Trim('"')))
return ResultEventArgs.Failure("Input Path is not a valid file");
// Disable UI while Check is running
DisableUIElements();
bool cachedCanExecuteSelectionChanged = CanExecuteSelectionChanged;
DisableEventHandlers();
// Get progress indicators
var resultProgress = new Progress();
resultProgress.ProgressChanged += ProgressUpdated;
var protectionProgress = new Progress();
protectionProgress.ProgressChanged += ProgressUpdated;
// Populate an environment
var env = new DumpEnvironment(Options,
Path.GetFullPath(InputPath.Trim('"')),
null,
CurrentSystem,
CurrentProgram);
env.SetProcessor();
// Finally, attempt to do the output dance
var result = await env.VerifyAndSaveDumpOutput(
resultProgress: resultProgress,
protectionProgress: protectionProgress,
processUserInfo: processUserInfo);
// Reenable UI and event handlers, if necessary
EnableUIElements();
if (cachedCanExecuteSelectionChanged)
EnableEventHandlers();
return result;
}
///
/// Handler for Result ProgressChanged event
///
private void ProgressUpdated(object? sender, ResultEventArgs value)
{
Status = value?.Message ?? string.Empty;
}
///
/// Handler for ProtectionProgress ProgressChanged event
///
private void ProgressUpdated(object? sender, ProtectionProgress value)
{
string message = $"{value.Percentage * 100:N2}%: {value.Filename} - {value.Protection}";
Status = message;
}
#endregion
}
}