using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using QC.CTDS.DM.DataStructures;
using QC.CTDS.DM.DataStructures.FormatDescriptorStructure;
using QC.CTDS.DM.DataStructures.InputDataStructure;
using QC.CTDS.DM.DataStructures.OutputDataStructure;
using QC.CTDS.DM.SharedLibrary;

namespace QC.CTDS.DM.DataProcessor;

internal class HistogramDescriptorProcessor : IDescriptorProcessor
{
	private HistogramOutputGroupDescriptor fdHistGroupDescriptor;

	internal ReportSettings reportSettings;

	internal List<TestRunInfo> testRuns;

	internal HistogramDescriptorProcessor()
	{
	}

	public OutputGroup ProcessDescriptorData(ReportSettings settings, GroupSetDescriptor groupSetDesc, List<TestRunInfo> testRuns)
	{
		reportSettings = settings;
		fdHistGroupDescriptor = groupSetDesc as HistogramOutputGroupDescriptor;
		this.testRuns = testRuns;
		if (reportSettings.FailureAnalysis)
		{
			return null;
		}
		if (fdHistGroupDescriptor == null)
		{
			throw new Exception("Unsopported descriptor type");
		}
		OutputGroup outputGroup = new OutputGroup();
		outputGroup.Name = fdHistGroupDescriptor.Name;
		if (fdHistGroupDescriptor.OGDisplayProperties != null && fdHistGroupDescriptor.OGDisplayProperties.Count > 0)
		{
			outputGroup.DisplayProp = fdHistGroupDescriptor.OGDisplayProperties[0];
		}
		testRuns = DataProcessorUtils.GetTestFilteredSourceData(fdHistGroupDescriptor.Result.Where((ResultDataSet res) => !string.IsNullOrEmpty(res.testID) && !string.IsNullOrEmpty(res.resID)), testRuns);
		if (testRuns.Count > 0)
		{
			if (fdHistGroupDescriptor.Discriminator1.Count > 0 || fdHistGroupDescriptor.Filter.Count > 0)
			{
				List<DiscGroup> chartGroupedItems = DataProcessorUtils.GetFilteredSourceData(fdHistGroupDescriptor, testRuns, fdHistGroupDescriptor.sort);
				if (chartGroupedItems.Count <= 0)
				{
					return outputGroup;
				}
				HistogramData[] histDataArray = new HistogramData[chartGroupedItems.Count];
				CommonFunctions.RunLoop(reportSettings.RunInSequentialMode, 0, chartGroupedItems.Count, delegate(int index)
				{
					histDataArray[index] = GenerateHistogramData(chartGroupedItems[index].TestItems, chartGroupedItems[index].GrpName);
				});
				for (int i = 0; i < histDataArray.Length; i++)
				{
					if (histDataArray[i] != null && histDataArray[i].DataTbl.Rows.Count > 0 && histDataArray[i].DistributionTbl.Rows.Count > 0)
					{
						outputGroup.OutputDataList.Add(histDataArray[i]);
					}
				}
			}
			else
			{
				HistogramData histogramData = GenerateHistogramData(testRuns);
				if (histogramData.DataTbl.Rows.Count > 0 && histogramData.DistributionTbl.Rows.Count > 0)
				{
					outputGroup.OutputDataList.Add(histogramData);
				}
			}
		}
		return outputGroup;
	}

