Files
C4IT-F4SD-Client/FasdDesktopUi/Basics/SupportCaseDataProvider.cs
2025-11-11 11:03:42 +01:00

602 lines
24 KiB
C#

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Documents;
using System.Linq;
using System.Windows.Input;
using System.Diagnostics;
using C4IT.FASD.Base;
using C4IT.Logging;
using C4IT.FASD.Cockpit.Communication;
using C4IT.MultiLanguage;
using static C4IT.Logging.cLogManager;
using FasdDesktopUi.Basics.Helper;
using FasdDesktopUi.Basics.Models;
using FasdDesktopUi.Basics.UserControls;
using FasdDesktopUi.Pages;
using FasdDesktopUi.Pages.CustomMessageBox;
using FasdDesktopUi.Config;
using FasdDesktopUi.Pages.SearchPage;
using FasdDesktopUi.Pages.TicketCompletion;
using Newtonsoft.Json;
using FasdDesktopUi.Basics.Services.ProtocollService;
using FasdDesktopUi.Basics.Services.SupportCase;
using FasdDesktopUi.Basics.Services.RelationService;
namespace FasdDesktopUi.Basics
{
public sealed class cSupportCaseDataProvider
{
public class cSearchResultRelationsByClass : Dictionary<enumFasdInformationClass, List<cF4sdApiSearchResultRelation>>
{
}
public FlowDocument CaseNotes { get; private set; } = new FlowDocument();
private static cSupportCaseDataProvider CurrentProvider;
public static Pages.SlimPage.SlimPageView slimPage { get; set; }
public static Pages.DetailsPage.DetailsPageView detailsPage { get; set; }
private static readonly Dictionary<Guid, cSupportCaseDataProvider> DataProviders = new Dictionary<Guid, cSupportCaseDataProvider>();
public EventHandler<bool> NotepadDocumentUpdated { get; set; }
#region Properties
private readonly object caseIdLockObject = new object();
public Guid CaseId { get; private set; }
public bool IsActive
{
get
{
return CaseId != Guid.Empty || slimPage?.IsActive is true || detailsPage?.IsActive is true;
}
}
public SupportCasePageBase ActiveSupportCaseWindow
{
get
{
if (detailsPage?.IsVisible is true)
return detailsPage;
if (slimPage?.IsVisible is true)
return slimPage;
return null;
}
}
System.Timers.Timer caseAliveTimer;
public cHealthCardDataHelper HealthCardDataHelper { get; private set; }
public cDirectConnectionHelper DirectConnectionHelper { get; private set; }
public cQuickActionProtocollHelper QuickActionProtocollHelper { get; private set; }
public cSearchResultRelationsByClass CaseRelations { get; } = new cSearchResultRelationsByClass();
public cNamedParameterList NamedParameterEntries { get; private set; } = new cNamedParameterList();
public cF4sdIdentityList Identities { get; set; }
#if DEBUG
public string lastCaseRelationsJson = null;
#endif
#endregion
public static event EventHandler CaseChanged;
private cSupportCaseDataProvider()
{
HealthCardDataHelper = new cHealthCardDataHelper(this);
DirectConnectionHelper = new cDirectConnectionHelper(this);
QuickActionProtocollHelper = new cQuickActionProtocollHelper(this);
}
public static async Task<cSupportCaseDataProvider> GetDataProviderForAsync(List<cF4sdApiSearchResultRelation> storedRelations, cF4sdApiSearchResultRelation selectedRelation, IRelationService relationService)
{
try
{
if (selectedRelation == null)
{
Debug.Assert(true, "The selected relation must not be null here!");
LogEntry("The selected relation must not be null here!", LogLevels.Error);
return null;
}
// get the identities of the selected relation
var Identities = selectedRelation.Identities.Clone();
// get the main indentities from all identites (normally this is the user, in a special case, where a computer was searched and found without any user activities, it could be the computer)
var MainIdentity = Identities.FirstOrDefault(identity => identity.Class == enumFasdInformationClass.User);
if (MainIdentity == null)
MainIdentity = Identities.FirstOrDefault(identity => identity.Class == enumFasdInformationClass.Computer);
if (MainIdentity == null)
MainIdentity = Identities.FirstOrDefault(identity => identity.Class == enumFasdInformationClass.VirtualSession);
if (MainIdentity == null)
MainIdentity = Identities.FirstOrDefault(identity => identity.Class == enumFasdInformationClass.MobileDevice);
if (MainIdentity == null)
{
LogEntry("Couldn't find neither a user identity nor a computer identity for the selected realtion.", LogLevels.Error);
return null;
}
var firstHealthCardInformationClass = cF4sdIdentityEntry.GetFromSearchResult(selectedRelation.Type);
// if we have the special relation computer -> user, the initial information class is changed to computer ( user -> computer )
if (firstHealthCardInformationClass == enumFasdInformationClass.User)
if (Identities.Any(v => (v.Class == enumFasdInformationClass.Computer)))
firstHealthCardInformationClass = enumFasdInformationClass.Computer;
if (Identities.Any(v => (v.Class == enumFasdInformationClass.VirtualSession)))
firstHealthCardInformationClass = enumFasdInformationClass.VirtualSession;
if (Identities.Any(v => (v.Class == enumFasdInformationClass.MobileDevice)))
firstHealthCardInformationClass = enumFasdInformationClass.MobileDevice;
var requiredInformationClasses = new List<enumFasdInformationClass>() { firstHealthCardInformationClass };
// if we have an opened support case, close it immediately
if (cSupportCaseDataProvider.CurrentProvider != null)
{
await cSupportCaseDataProvider.CurrentProvider.CloseCaseAsync();
cSupportCaseDataProvider.CurrentProvider = null;
}
if (!DataProviders.TryGetValue(MainIdentity.Id, out var _result))
{
_result = new cSupportCaseDataProvider();
DataProviders.Add(MainIdentity.Id, _result);
}
_result.NamedParameterEntries = new cNamedParameterList(_result);
_result.StartCase(MainIdentity.Id);
var supportCase = SupportCaseFactory.Get(MainIdentity, relationService, _result);
cSupportCaseDataProvider.detailsPage.SetSupportCase(supportCase);
cSupportCaseDataProvider.slimPage.SetSupportCase(supportCase);
var Status = await _result.SetViewDataAsync(requiredInformationClasses, Identities, true);
if (!Status)
return null;
CurrentProvider = _result;
// start the direct connection
if (_result.DirectConnectionHelper.IsDirectConnectionActive is false)
_ = Task.Run(async () =>
{
try
{
await _result.DirectConnectionHelper.DirectConnectionStartAsync();
}
catch { }
});
// start the slim or detaild page
bool shouldSkipSlimView = Identities.Any(identity => identity.Class is enumFasdInformationClass.Ticket) || cFasdCockpitConfig.Instance.Global.ShouldSkipSlimView;
if (shouldSkipSlimView)
cSupportCaseDataProvider.detailsPage?.Show();
else
cSupportCaseDataProvider.slimPage.Show();
return _result;
}
catch (Exception E)
{
LogException(E);
}
return null;
}
public void StartCase(Guid userId)
{
var CM = MethodBase.GetCurrentMethod();
LogMethodBegin(CM);
try
{
lock (caseIdLockObject)
{
CaseId = Guid.NewGuid();
}
if (cFasdCockpitConfig.IsAnalyticsActive)
{
_ = Task.Run(async () =>
{
try
{
var caseParameter = new cF4SDCaseParameters() { CaseId = CaseId, SessionId = cFasdCockpitConfig.SessionId, UserId = userId };
var successfullyStartedCase = await cFasdCockpitCommunicationBase.Instance.StartCase(caseParameter);
if (successfullyStartedCase is false)
{
LogEntry($"Could not start case '{caseParameter.CaseId}' for user '{caseParameter.UserId}' in session '{caseParameter.SessionId}'.", LogLevels.Warning);
return;
}
caseAliveTimer = new System.Timers.Timer(1000 * 60 * 1);
caseAliveTimer.Elapsed += (async (sender, e) => { await cFasdCockpitCommunicationBase.Instance.KeepAliveCase(CaseId); });
caseAliveTimer.Start();
}
catch (Exception E)
{
LogException(E);
}
});
}
TimerView.ResetTimer();
CaseChanged?.Invoke(this, new EventArgs());
}
catch (Exception E)
{
LogException(E);
}
finally
{
LogMethodEnd(CM);
}
}
public async Task CloseCaseAsync()
{
var CM = MethodBase.GetCurrentMethod();
LogMethodBegin(CM);
try
{
Guid tempCaseId;
lock (caseIdLockObject)
{
tempCaseId = CaseId;
if (CaseId.Equals(Guid.Empty))
return;
CaseId = Guid.Empty;
}
detailsPage?.EndPause();
List<Task> tasks = new List<Task>();
tasks.Add(DirectConnectionHelper.DirectConnectionStopAsync());
if (cFasdCockpitConfig.IsAnalyticsActive)
{
var workTimes = TimerView.GetWorkTimes();
var nettoTime = workTimes["NettoWorkingTime"];
var caseParameter = new cF4SDCaseStatusParameters() { CaseId = tempCaseId, StatusId = CaseStatus.Finished, ActiveTime = (double)nettoTime };
tasks.Add(cFasdCockpitCommunicationBase.Instance.UpdateCase(caseParameter, TimerView.caseTimes));
caseAliveTimer?.Stop();
caseAliveTimer?.Dispose();
}
await Task.WhenAll(tasks);
ResetCachedData();
}
catch (Exception E)
{
LogException(E);
}
finally
{
LogMethodEnd(CM);
}
}
private void ResetCachedData()
{
try
{
CaseNotes = new FlowDocument();
NotepadDocumentUpdated?.Invoke(this, true);
DirectConnectionHelper.Reset();
HealthCardDataHelper.Reset();
F4SDProtocoll.Instance.Clear();
}
catch (Exception E)
{
LogException(E);
}
}
static bool IsFlowDocumentNotEmpty(FlowDocument doc)
{
if (doc == null)
return false;
// Erstellt einen TextRange, der den gesamten Inhalt des Dokuments abdeckt
TextRange textRange = new TextRange(doc.ContentStart, doc.ContentEnd);
return !string.IsNullOrWhiteSpace(textRange.Text);
}
public static async Task<bool> SupportTicketActiveNoticeAsync()
{
// returns true, if we can continue with the search process
// returns false, if we have to stop the search process, because the current case remains opened
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
try
{
if (cSupportCaseDataProvider.CurrentProvider?.IsActive != true)
return true;
Mouse.OverrideCursor = null;
var ownerWindow = cSupportCaseDataProvider.CurrentProvider.ActiveSupportCaseWindow;
var ButtonText = new List<string>()
{
cMultiLanguageSupport.GetItem("Searchbar.NewSearch.ActiveSupportCase.CloseCase"),
cMultiLanguageSupport.GetItem("Searchbar.NewSearch.ActiveSupportCase.CancelCase"),
cMultiLanguageSupport.GetItem("Searchbar.NewSearch.ActiveSupportCase.ContinueCase")
};
int ResultIndex = 1;
var completitionPolicy = cFasdCockpitConfig.Instance.Global.TicketConfiguration.CompletitionPolicy;
if (completitionPolicy == enumShowDocumentCaseDialog.always ||
(completitionPolicy == enumShowDocumentCaseDialog.ifRequired &&
(F4SDProtocoll.Instance.GetOfType<QuickActionProtocollEntry>().Count() > 0 ||
IsFlowDocumentNotEmpty(CurrentProvider.CaseNotes))))
{
ResultIndex = CustomMessageBox.Show(cMultiLanguageSupport.GetItem("Searchbar.NewSearch.ActiveSupportCase"), ButtonText, "First Aid Service Desk", enumHealthCardStateLevel.Warning, Owner: ownerWindow, TopMost: true, CenterScreen: ownerWindow is Pages.SlimPage.SlimPageView, MaxWidth: 700);
}
switch (ResultIndex)
{
case 0: // close case with ticket completion
var _res = CloseCaseWithTicket(ownerWindow);
if (_res)
{
ownerWindow?.Hide();
return true;
}
break;
case 1: // close case immediately
await cSupportCaseDataProvider.CurrentProvider?.CloseCaseAsync();
ownerWindow?.Hide();
return true;
default: // return to current support case
break;
}
}
catch (Exception E)
{
LogException(E);
}
finally
{
if (CM != null) LogMethodEnd(CM);
}
return false;
}
public static async Task<bool> CloseSupportCaseAsync()
{
MethodBase CM = null; if (DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
try
{
var doClose = await SupportTicketActiveNoticeAsync();
if (doClose)
{
if (cSearchManager.Instance?.HistoryList?.LastOrDefault()?.isSeen != true)
{
SearchPageView.Instance.ActivateSearchView();
}
}
return doClose;
}
catch (Exception E)
{
LogException(E);
}
finally
{
if (CM != null) LogMethodEnd(CM);
}
return false;
}
public static bool CloseCaseWithTicket(Window ownerWindow)
{
var CM = MethodBase.GetCurrentMethod();
LogMethodBegin(CM);
try
{
var closeCaseDialogResult = TicketCompletion.Show(cSupportCaseDataProvider.CurrentProvider, ownerWindow);
if (closeCaseDialogResult != null)
{
var _h = cSupportCaseDataProvider.CurrentProvider?.CloseCaseAsync();
}
return closeCaseDialogResult != null;
}
catch (Exception E)
{
LogException(E);
}
finally
{
LogMethodEnd(CM);
}
return false;
}
public async Task<bool> SetViewDataAsync(List<enumFasdInformationClass> requiredInformationClasses, cF4sdIdentityList Identities, bool isNewCase)
{
try
{
var couldGetHealthCard = HealthCardDataHelper.TryGetHealthcard(requiredInformationClasses);
if (!couldGetHealthCard)
{
LogEntry("Couldn't find a matching healthcard.", LogLevels.Error);
CustomMessageBox.Show(cMultiLanguageSupport.GetItem("SearchBar.NoValidHealthcard"), "Load new case", enumHealthCardStateLevel.Error);
return false;
}
var requiredTables = cHealthCard.GetRequiredTables(HealthCardDataHelper.SelectedHealthCard);
if (cF4SDCustomDialogConfig.Instance != null)
{
var requiredTablesForCustomDialogs = cF4SDCustomDialogConfig.Instance.GetRequiredTables(HealthCardDataHelper.SelectedHealthCard.InformationClasses);
foreach (var table in requiredTablesForCustomDialogs)
{
requiredTables.Add(table);
}
}
var isOk = await HealthCardDataHelper.GetHealthCardRawDataAsync(new cF4sdHealthCardRawDataRequest()
{
Identities = Identities,
Tables = requiredTables.ToList(),
MaxAge = cF4SDCockpitXmlConfig.Instance?.HealthCardConfig?.SearchResultAge ?? 14
});
if (isNewCase)
HealthCardDataHelper.LastDataRequest = DateTime.Now;
if (isOk == false)
{
string identityString = "";
foreach (var identity in Identities)
{
identityString += "\n" + identity.Id + " (Type: " + identity.Class + ")";
}
LogEntry($"Error trying to receive healthcard data for following identities: {identityString}", LogLevels.Error);
CustomMessageBox.Show($"Error trying to receive healthcard data for following identities: {identityString}", "Data Error", enumHealthCardStateLevel.Error);
return false;
}
var slimPageData = await HealthCardDataHelper.GetSlimPageDataAsync();
var detailsPageData = await HealthCardDataHelper.GetDetailsPageDataAsync();
slimPage?.SetPropertyValues(slimPageData);
detailsPage?.SetPropertyValues(detailsPageData);
return true;
}
catch (Exception E)
{
LogException(E);
}
return false;
}
public async Task ChangeHealthCardAsync(enumFasdInformationClass informationClass)
{
var CM = MethodBase.GetCurrentMethod();
LogMethodBegin(CM);
try
{
await SetViewDataAsync(new List<enumFasdInformationClass>() { informationClass }, Identities, false);
}
catch (Exception E)
{
LogException(E);
}
finally
{
LogMethodEnd(CM);
}
}
public async Task ExchangeCaseIdentitiesAsync(cF4sdApiSearchResultRelation searchResultRelation)
{
#if DEBUG
var jsonRels = JsonConvert.SerializeObject(CaseRelations);
if (lastCaseRelationsJson != null && lastCaseRelationsJson.Equals(jsonRels) is false)
LogEntry($"CaseRelations changed: {jsonRels}", LogLevels.Debug);
lastCaseRelationsJson = jsonRels;
var jsonResult = JsonConvert.SerializeObject(searchResultRelation);
var jsonIds = JsonConvert.SerializeObject(Identities);
#endif
var CM = MethodBase.GetCurrentMethod();
LogMethodBegin(CM);
try
{
var ComputerRemoved = false;
var ComputerAdded = false;
List<enumFasdInformationClass> updatedInformationClasses = new List<enumFasdInformationClass>();
foreach (var relationIdentity in searchResultRelation.Identities)
{
var existingIdentity = Identities.FirstOrDefault(identity => identity.Class == relationIdentity.Class);
if (existingIdentity != null)
{
if (existingIdentity.Id.Equals(relationIdentity.Id) is false)
{
updatedInformationClasses.Add(existingIdentity.Class);
ComputerRemoved |= relationIdentity.Class == enumFasdInformationClass.Computer;
ComputerAdded |= relationIdentity.Class == enumFasdInformationClass.Computer;
}
relationIdentity.CopyTo(existingIdentity);
}
else
{
Identities.Add(relationIdentity.CreateCopy());
ComputerAdded |= relationIdentity.Class == enumFasdInformationClass.Computer;
}
}
HealthCardDataHelper.RemoveTablesWithUpdatedIdentities(updatedInformationClasses);
if (ComputerRemoved)
await CurrentProvider?.DirectConnectionHelper?.DirectConnectionStopAsync();
var searchResultInfoClass = cF4sdIdentityEntry.GetFromSearchResult(searchResultRelation.Type);
await SetViewDataAsync(new List<enumFasdInformationClass>() { searchResultInfoClass }, Identities, false);
if (ComputerAdded)
_ = Task.Run(async () =>
{
try
{
await DirectConnectionHelper.DirectConnectionStartAsync();
}
catch { }
});
}
catch (Exception E)
{
LogException(E);
}
finally
{
#if DEBUG
jsonRels = JsonConvert.SerializeObject(CaseRelations);
jsonResult = JsonConvert.SerializeObject(searchResultRelation);
jsonIds = JsonConvert.SerializeObject(Identities);
if (lastCaseRelationsJson != null && lastCaseRelationsJson.Equals(jsonRels) is false)
LogEntry($"CaseRelations changed: {jsonRels}", LogLevels.Debug);
lastCaseRelationsJson = jsonRels;
#endif
LogMethodEnd(CM);
}
}
#region Case Notes
public static event EventHandler CaseNotesChanged;
public void SaveCaseNotes() => CaseNotesChanged?.Invoke(this, EventArgs.Empty);
#endregion
}
}