Files
C4IT-F4SD-Client/FasdDesktopUi/Basics/UiActions/ShowDetailedDataAction.cs
2025-11-13 17:35:09 +01:00

538 lines
23 KiB
C#

using C4IT.F4SD.DisplayFormatting;
using C4IT.FASD.Base;
using C4IT.FASD.Cockpit.Communication;
using C4IT.Logging;
using C4IT.MultiLanguage;
using FasdDesktopUi.Basics.Models;
using FasdDesktopUi.Basics.UserControls;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using static C4IT.FASD.Base.cF4SDHealthCardRawData;
using static C4IT.Logging.cLogManager;
namespace FasdDesktopUi.Basics.UiActions
{
public class cShowDetailedDataAction : cUiActionBase
{
private static readonly Dictionary<cF4sdIdentityList, Dictionary<string, cF4SDHealthCardRawData.cHealthCardDetailsTable>> CachedDetails = new Dictionary<cF4sdIdentityList, Dictionary<string, cF4SDHealthCardRawData.cHealthCardDetailsTable>>();
private cSupportCaseDataProvider DataProvider;
private readonly cHealthCardStateBase StateDefinition;
private int DayIndex { get; set; }
private string DetailsTitle { get; set; }
private string Recommendation { get; set; }
private cHealthCardDetailsTable ValuedDetailsData = null;
public cShowDetailedDataAction(cHealthCardStateBase StateDefinition, int DayIndex = 0, cHealthCardDetailsTable ValuedDetailsData = null)
{
this.StateDefinition = StateDefinition;
this.DayIndex = DayIndex;
this.DetailsTitle = StateDefinition.Names.GetValue();
this.Recommendation = StateDefinition.Descriptions.GetValue();
if (this.Recommendation == String.Empty)
this.Recommendation = null;
this.ValuedDetailsData = ValuedDetailsData;
}
public override async Task<bool> RunUiActionAsync(object sender, UIElement UiLocation, bool isDetailedLayout, cSupportCaseDataProvider dataProvider)
{
try
{
if (!(UiLocation is Decorator decorator))
return false;
DataProvider = dataProvider;
DataProvider.HealthCardDataHelper.LoadingHelper.DataRefreshed += (s, e) => CachedDetails.Clear();
Mouse.OverrideCursor = Cursors.Wait;
if (StateDefinition.Details is cHealthCardDetailsValued)
{
if (ValuedDetailsData == null)
return false;
}
else
{
if (!await LoadDetailsDataAsync())
return false;
}
cDetailedDataModel detailedData = null;
cDetailedChartModel detailedChartData = null;
cChartModel chartData = null;
if (StateDefinition.Details is cHealthCardDetailsValued)
{
detailedData = GetValuedDataModel();
}
else
{
detailedData = GetDetailedData();
detailedChartData = GetDetailedChartData();
chartData = GetChartData();
}
cRecommendationDataModel recommendationDataModel = Recommendation != null ? new cRecommendationDataModel() { Category = DetailsTitle, Recommendation = Recommendation } : null;
if (decorator.Child is DataCanvas existingDataCanvas)
{
var tempDataCanvasData = new cDataCanvasDataModel() { QuickActionStatusMonitorData = null, DetailedData = detailedData, DetailedChartData = detailedChartData, ChartData = chartData, RecommendationData = recommendationDataModel };
if (!(StateDefinition.Details is cHealthCardDetailsValued))
{
tempDataCanvasData.GetDetailedDataAsync = GetRefreshedDetailedDataAsync;
tempDataCanvasData.GetChartDataAsync = GetRefreshedChartDataAsync;
tempDataCanvasData.GetDatailedChartDataAsync = GetRefreshedDetailsChartDataAsync;
}
existingDataCanvas.DataCanvasData = tempDataCanvasData;
existingDataCanvas.IsDetailedLayout = isDetailedLayout;
existingDataCanvas.DataProvider = DataProvider;
existingDataCanvas.Visibility = Visibility.Visible;
}
else
{
DataCanvas dataCanvas = new DataCanvas() { DataCanvasData = new cDataCanvasDataModel() { DetailedData = detailedData, DetailedChartData = detailedChartData, ChartData = chartData, RecommendationData = recommendationDataModel }, IsDetailedLayout = isDetailedLayout, DataProvider = DataProvider };
if (!(StateDefinition.Details is cHealthCardDetailsValued))
{
dataCanvas.DataCanvasData.GetDetailedDataAsync = GetRefreshedDetailedDataAsync;
dataCanvas.DataCanvasData.GetChartDataAsync = GetRefreshedChartDataAsync;
dataCanvas.DataCanvasData.GetDatailedChartDataAsync = GetRefreshedDetailsChartDataAsync;
}
decorator.Child = dataCanvas;
}
decorator.Visibility = Visibility.Visible;
return true;
}
catch (Exception E)
{
LogException(E);
}
finally
{
Mouse.OverrideCursor = null;
}
return false;
}
private async Task<bool> LoadDetailsDataAsync()
{
try
{
if (StateDefinition == null || StateDefinition.Details == null)
return false;
if (!(StateDefinition.Details is cHealthCardDetails _details) || _details.Table == null)
return false;
if (CachedDetails.TryGetValue(DataProvider.Identities, out var cachedDetailsForIdentities))
{
if (cachedDetailsForIdentities.TryGetValue(_details.Table, out _))
return true;
}
else
cachedDetailsForIdentities = new Dictionary<string, cF4SDHealthCardRawData.cHealthCardDetailsTable>();
cF4sdHealthCardRawDataRequest requestData = new cF4sdHealthCardRawDataRequest()
{
Identities = DataProvider.Identities,
MaxAge = cF4SDCockpitXmlConfig.Instance.HealthCardConfig.SearchResultAge,
Tables = StateDefinition.GetRequiredTables()
};
var detailsData = await cFasdCockpitCommunicationBase.Instance.GetDetailsData(requestData);
if (detailsData.Any(data => data.Name == _details.Table) || detailsData.Any(data => data.Name == StateDefinition.DetailedChartDetails?.ValueTable) || detailsData.Any(data => data.Name == StateDefinition.ChartDetails?.ValueTable))
{
if (StateDefinition.Details != null && detailsData.Any(data => data.Name == _details.Table))
{
if (!cachedDetailsForIdentities.ContainsKey(_details.Table))
cachedDetailsForIdentities.Add(_details.Table, detailsData.First(data => data.Name == _details.Table));
if (!CachedDetails.ContainsKey(DataProvider.Identities))
CachedDetails.Add(DataProvider.Identities, cachedDetailsForIdentities);
}
if (StateDefinition.DetailedChartDetails != null && detailsData.Any(data => data.Name == StateDefinition.DetailedChartDetails.ValueTable))
{
if (!cachedDetailsForIdentities.ContainsKey(StateDefinition.DetailedChartDetails.ValueTable))
cachedDetailsForIdentities.Add(StateDefinition.DetailedChartDetails.ValueTable, detailsData.First(data => data.Name == StateDefinition.DetailedChartDetails.ValueTable));
if (!CachedDetails.ContainsKey(DataProvider.Identities))
CachedDetails.Add(DataProvider.Identities, cachedDetailsForIdentities);
}
if (StateDefinition.ChartDetails != null && detailsData.Any(data => data.Name == StateDefinition.ChartDetails.ValueTable))
{
if (!cachedDetailsForIdentities.ContainsKey(StateDefinition.ChartDetails.ValueTable))
cachedDetailsForIdentities.Add(StateDefinition.ChartDetails.ValueTable, detailsData.First(data => data.Name == StateDefinition.ChartDetails.ValueTable));
if (!CachedDetails.ContainsKey(DataProvider.Identities))
CachedDetails.Add(DataProvider.Identities, cachedDetailsForIdentities);
}
}
else
return false;
return true;
}
catch (Exception E)
{
LogException(E);
}
return false;
}
private void UpdateProcessorStateDefinition()
{
// correct an error in older definitions of table agnt-computer-event-details-processorUsage
try
{
var oldFromColumn = StateDefinition.Details.FirstOrDefault(column => column.Name == "From");
var oldToColumn = StateDefinition.Details.FirstOrDefault(column => column.Name == "To");
if (oldFromColumn is null || oldToColumn is null)
return;
if (oldFromColumn.Column != "Duration" || oldToColumn.Column != "time")
return;
oldFromColumn.Column = "time";
oldToColumn.Column = "Duration.add";
}
catch (Exception E)
{
LogException(E);
}
}
private void ProcessDetailValue(string processintType, ref object rawValue, DateTime timeColumnValue)
{
try
{
if (rawValue is Int64 milliSec)
{
switch (processintType)
{
case "add":
rawValue = timeColumnValue.AddMilliseconds(milliSec);
break;
case "sub":
rawValue = timeColumnValue.AddMilliseconds(-milliSec);
break;
}
}
}
catch (Exception E)
{
LogException(E);
}
}
private cDetailedDataModel GetValuedDataModel()
{
if (!(StateDefinition.Details is cHealthCardDetailsValued _details) || ValuedDetailsData == null)
return null;
if (ValuedDetailsData.Columns.Count > 1)
return null;
var _rowHeadings = _details.Select(v => v.Names.GetValue() as object).ToList();
cDetailedDataModel output = new cDetailedDataModel()
{
Heading = StateDefinition.Names.GetValue(),
FullDetailedData = new List<object>(),
HasColumnHeaders = _rowHeadings.Count > 1
};
if (_rowHeadings.Count > 1)
output.FullDetailedData.Add(_rowHeadings);
var _data = ValuedDetailsData.Values[0];
foreach (var _row in _data)
output.FullDetailedData.Add(new List<object>() { _row[0] });
return output;
}
private cDetailedDataModel GetDetailedData()
{
try
{
const string timeColumnName = "time";
cDetailedDataModel output = new cDetailedDataModel() { FullDetailedData = new List<object>() };
string dateAddtionFormat = cMultiLanguageSupport.GetItem("DetailsPage.History.Details");
string dateAddition = string.Format(dateAddtionFormat, DateTime.Today.AddDays(-DayIndex).ToString("d", new CultureInfo(cFasdCockpitConfig.Instance.SelectedLanguage)));
string detailedDataHeading = "Details - " + DetailsTitle + dateAddition;
output.Heading = detailedDataHeading;
if (!(StateDefinition.Details is cHealthCardDetails _details) || _details.Table == null)
return null;
// correct an error in older definitions of table agnt-computer-event-details-processorUsage
if (_details.Table == "agnt-computer-event-details-processorUsage")
UpdateProcessorStateDefinition();
var headerValues = StateDefinition.Details.Select(value => value.Names.GetValue());
output.FullDetailedData.Add(headerValues.ToList<object>());
var detailsData = CachedDetails[DataProvider.Identities][_details.Table];
if (!detailsData.Values.TryGetValue(DayIndex, out var details))
return output;
int columnCount = StateDefinition.Details.Count;
List<int> rawColumnIndexes = new List<int>(columnCount);
List<RawValueType> displayTypes = new List<RawValueType>(columnCount);
List<string> valueProcessings = new List<string>(columnCount);
int timeColumnIndex = detailsData.Columns.IndexOf(timeColumnName);
int filterColumnIndex = detailsData.Columns.IndexOf(StateDefinition.Details?.Filter?.FilterColumn);
foreach (var columnDefinition in StateDefinition.Details)
{
var splitColumnName = columnDefinition.Column.Split('.');
var rawColumnIndex = detailsData.Columns.IndexOf(splitColumnName[0]);
var displayType = columnDefinition.DisplayType;
var valueProcessing = splitColumnName.Length > 1 ? splitColumnName[1] : null;
rawColumnIndexes.Add(rawColumnIndex);
displayTypes.Add(cUtility.GetRawValueType(displayType));
valueProcessings.Add(valueProcessing);
}
foreach (var detailsRow in details)
{
var displayValuesOfRow = new List<object>(columnCount);
var displayTypeEnumerator = displayTypes.GetEnumerator();
var valueProcessingsEnumerator = valueProcessings.GetEnumerator();
bool shouldHideRow = false;
if (StateDefinition.Details.Filter != null && !rawColumnIndexes.Contains(filterColumnIndex))
{
bool columnValueMatchesFilterValue = StateDefinition.Details.Filter.FilterValues.Contains(detailsRow[filterColumnIndex]);
if (!columnValueMatchesFilterValue)
shouldHideRow = true;
}
cUtility.RawValueFormatter.SetDefaultCulture(new System.Globalization.CultureInfo(cFasdCockpitConfig.Instance.SelectedLanguage));
foreach (var index in rawColumnIndexes)
{
try
{
if (shouldHideRow)
continue;
if (detailsRow.Length < index || !displayTypeEnumerator.MoveNext() || !valueProcessingsEnumerator.MoveNext())
continue;
var rawDetailValue = detailsRow[index];
if (index == filterColumnIndex
&& !StateDefinition.Details.Filter.FilterValues.Contains(rawDetailValue))
{
shouldHideRow = true;
continue;
}
if (valueProcessingsEnumerator.Current != null)
if (detailsRow[timeColumnIndex] is DateTime timeColumnValue)
ProcessDetailValue(valueProcessingsEnumerator.Current, ref rawDetailValue, timeColumnValue);
var displayValue = cUtility.RawValueFormatter.GetDisplayValue(rawDetailValue, displayTypeEnumerator.Current);
displayValuesOfRow.Add(displayValue);
}
catch (Exception E)
{
LogException(E);
}
}
if (shouldHideRow)
continue;
output.FullDetailedData.Add(displayValuesOfRow);
}
return output;
}
catch (Exception E)
{
LogException(E);
}
return null;
}
private cDetailedChartModel GetDetailedChartData()
{
try
{
if (StateDefinition?.DetailedChartDetails is null)
return null;
var detailsDataTable = CachedDetails[DataProvider.Identities][StateDefinition.DetailedChartDetails.ValueTable];
int valueIndex = detailsDataTable.Columns.IndexOf(StateDefinition.DetailedChartDetails.ValueColumn);
int timeIndex = detailsDataTable.Columns.IndexOf(StateDefinition.DetailedChartDetails.TimeColumn);
int durationIndex = detailsDataTable.Columns.IndexOf(StateDefinition.DetailedChartDetails.DurationColumn);
string title = StateDefinition.Names.GetValue();
bool isThresholdActive = StateDefinition is cHealthCardStateLevel;
var output = new cDetailedChartModel()
{
Data = detailsDataTable.Values[DayIndex],
ValueIndex = valueIndex,
TimeIndex = timeIndex,
DurationIndex = durationIndex,
ChartTitle = title,
IsThresholdActive = isThresholdActive,
};
if (StateDefinition is cHealthCardStateLevel stateLevelDefinition)
{
output.WarningThreshold = stateLevelDefinition.Warning;
output.ErrorThreshold = stateLevelDefinition.Error;
}
return output;
}
catch (Exception E)
{
LogException(E);
}
return null;
}
private cChartModel GetChartData()
{
try
{
if (StateDefinition?.ChartDetails is null)
return null;
var detailsDataTable = CachedDetails[DataProvider.Identities][StateDefinition.ChartDetails.ValueTable];
int valueIndex = detailsDataTable.Columns.IndexOf(StateDefinition.ChartDetails.ValueColumn);
int timeIndex = detailsDataTable.Columns.IndexOf(StateDefinition.ChartDetails.TimeColumn);
int durationIndex = detailsDataTable.Columns.IndexOf(StateDefinition.ChartDetails.DurationColumn);
string title = StateDefinition.Names.GetValue();
bool isThresholdActive = false;
double warningThreshold = 0;
double errorThreshold = 0;
bool isDirectionUp = true;
if (StateDefinition is cHealthCardStateLevel stateLevel)
{
isThresholdActive = true;
warningThreshold = stateLevel.Warning;
errorThreshold = stateLevel.Error;
isDirectionUp = stateLevel.IsDirectionUp;
}
int stepLengthScale = StateDefinition.ChartDetails.StepLengthScale;
int stepLengthLine = StateDefinition.ChartDetails.StepLengthLine;
int maxValue = StateDefinition.ChartDetails.MaxValue;
int minValue = StateDefinition.ChartDetails.MinValue;
string unitFormat = StateDefinition.UnitFormat;
var output = new cChartModel()
{
Data = detailsDataTable.Values[DayIndex],
ValueIndex = valueIndex,
TimeIndex = timeIndex,
DurationIndex = durationIndex,
ChartTitle = title,
WarningThreshold = warningThreshold,
ErrorThreshold = errorThreshold,
IsThresholdActive = isThresholdActive,
IsDirectionUp = isDirectionUp,
StepLengthScale = stepLengthScale,
StepLengthLine = stepLengthLine,
MaxValue = maxValue,
MinValue = minValue,
UnitFormat = unitFormat,
};
return output;
}
catch (Exception E)
{
LogException(E);
}
return null;
}
private async Task<cDetailedDataModel> GetRefreshedDetailedDataAsync()
{
cDetailedDataModel output = null;
try
{
CachedDetails.Remove(DataProvider.Identities);
if (await LoadDetailsDataAsync())
return GetDetailedData();
}
catch (Exception E)
{
LogException(E);
}
return output;
}
private async Task<cDetailedChartModel> GetRefreshedDetailsChartDataAsync()
{
cDetailedChartModel output = null;
try
{
CachedDetails.Remove(DataProvider.Identities);
if (await LoadDetailsDataAsync())
return GetDetailedChartData();
}
catch (Exception E)
{
LogException(E);
}
return output;
}
private async Task<cChartModel> GetRefreshedChartDataAsync()
{
cChartModel output = null;
try
{
CachedDetails.Remove(DataProvider.Identities);
if (await LoadDetailsDataAsync())
return GetChartData();
}
catch (Exception E)
{
LogException(E);
}
return output;
}
}
}