	private HistogramData GenerateHistogramData(List<TestRunInfo> testRuns, string combinedSeriesGrpString = null)
	{
		HistogramData histogramData = new HistogramData();
		if (testRuns.Count > 0)
		{
			if (!string.IsNullOrEmpty(combinedSeriesGrpString))
			{
				histogramData.Name = fdHistGroupDescriptor.Name + " : " + combinedSeriesGrpString;
			}
			else
			{
				histogramData.Name = fdHistGroupDescriptor.Name;
			}
			List<string> list = new List<string>();
			foreach (ResultDataSet resultSet in fdHistGroupDescriptor.Result.Where((ResultDataSet res) => !string.IsNullOrEmpty(res.resID) && !string.IsNullOrEmpty(res.testID)))
			{
				List<TestRunInfo> testFilteredSourceData = DataProcessorUtils.GetTestFilteredSourceData(new ResultDataSet[1] { resultSet }, testRuns);
				List<TestRunInfo> source = testFilteredSourceData;
				Func<TestRunInfo, bool> predicate = (TestRunInfo runinfo) => runinfo.ContainsParam(resultSet.resID);
				testFilteredSourceData = source.Where(predicate).ToList();
				if ((reportSettings.AllFailureAnalysis && !testFilteredSourceData.Any((TestRunInfo runInfo) => runInfo.HasParamFailed(resultSet.resID))) || testFilteredSourceData.Count <= 0)
				{
					continue;
				}
				TestRunInfo testRunInfo = testFilteredSourceData.Find((TestRunInfo runinfo) => runinfo.ContainsParam(resultSet.resID));
				string paramUnit = testRunInfo.GetParamValue(resultSet.resID).ParamUnit;
				if (!string.IsNullOrEmpty(resultSet.name))
				{
					list.Add(resultSet.name);
				}
				else if (!string.IsNullOrEmpty(paramUnit))
				{
					list.Add(resultSet.resID + "(" + paramUnit + ")");
				}
				else
				{
					list.Add(resultSet.resID);
				}
				if (resultSet.Discriminator1.Count > 0 || resultSet.Filter.Count > 0)
				{
					List<DiscGroup> filteredSourceData = DataProcessorUtils.GetFilteredSourceData(resultSet, testFilteredSourceData, resultSet.sort);
					if (filteredSourceData.Count <= 0)
					{
						continue;
					}
					foreach (DiscGroup item in filteredSourceData)
					{
						AddResultData(histogramData, resultSet, item.TestItems, item.GrpName, item.GrpNameWithInvisibleDisc);
					}
				}
				else
				{
					AddResultData(histogramData, resultSet, testFilteredSourceData);
				}
			}
			histogramData.XAxisTitle = string.Join(":", list);
		}
		histogramData.CalculateMeanStdRange();
		GenerateDistributionData(histogramData);
		return histogramData;
	}

	private void GenerateDistributionData(HistogramData histData)
	{
		List<double> histogramBinsList = CalculateXAxisBins(histData);
		OrganizeResultDataInBins(histData, histogramBinsList);
	}

	private void OrganizeResultDataInBins(HistogramData histData, List<double> histogramBinsList)
	{
		DataColumn column = new DataColumn();
		histData.DistributionTbl.Columns.Add(column);
		for (int i = 0; i < histogramBinsList.Count; i++)
		{
			DataRow dataRow = histData.DistributionTbl.NewRow();
			dataRow[column] = histogramBinsList[i];
			histData.DistributionTbl.Rows.Add(dataRow);
		}
		DataRow dataRow2 = histData.DistributionTbl.NewRow();
		dataRow2[column] = "More";
		histData.DistributionTbl.Rows.Add(dataRow2);
		foreach (KeyValuePair<string, HistogramStatsData> item in histData.StatisticsDict)
		{
			histData.DistributionTbl.Columns.Add(item.Key);
			WriteResultFrequency(histData, item.Key, histogramBinsList, dataRow2, item.Value);
		}
		if (histData.DistributionTbl.Columns.Count > 1)
		{
			histData.HistogramColumnStartIndex = 1;
			histData.HistogramColumnStopIndex = histData.DistributionTbl.Columns.Count - 1;
		}
		foreach (KeyValuePair<string, HistogramStatsData> item2 in histData.StatisticsDict)
		{
			string columnName = item2.Key + "_Dist";
			histData.DistributionTbl.Columns.Add(columnName);
			WriteNormalDistribution(histData, columnName, histogramBinsList, dataRow2, item2.Value);
		}
		if (histData.DistributionTbl.Columns.Count > histData.HistogramColumnStopIndex)
		{
			histData.NormalDistColumnStartIndex = histData.HistogramColumnStopIndex + 1;
			histData.NormalDistColumnStopIndex = histData.DistributionTbl.Columns.Count - 1;
		}
		if (reportSettings.ShowLimitUnits)
		{
			foreach (KeyValuePair<string, HistogramStatsData> item3 in histData.StatisticsDict)
			{
				string empty = string.Empty;
				if (!double.IsNaN(item3.Value.MinLimit))
				{
					empty = item3.Key + "_Min";
					histData.DistributionTbl.Columns.Add(empty);
					WriteLimitsFrequceny(histData, empty, item3.Value.MinLimit, histogramBinsList, dataRow2);
				}
				if (!double.IsNaN(item3.Value.MaxLimit))
				{
					empty = item3.Key + "_Max";
					histData.DistributionTbl.Columns.Add(empty);
					WriteLimitsFrequceny(histData, empty, item3.Value.MaxLimit, histogramBinsList, dataRow2);
				}
			}
		}
		if (histData.DistributionTbl.Columns.Count > histData.NormalDistColumnStartIndex)
		{
			histData.LimitColumnStartIndex = histData.NormalDistColumnStopIndex + 1;
			histData.LimitColumnStopIndex = histData.DistributionTbl.Columns.Count - 1;
		}
	}

