538 lines
23 KiB
C#
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.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;
|
|
}
|
|
|
|
}
|
|
}
|