using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.Windows; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Messaging; using Livia.Models; using Livia.Models.Data; using Livia.Properties; using Livia.Utility; using Livia.ViewModels.Utility; using Livia.Views.Utility; using Microsoft.Extensions.Logging; namespace Livia.ViewModels; public class ReportModuleItemViewModel : ObservableObject, ISelectableItem { public bool IsChecked { get => _isChecked; set => SetProperty(ref _isChecked, value); } public string Name { get; } public object Value { get; } private bool _isChecked = true; public ReportModuleItemViewModel(string name, object value, bool isChecked = true) { Name = name; Value = value; IsChecked = isChecked; } } public class ReportModuleExpanderViewModel : ObservableObject { public string Name { get; } public string Type { get; } public bool Visible => ModuleItemCollection.Items.Count > 0; public SelectableObservableCollection ModuleItemCollection { get; } = new(); public ReportModuleExpanderViewModel(string name, string type, IEnumerable list) { Name = name; Type = type; ModuleItemCollection.AddRange(list); } } public class SelectReportModuleWindowViewModel : ObservableObject, IDisposable, IRecipient, IRecipient { public event EventHandler? OnRequestClose; public static string DefaultReportName => Application.Current.TryFindResource("DefaultReportName") as string ?? "Report1"; public bool Processing { get => _processing; private set => SetProperty(ref _processing, value); } public bool ReportModuleAal { get => _reportModuleAal; set => SetProperty(ref _reportModuleAal, value); } public bool ShowRoiLocation { get => _showRoiLocation; set => SetProperty(ref _showRoiLocation, value); } public string ReportName { get => _reportName; set => SetProperty(ref _reportName, value); } public string Language { get => _language; set => SetProperty(ref _language, value); } public ObservableCollection ModuleGroups { get; } = []; public IPatientInfoManager PatientInfoManager { get; } private readonly IDataBlockLoader _dataBlockLoader; private readonly IServerHandler _serverHandler; private readonly IWarningSystem _warningSystem; private readonly ILogger _logger; private readonly CancellationTokenSource _cancellationTokenSource = new(); private bool _processing; private bool _reportModuleAal = true; private bool _showRoiLocation = true; private string _reportName; private string _language; public SelectReportModuleWindowViewModel(ILiviaControlViewModel liviaControlViewModel, IServerHandler serverHandler, IWarningSystem warningSystem, IPatientInfoManager patientInfoManager, ILogger logger, IDataBlockLoader blockLoader) { _serverHandler = serverHandler; _warningSystem = warningSystem; PatientInfoManager = patientInfoManager; _logger = logger; _dataBlockLoader = blockLoader; _reportName = DefaultReportName; List viewModels = liviaControlViewModel.GenerateReportModuleGroups(); foreach (ReportModuleExpanderViewModel reportModuleExpanderViewModel in viewModels) { ModuleGroups.Add(reportModuleExpanderViewModel); } _language = Settings.Default.Language; WeakReferenceMessenger.Default.RegisterAll(this); } private SelectReportModuleJson GenerateJson(bool overrideSameName) { ReportModules reportModules = new() { BrainRoi = true, ShowRoiLocation = ShowRoiLocation, ReportModuleAal = Settings.Default.ShowReportModuleAalCheckbox && ReportModuleAal, RegionalPerfusion = [], ParamColorImg = [], Cbf = [], Att = [], Acbv = [], AnteriorAspects = [], PosteriorAspects = [], RestrictedDiffusion = [] }; //TODO::is this good approach? foreach (ReportModuleExpanderViewModel viewModel in ModuleGroups) { List selectedItems = (from reportModuleItemViewModel in viewModel.ModuleItemCollection.Items where reportModuleItemViewModel.IsChecked select reportModuleItemViewModel.Value).ToList(); switch (viewModel.Type) { case "regional_perfusion": reportModules.RegionalPerfusion.AddRange(selectedItems); break; case "param_color_img": reportModules.ParamColorImg.AddRange(selectedItems); break; case "cbf": reportModules.Cbf.AddRange(selectedItems); break; case "att": reportModules.Att.AddRange(selectedItems); break; case "acbv": reportModules.Acbv.AddRange(selectedItems); break; case "anterior_aspects": reportModules.AnteriorAspects.AddRange(selectedItems); break; case "posterior_aspects": reportModules.PosteriorAspects.AddRange(selectedItems); break; case "restricted_diffusion": reportModules.RestrictedDiffusion.AddRange(selectedItems); break; default: _logger.LogError("Unknown Report Module type {type}", viewModel.Type); break; } } SelectReportModuleJson json = new() { Anonymous = PatientInfoManager.AnonymousMode, Key = _dataBlockLoader.CurrentDisplayingDataBlock?.Key ?? "", Language = LiviaUtility.GetLanguageOnlyString(Language), Title = ReportName, Override = overrideSameName, DisplayModules = reportModules }; return json; } public bool CheckReportNameValid() { if (ReportName.Length is not (0 or > 20) && ReportName.IndexOfAny(Path.GetInvalidFileNameChars()) == -1) return true; _warningSystem.ShowDialog(WarningWindowKind.Warning, true, "ReportNameWarning"); return false; } public async Task SelectReportModule(string fileName) { Processing = true; bool overrideSameName = !Settings.Default.ShowSelectReportModuleDialog; while (true) { (bool success, string messageIndex) = await _serverHandler.SelectReportModule(fileName, GenerateJson(overrideSameName), _cancellationTokenSource.Token).ConfigureAwait(false); if (success) { _warningSystem.ShowDialog(WarningWindowKind.Info, true, messageIndex); if (!Settings.Default.OpenReportOnFinish) return true; try { Process.Start("explorer.exe", fileName); } catch (Exception e) { _logger.LogError(e, "Error opening {path}", fileName); } } else if (messageIndex == "ServerError10035") { bool confirm = _warningSystem.ShowDialog(WarningWindowKind.Confirmation, true, messageIndex) ?? false; if (confirm) { overrideSameName = true; continue; } } else if (_cancellationTokenSource.Token.IsCancellationRequested) { _logger.LogInformation("SelectReportModule canceled"); } else { _warningSystem.ShowDialog(WarningWindowKind.Warning, false, messageIndex); } Processing = false; return success; } } public void Receive(LogoutMessage message) { //TODO::not sure if it is safe if (!Processing) OnRequestClose?.Invoke(this, EventArgs.Empty); } public void Receive(IdleTimerTickMessage message) { if (Processing) message.IdleTimer.ResetTimer(); } public void Dispose() { WeakReferenceMessenger.Default.UnregisterAll(this); } }