	private void WriteNormalDistribution(HistogramData histData, string columnName, List<double> histogramBinsList, DataRow moreBinRow, HistogramStatsData histogramStatsData)
	{
		for (int i = 0; i < histogramBinsList.Count; i++)
		{
			if (!double.IsNaN(histogramStatsData.Mean) && !double.IsNaN(histogramStatsData.StdDev))
			{
				histData.DistributionTbl.Rows[i][columnName] = CommonFunctions.NormalDistribution(histogramBinsList[i], histogramStatsData.Mean, histogramStatsData.StdDev, cumulative: true);
			}
		}
		moreBinRow[columnName] = 1;
	}

	private void WriteResultFrequency(HistogramData histData, string columnName, List<double> histogramBinsList, DataRow moreBinRow, HistogramStatsData statsData)
	{
		int i;
		for (i = 0; i < histogramBinsList.Count; i++)
		{
			if (i == 0)
			{
				IEnumerable<double> enumerable = statsData.Vals.Where((double val) => val <= histogramBinsList[i]);
				if (enumerable != null)
				{
					histData.DistributionTbl.Rows[i][columnName] = enumerable.Count();
				}
			}
			else
			{
				IEnumerable<double> enumerable2 = statsData.Vals.Where((double val) => val > histogramBinsList[i - 1] && val <= histogramBinsList[i]);
				if (enumerable2 != null)
				{
					histData.DistributionTbl.Rows[i][columnName] = enumerable2.Count();
				}
			}
		}
		IEnumerable<double> enumerable3 = statsData.Vals.Where((double val) => histogramBinsList[histogramBinsList.Count - 1] < val);
		if (enumerable3 != null)
		{
			moreBinRow[columnName] = enumerable3.Count();
		}
	}

	private void WriteLimitsFrequceny(HistogramData histData, string columnName, double limVal, List<double> histogramBinsList, DataRow moreBinRow)
	{
		for (int i = 0; i < histogramBinsList.Count; i++)
		{
			if (i == 0)
			{
				if (limVal <= histogramBinsList[i])
				{
					histData.DistributionTbl.Rows[i][columnName] = 1;
				}
				else
				{
					histData.DistributionTbl.Rows[i][columnName] = 0;
				}
			}
			else if (limVal > histogramBinsList[i - 1] && limVal <= histogramBinsList[i])
			{
				histData.DistributionTbl.Rows[i][columnName] = 1;
			}
			else
			{
				histData.DistributionTbl.Rows[i][columnName] = 0;
			}
		}
		if (histogramBinsList[histogramBinsList.Count - 1] < limVal)
		{
			moreBinRow[columnName] = 1;
		}
		else
		{
			moreBinRow[columnName] = 0;
		}
	}

