using C4IT.FASD.Base; using C4IT.FASD.Cockpit.Communication; using FasdDesktopUi.Basics.CustomEvents; using FasdDesktopUi.Basics.Services.RelationService; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using static C4IT.Logging.cLogManager; namespace FasdDesktopUi.Basics.Services.SupportCase { public class SupportCase : ISupportCase { private readonly Dictionary> _caseRelations = new Dictionary>(); private readonly Dictionary> _supportCaseDataCache = new Dictionary>(); internal readonly Guid Id; private readonly IRelationService _relationService; public cSupportCaseDataProvider SupportCaseDataProviderArtifact { get; } internal SupportCase(Guid id, IRelationService relationService, cSupportCaseDataProvider supportCaseDataProvider) { Id = id; _relationService = relationService; SupportCaseDataProviderArtifact = supportCaseDataProvider; AddCaseRelations(_relationService?.GetLoadedRelations()); } ~SupportCase() { if (_relationService != null) _relationService.RelationsFound -= HandleRelationsFound; } public void Initialize() { if (_relationService != null) _relationService.RelationsFound += HandleRelationsFound; } public ILookup GetCaseRelations() { try { IEnumerable<(enumFasdInformationClass InformationClass, cF4sdApiSearchResultRelation Relation)> flatList = _caseRelations.SelectMany(i => i.Value.Select(v => (i.Key, v))); return flatList.ToLookup(v => v.InformationClass, v => v.Relation); } catch (Exception ex) { LogException(ex); } return null; } public void AddCaseRelations(ILookup relations) { try { if (relations is null) return; foreach (var relationType in relations) { if (_caseRelations.TryGetValue(relationType.Key, out var caseRelation)) caseRelation = caseRelation.Union(relationType).ToList(); else _caseRelations.Add(relationType.Key, relationType.ToList()); if (SupportCaseDataProviderArtifact?.CaseRelations?.TryGetValue(relationType.Key, out var caseRelations) ?? false) caseRelations = caseRelations.Union(relationType).ToList(); else SupportCaseDataProviderArtifact?.CaseRelations?.Add(relationType.Key, relationType.ToList()); } CaseRelationsAdded?.Invoke(this, new RelationEventArgs() { Relations = relations }); } catch (Exception ex) { LogException(ex); } } public async Task LoadSupportCaseDataAsync(cF4sdApiSearchResultRelation relation, IEnumerable tablesToLoad) { try { cF4SDHealthCardRawData rawData = null; // todo this is only a temporary fix. Currently the tablesToLoad contain also detail tables // and tables won't be loaded e.g. the QuickActionHistory bool isDataComplete = tablesToLoad.Any(t => _supportCaseDataCache.TryGetValue(t, out var cachedTables) && cachedTables.TryGetValue(relation, out var table) && !table.IsIncomplete && !table.Columns.Values.Any(c => c.IsIncomplete) ); var rawDataRequest = new cF4sdHealthCardRawDataRequest() { Identities = relation.Identities, Tables = tablesToLoad.ToList(), MaxAge = cF4SDCockpitXmlConfig.Instance?.HealthCardConfig?.SearchResultAge ?? 14 }; while (!isDataComplete) { if (rawData is null) { rawData = await cFasdCockpitCommunicationBase.Instance.GetHealthCardData(rawDataRequest); await SupportCaseDataProviderArtifact.HealthCardDataHelper.LoadingHelper.SetHealthCardRawData(rawData, rawDataRequest.Identities); } else { rawData = await cFasdCockpitCommunicationBase.Instance.GetHealthCardData(rawData.Id); await SupportCaseDataProviderArtifact.HealthCardDataHelper.LoadingHelper.UpdateHealthcardRawData(rawData); } UpdateSupportCaseDataCache(relation, rawData?.Tables?.Values); isDataComplete = rawData?.Tables? .Where(table => table.Key.StartsWith("Computation_") == false) .All(table => !table.Value.IsIncomplete && !table.Value.Columns.Values.Any(c => c.IsIncomplete)) ?? false; } } catch (Exception ex) { LogException(ex); } } public void UpdateSupportCaseDataCache(cF4sdApiSearchResultRelation relation, IEnumerable tables) { try { if (tables is null) return; List dataTables = tables?.ToList(); foreach (var table in dataTables) { if (string.IsNullOrEmpty(table.Name)) continue; if (!_supportCaseDataCache.ContainsKey(table.Name)) _supportCaseDataCache.Add(table.Name, new Dictionary()); if (!_supportCaseDataCache[table.Name].ContainsKey(relation)) _supportCaseDataCache[table.Name][relation] = table; else MergeTable(_supportCaseDataCache[table.Name][relation], table); } SupportCaseDataCacheHasChanged?.Invoke(this, new SupportCaseDataEventArgs() { Relation = relation, DataTables = dataTables }); } catch (Exception ex) { LogException(ex); } void MergeTable(cF4SDHealthCardRawData.cHealthCardTable existingTable, cF4SDHealthCardRawData.cHealthCardTable newTable) { foreach (var newColumn in newTable.Columns) { existingTable.Columns[newColumn.Key] = newColumn.Value; } } } public void InvalidateCaseDataCacheFor(cF4sdApiSearchResultRelation relation) { try { foreach (var tableCache in _supportCaseDataCache.Values) { tableCache.Remove(relation); } // todo: invoke SupportCaseDataChache with empty tables // SupportCaseDataCacheHasChanged?.Invoke(this, new SupportCaseDataEventArgs() { Relation = relation }); } catch (Exception ex) { LogException(ex); } } public void InvalidateLatestCaseDataCacheFor(cF4sdApiSearchResultRelation relation, out ICollection invalidatedTables) { invalidatedTables = new HashSet(); try { foreach (var tableCache in _supportCaseDataCache.Values) { if (!tableCache.TryGetValue(relation, out cF4SDHealthCardRawData.cHealthCardTable table)) continue; table.IsIncomplete = true; foreach (var column in table.Columns.Values) { column.Values[0] = null; column.IsIncomplete = true; } invalidatedTables.Add(table); } } catch (Exception ex) { LogException(ex); } } public IEnumerable GetSupportCaseHealthcardData(cF4sdApiSearchResultRelation relation, cValueAddress valueAddress) { try { if (!_supportCaseDataCache.TryGetValue(valueAddress.ValueTable, out var tables)) return null; if (!tables.TryGetValue(relation, out var table)) return null; if (!table.Columns.TryGetValue(valueAddress.ValueColumn, out var column)) return null; return column.Values; } catch (Exception ex) { LogException(ex); } return null; } private void HandleRelationsFound(object sender, StagedSearchResultRelationsEventArgs e) { AddCaseRelations(e.StagedResultRelations.Relations); if (e.StagedResultRelations.IsComplete) _relationService.RelationsFound -= HandleRelationsFound; } private void AddCaseRelations(IEnumerable relations) => AddCaseRelations(relations?.ToLookup(r => cF4sdIdentityEntry.GetFromSearchResult(r.Type), r => r)); public event EventHandler CaseRelationsAdded; public event EventHandler SupportCaseDataCacheHasChanged; } }