	private List<double> CalculateXAxisBins(HistogramData histData)
	{
		List<double> list = new List<double>();
		int num = 12;
		bool flag = true;
		bool flag2 = true;
		double result = double.NaN;
		double result2 = double.NaN;
		double result3 = double.NaN;
		double minVal = histData.MinXAxis;
		double maxVal = histData.MaxXAxis;
		bool flag3 = false;
		bool flag4 = false;
		if (fdHistGroupDescriptor.OGDisplayProperties != null && fdHistGroupDescriptor.OGDisplayProperties.Count > 0 && fdHistGroupDescriptor.OGDisplayProperties[0].XAxis != null && fdHistGroupDescriptor.OGDisplayProperties[0].XAxis.Count > 0)
		{
			Axis axis = fdHistGroupDescriptor.OGDisplayProperties[0].XAxis[0];
			flag3 = double.TryParse(axis.min, out result2);
			flag4 = double.TryParse(axis.max, out result3);
			if (double.TryParse(axis.step, out result) && result > 0.0)
			{
				flag2 = false;
			}
			if (flag3 && flag4)
			{
				flag = false;
				minVal = result2;
				maxVal = result3;
			}
			else if (flag4 && result3 > maxVal)
			{
				maxVal = result3;
			}
			else if (flag3 && result2 < minVal)
			{
				minVal = result2;
			}
		}
		double num2 = minVal;
		double num3 = maxVal;
		if (flag)
		{
			CommonFunctions.RoundSmart(ref minVal, ref maxVal, forceRes: false, 0);
		}
		if (flag2)
		{
			result = (maxVal - minVal) / (double)(num - 1);
			result = ((result < 0.0005) ? CommonFunctions.RoundDouble(result + 5E-05, 4) : ((result < 0.005) ? CommonFunctions.RoundDouble(result + 0.0005, 3) : ((result < 0.05) ? CommonFunctions.RoundDouble(result + 0.005, 2) : ((result < 0.5) ? CommonFunctions.RoundDouble(result + 0.05, 1) : ((result < 5.0) ? CommonFunctions.RoundDouble(result + 0.5, 0) : ((result < 50.0) ? CommonFunctions.RoundDouble(result + 5.0, -1) : ((result < 500.0) ? CommonFunctions.RoundDouble(result + 50.0, -2) : ((!(result < 5000.0)) ? CommonFunctions.RoundDouble(result + 5000.0, -4) : CommonFunctions.RoundDouble(result + 500.0, -3)))))))));
			if (result * (double)num * 0.75 > maxVal - minVal)
			{
				result /= 2.0;
				num = (int)((double)num * 1.5);
			}
		}
		else
		{
			num = (int)((maxVal - minVal) / result + 1.0);
			if (flag)
			{
				int num4 = 0;
				if (num > 200)
				{
					while (num > 200 && num4++ < 2)
					{
						double num5 = double.NaN;
						if (histData.StatisticsDict.Count > 0)
						{
							num5 = histData.StatisticsDict.ElementAt(histData.StatisticsDict.Count - 1).Value.Vals.Median();
							if (num5 - num2 < num3 - num5)
							{
								minVal = num2;
								maxVal = (num3 = 2.0 * num5 - num2);
							}
							else
							{
								maxVal = num3;
								minVal = (num2 = 2.0 * num5 - num3);
							}
							num = (int)((num3 - num2) / result + 1.0);
						}
					}
					CommonFunctions.RoundSmart(ref minVal, ref maxVal, forceRes: false, 0);
					num = (int)((maxVal - minVal) / result + 1.0);
					if (num > 200)
					{
						result = (maxVal - minVal) / 199.0;
						num = 200;
					}
				}
				if (num < 12)
				{
					int num6 = 12 - num;
					minVal -= (double)(num6 / 2) * result;
					num6 -= num6 / 2;
					maxVal += (double)num6 * result;
					num = (int)((maxVal - minVal) / result + 1.0);
				}
			}
		}
		for (int i = 0; i < num; i++)
		{
			list.Add(Math.Round(minVal + result * (double)i, 2));
		}
		return list;
	}

	private void AddResultData(HistogramData histData, ResultDataSet resultSet, List<TestRunInfo> resultSetRuns, string combinedGrpName = null, string completeGrpName = null)
	{
		string empty = string.Empty;
		string text = (string.IsNullOrEmpty(resultSet.name) ? resultSet.resID : resultSet.name);
		if (!string.IsNullOrEmpty(resultSet.GroupName))
		{
			text = text + "_" + resultSet.GroupName;
		}
		empty = (string.IsNullOrEmpty(combinedGrpName) ? text : (text + ":" + combinedGrpName));
		if (histData.StatisticsDict.ContainsKey(empty))
		{
			if (string.IsNullOrEmpty(completeGrpName) || !(completeGrpName != combinedGrpName))
			{
				return;
			}
			int num = 1;
			empty = empty + "_" + num;
			while (histData.StatisticsDict.ContainsKey(empty))
			{
				empty = empty + "_" + ++num;
			}
		}
		string columnName = empty + "_RUNID";
		DataColumn column = new DataColumn(columnName);
		DataColumn dataColumn = new DataColumn(empty);
		dataColumn.ExtendedProperties.Add("NumberFormat", resultSet.format);
		histData.DataTbl.Columns.Add(column);
		histData.DataTbl.Columns.Add(dataColumn);
		string empty2 = string.Empty;
		List<double> list = new List<double>();
		double num2 = double.NaN;
		double num3 = double.NaN;
		for (int i = 0; i < resultSetRuns.Count; i++)
		{
			empty2 = (reportSettings.ShowSerialNumberInChartData ? (resultSetRuns[i].UUT_ID + "_" + resultSetRuns[i].RunId) : resultSetRuns[i].RunId.ToString());
			ParamInfo paramValue = resultSetRuns[i].GetParamValue(resultSet.resID);
			OutputParamInfo outputParamInfo = null;
			if (paramValue != null)
			{
				outputParamInfo = ((!(paramValue is OutputParamInfo)) ? new OutputParamInfo(paramValue) : (paramValue as OutputParamInfo));
			}
			if (outputParamInfo != null)
			{
				if (i >= histData.DataTbl.Rows.Count)
				{
					histData.DataTbl.Rows.Add(histData.DataTbl.NewRow());
				}
				histData.DataTbl.Rows[i][column] = empty2;
				if (double.IsNaN(outputParamInfo.Val))
				{
					histData.DataTbl.Rows[i][dataColumn] = outputParamInfo.StrVal;
				}
				else
				{
					histData.DataTbl.Rows[i][dataColumn] = outputParamInfo.Val.ToString();
					list.Add(outputParamInfo.Val);
				}
				if (!double.IsNaN(outputParamInfo.MinLimit) && double.IsNaN(num2))
				{
					num2 = outputParamInfo.MinLimit;
				}
				if (!double.IsNaN(outputParamInfo.MaxLimit) && double.IsNaN(num3))
				{
					num3 = outputParamInfo.MaxLimit;
				}
			}
		}
		if (list.Count <= 0)
		{
			return;
		}
		HistogramStatsData histogramStatsData = new HistogramStatsData();
		histogramStatsData.Mean = list.Avg();
		histogramStatsData.StdDev = list.StandardDeviation();
		if (!double.IsNaN(num2))
		{
			histogramStatsData.MinLimit = num2;
		}
		if (!double.IsNaN(num3))
		{
			histogramStatsData.MaxLimit = num3;
		}
		histogramStatsData.Vals = list;
		histData.StatisticsDict.Add(empty, histogramStatsData);
		if (reportSettings.ShowLimitUnits)
		{
			histData.MinXAxis = new double[3]
			{
				histData.MinXAxis,
				num2,
				list.Min()
			}.Where((double val) => !double.IsNaN(val) && !double.IsNegativeInfinity(val) && !double.IsPositiveInfinity(val)).Min();
			histData.MaxXAxis = new double[3]
			{
				histData.MaxXAxis,
				num3,
				list.Max()
			}.Where((double val) => !double.IsNaN(val) && !double.IsNegativeInfinity(val) && !double.IsPositiveInfinity(val)).Max();
		}
		else
		{
			histData.MinXAxis = new double[2]
			{
				histData.MinXAxis,
				list.Min()
			}.Where((double val) => !double.IsNaN(val) && !double.IsNegativeInfinity(val) && !double.IsPositiveInfinity(val)).Min();
			histData.MaxXAxis = new double[2]
			{
				histData.MaxXAxis,
				list.Max()
			}.Where((double val) => !double.IsNaN(val) && !double.IsNegativeInfinity(val) && !double.IsPositiveInfinity(val)).Max();
		}
	}
}
