using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Data.Entity; using System.Linq; using System.Text; using System.Threading.Tasks; using Tango.BL; using Tango.BL.Builders; using Tango.BL.Entities; using Tango.BL.Enumerations; using Tango.Core.Commands; using Tango.MachineStudio.Common; using Tango.MachineStudio.Common.Notifications; using Tango.MachineStudio.Statistics.Models; using Tango.SharedUI; using Tango.SharedUI.Components; using Tango.AutoComplete.Editors; using System.Windows.Media; using LiveCharts.Wpf; using LiveCharts; using Tango.BL.ValueObjects; using System.Diagnostics; using Microsoft.Win32; using Tango.CSV; using System.ComponentModel; namespace Tango.MachineStudio.Statistics.ViewModels { public enum HeadCleaningSelectionEnum { [Description("Exclude")] Exclude = 0, [Description("Include")] Include = 1, [Description("Only")] Only = 2 }; public class JobRunsViewVM : ViewModel { private INotificationProvider _notification; private List _organizations; private List _allMachines; private List _allUsers; private List _rmlsModels; #region Properties private ObservableCollection _jobRuns; /// /// Gets or sets the job runs. Contains filtered data of JobRunModel. /// public ObservableCollection JobRuns { get { return _jobRuns; } set { _jobRuns = value; RaisePropertyChangedAuto(); } } private JobRunModel _selectedJobRun = null; /// /// Gets or sets the JobRunModel. Binding to selected item of grid items. /// public JobRunModel SelectedJobRun { get { return _selectedJobRun; } set { _selectedJobRun = value; RaisePropertyChangedAuto(); } } private SelectedObjectCollection _selectedOrganizations; /// /// Gets or sets the selected machines. Contains all available machines and selected machines. Binding to ComboBox Machines. /// public SelectedObjectCollection SelectedOrganizations { get { return _selectedOrganizations; } set { _selectedOrganizations = value; RaisePropertyChangedAuto(); } } private bool _IsEnabledSelectionSites; public bool IsEnabledSelectionSites { get { return _IsEnabledSelectionSites; } set { _IsEnabledSelectionSites = value; RaisePropertyChangedAuto(); } } private bool _allSelectedSites; public bool AllSelectedSites { get { return _allSelectedSites; } set { _allSelectedSites = value; RaisePropertyChangedAuto(); } } private SelectedObjectCollection _selectedSites; /// /// Gets or sets the selected machines. Contains all available machines and selected machines. Binding to ComboBox Machines. /// public SelectedObjectCollection SelectedSites { get { return _selectedSites; } set { _selectedSites = value; RaisePropertyChangedAuto(); } } private bool _allSelectedMachines; public bool AllSelectedMachines { get { return _allSelectedMachines; } set { _allSelectedMachines = value; RaisePropertyChangedAuto(); } } private SelectedObjectCollection _selectedMachines; /// /// Gets or sets the selected machines. Contains all available machines and selected machines. Binding to ComboBox Machines. /// public SelectedObjectCollection SelectedMachines { get { return _selectedMachines; } set { _selectedMachines = value; RaisePropertyChangedAuto(); } } private DateTime _startSelectedDate; /// /// Gets or sets the start selected date. /// public DateTime StartSelectedDate { get { return _startSelectedDate; } set { _startSelectedDate = value; RaisePropertyChangedAuto(); } } private DateTime _endSelectedDate; /// /// Gets or sets the end selected date. /// public DateTime EndSelectedDate { get { return _endSelectedDate; } set { _endSelectedDate = value; RaisePropertyChangedAuto(); } } protected Double _lengthLowerValue; /// /// Gets or sets the length lower value of Range Slider /// public Double LengthLowerValue { get { return _lengthLowerValue; } set { _lengthLowerValue = value; RaisePropertyChangedAuto(); } } protected Double _lengthUpperValue; /// /// Gets or sets the length upper value of Range Slider. /// public Double LengthUpperValue { get { return _lengthUpperValue; } set { _lengthUpperValue = value; RaisePropertyChangedAuto(); } } private SelectedObjectCollection _jobRunSelectedSources; /// /// Gets or sets the job run selected sources. Binding to ComboBox "Source". /// public SelectedObjectCollection JobRunSelectedSources { get { return _jobRunSelectedSources; } set { _jobRunSelectedSources = value; RaisePropertyChangedAuto(); } } private SelectedObjectCollection _jobRunSelectedStatuses; /// /// Gets or sets the job run selected statuses. Binding to ComboBox "Status". /// public SelectedObjectCollection JobRunSelectedStatuses { get { return _jobRunSelectedStatuses; } set { _jobRunSelectedStatuses = value; RaisePropertyChangedAuto(); } } public SelectedObjectCollection _isGradientSelection; /// /// Gets or sets the is gradient selection. Binding to ComboBox "IsGradient". /// public SelectedObjectCollection IsGradientSelection { get { return _isGradientSelection; } set { _isGradientSelection = value; RaisePropertyChangedAuto(); } } private SelectedObjectCollection _selectedThreads; /// /// Gets or sets the selected threads. Contains all available threads and selected threads. Binding to ComboBox "Thread". /// public SelectedObjectCollection SelectedThreads { get { return _selectedThreads; } set { _selectedThreads = value; RaisePropertyChangedAuto(); } } private HeadCleaningSelectionEnum _headCleaningSelected; public HeadCleaningSelectionEnum HeadCleaningSelected { get { return _headCleaningSelected; } set { _headCleaningSelected = value; RaisePropertyChangedAuto(); } } /// /// Gets or sets the JobRuns providers. /// public ISuggestionProvider JobsProvider { get; set; } private Job _selectedJob; /// /// Gets or sets the job. /// public Job SelectedJob { get { return _selectedJob; } set { _selectedJob = value; RaisePropertyChangedAuto(); } } /// /// Gets or sets the statistics value collection. Class - container included calculated statistic values. /// public StatisticsValueCollection StatisticsValueCollection { get; set; } #endregion public RelayCommand LoadJobRunsCommand { get; set; } public RelayCommand ExportToExcelCommand { get; set; } public JobRunsViewVM(INotificationProvider notificationProvider) { _notification = notificationProvider; JobRuns = new ObservableCollection(); LoadJobRunsCommand = new RelayCommand(async () => await LoadJobRuns(), () => IsFree && SelectedMachines != null && SelectedMachines.Source.Count > 0); ExportToExcelCommand = new RelayCommand(ExportToExcel, () => IsFree); LengthUpperValue = 1000000.0; LengthLowerValue = 0.0; DateTime now = DateTime.Now; StartSelectedDate = now.AddMonths(-1); EndSelectedDate = now; JobRunSelectedSources = new SelectedObjectCollection(new ObservableCollection() { JobSource.Local, JobSource.Remote }, new ObservableCollection() { JobSource.Local, JobSource.Remote }); JobRunSelectedSources.SelectionChanged -= (x, y) => RaisePropertyChanged(nameof(JobRunSelectedSources)); JobRunSelectedSources.SelectionChanged += (x, y) => RaisePropertyChanged(nameof(JobRunSelectedSources)); JobRunSelectedStatuses = new SelectedObjectCollection(new ObservableCollection() { JobRunStatus.Aborted, JobRunStatus.Completed, JobRunStatus.Failed, }, new ObservableCollection() { JobRunStatus.Aborted, JobRunStatus.Completed, JobRunStatus.Failed, }); JobRunSelectedStatuses.SelectionChanged -= (x, y) => RaisePropertyChanged(nameof(JobRunSelectedStatuses)); JobRunSelectedStatuses.SelectionChanged += (x, y) => RaisePropertyChanged(nameof(JobRunSelectedStatuses)); IsGradientSelection = new SelectedObjectCollection(new ObservableCollection { true, false }, new ObservableCollection { true, false }); IsGradientSelection.SelectionChanged -= (x, y) => RaisePropertyChanged(nameof(IsGradientSelection)); IsGradientSelection.SelectionChanged += (x, y) => RaisePropertyChanged(nameof(IsGradientSelection)); HeadCleaningSelected = HeadCleaningSelectionEnum.Exclude; JobsProvider = new SuggestionProvider((filter) => { try { if (filter != null) { using (ObservablesContext db = ObservablesContext.CreateDefault()) { return db.Jobs.Where(x => x.Name != null && x.Name.ToLower().Contains(filter.ToLower())).ToList(); } } else { return new List(); } } catch (Exception ex) { LogManager.Log(ex, "Error loading jobs."); return null; } }); StatisticsValueCollection = new StatisticsValueCollection(); } /// /// Initializes this instance. Called form main view VM in OnApplicationReady /// public async void Init() { using (_notification.PushTaskItem("Loading job runs...")) { try { IsFree = false; using (var db = ObservablesContext.CreateDefault()) { _organizations = await db.Organizations.Select(x => new OrganisationToSiteModel() { Name = x.Name, Guid = x.Guid }).ToListAsync(); foreach (var org in _organizations) { org.Sites = await db.Sites.Where(y => y.OrganizationGuid == org.Guid).Select(y => new SiteModel() { Guid = y.Guid, Name = y.Name, }).ToListAsync(); foreach (var site in org.Sites) { site.Machines = await db.Machines.Where(x => x.SiteGuid == site.Guid).Select(y => new MachineModel() { Guid = y.Guid, Name = y.Name, SerialNumber = y.SerialNumber }).ToListAsync(); } org.Machines = await db.Machines.Where(y => y.OrganizationGuid == org.Guid).Select(y => new MachineModel() { Guid = y.Guid, Name = y.Name, SerialNumber = y.SerialNumber }).ToListAsync(); } _allMachines = await db.Machines.ToListAsync(); _allUsers = await db.Users.Include(x => x.Contact).ToListAsync(); _rmlsModels = await db.Rmls.Select(x => new RmlModel() { Name = x.Name, Guid = x.Guid }).ToListAsync(); } IsEnabledSelectionSites = false; SelectedMachines = new SelectedObjectCollection(new ObservableCollection(), new ObservableCollection()); SelectedThreads = new SelectedObjectCollection(_rmlsModels.ToObservableCollection(), new ObservableCollection()); SelectedSites = new SelectedObjectCollection(new ObservableCollection(), new ObservableCollection()); SelectedOrganizations = new SelectedObjectCollection(_organizations.ToObservableCollection(), _organizations.ToObservableCollection()); SelectedOrganizations.SelectionChanged -= OnSelectedOrganizationsChanged; SelectedOrganizations.SelectionChanged += OnSelectedOrganizationsChanged; SelectedSites.SelectionChanged -= OnSelectedSitesChanged; SelectedSites.SelectionChanged += OnSelectedSitesChanged; AllSelectedSites = true; AllSelectedMachines = true; } catch (Exception ex) { LogManager.Log(ex, "Error loading job runs."); } finally { IsFree = true; } } } private void OnSelectedSitesChanged(object sender, EventArgs e) { if (SelectedSites.SynchedSource.Count > 0) { SelectedMachines = new SelectedObjectCollection(SelectedSites.SynchedSource.SelectMany(x => x.Machines).ToObservableCollection(), SelectedSites.SynchedSource.SelectMany(x => x.Machines).ToObservableCollection()); } else { SelectedMachines = new SelectedObjectCollection(SelectedOrganizations.SynchedSource.SelectMany(x => x.Machines).ToObservableCollection(), SelectedOrganizations.SynchedSource.SelectMany(x => x.Machines).ToObservableCollection()); } AllSelectedMachines = false; AllSelectedMachines = true; InvalidateRelayCommands(); } private void OnSelectedOrganizationsChanged(object sender, EventArgs e) { if (SelectedOrganizations.SynchedSource.Count != SelectedOrganizations.Source.Count) { IsEnabledSelectionSites = true; var selectedOrg = SelectedOrganizations.SynchedSource.ToList(); SelectedSites = new SelectedObjectCollection(selectedOrg.SelectMany(x => x.Sites).ToObservableCollection(), selectedOrg.SelectMany(x => x.Sites).ToObservableCollection()); SelectedSites.SelectionChanged -= OnSelectedSitesChanged; SelectedSites.SelectionChanged += OnSelectedSitesChanged; SelectedMachines = new SelectedObjectCollection(selectedOrg.SelectMany(x => x.Machines).ToObservableCollection(), selectedOrg.SelectMany(x => x.Machines).ToObservableCollection()); AllSelectedSites = false; AllSelectedSites = true; } else { SelectedSites = new SelectedObjectCollection(SelectedOrganizations.SynchedSource.SelectMany(x => x.Sites).ToObservableCollection(), SelectedOrganizations.SynchedSource.SelectMany(x => x.Sites).ToObservableCollection()); AllSelectedSites = false; IsEnabledSelectionSites = false; SelectedMachines = new SelectedObjectCollection(SelectedOrganizations.SynchedSource.SelectMany(x => x.Machines).ToObservableCollection(), SelectedOrganizations.SynchedSource.SelectMany(x => x.Machines).ToObservableCollection()); } AllSelectedMachines = false; AllSelectedMachines = true; InvalidateRelayCommands(); } /// /// Loads the job runs by filters. /// private async Task LoadJobRuns() { using (_notification.PushTaskItem("Loading job runs...")) { try { IsFree = false; using (var db = ObservablesContext.CreateDefault()) { DateTime startUtc = new DateTime(StartSelectedDate.Year, StartSelectedDate.Month, StartSelectedDate.Day, 0, 0, 0).ToUniversalTime(); TimeSpan offsetTime = (EndSelectedDate.Date == DateTime.Now.Date) ? DateTime.Now.TimeOfDay : new TimeSpan(23, 59, 59); DateTime endUtc = EndSelectedDate.ToUniversalTime() + offsetTime; string jobName = SelectedJob == null ? "" : SelectedJob.Name; var db_JobRuns = db.JobRuns.Where(x => (x.StartDate <= endUtc && x.StartDate >= startUtc)); var machineIDs = new HashSet(SelectedMachines.SynchedSource.ToList().Select(p => p.Guid)); if (machineIDs.Count > 0) { db_JobRuns = db_JobRuns.Where(x => machineIDs.Contains(x.MachineGuid)); } int[] jobRunSourceArr = JobRunSelectedSources.SynchedSource.Select(x => (int)x).ToArray(); if (jobRunSourceArr.Length > 0) { db_JobRuns = db_JobRuns.Where(x => jobRunSourceArr.Contains(x.JobSource)); } int[] jobRunStatusArr = JobRunSelectedStatuses.SynchedSource.Select(x => (int)x).ToArray(); if (jobRunStatusArr.Length > 0) { db_JobRuns = db_JobRuns.Where(x => jobRunStatusArr.Contains(x.Status)); } bool[] isGradientArr = IsGradientSelection.SynchedSource.Select(x => (bool)x).ToArray(); if (isGradientArr.Length > 0) { db_JobRuns = db_JobRuns.Where(x => isGradientArr.Contains(x.IsGradient)); } if (HeadCleaningSelected != HeadCleaningSelectionEnum.Include) { bool isHeadCleaning = HeadCleaningSelected == HeadCleaningSelectionEnum.Only; db_JobRuns = db_JobRuns.Where(x => isHeadCleaning == x.IsHeadCleaning); } List rmlGuids = SelectedThreads.SynchedSource.Select(y => y.Guid).ToList(); if (rmlGuids != null && rmlGuids.Count > 0) { db_JobRuns = db_JobRuns.Where(x => rmlGuids.Contains(x.RmlGuid)); } if (!String.IsNullOrEmpty(jobName)) { db_JobRuns = db_JobRuns.Where(x => x.JobName.ToLower().StartsWith(jobName.ToLower())); } var runs_db = await db_JobRuns.ToListAsync(); //Execute actual query. List runs = runs_db.Where(x => (x.JobLength < LengthUpperValue && x.JobLength >= LengthLowerValue)).ToList(); var modelList = runs.Select(x => new JobRunModel() { JobRun = x, Machine = _allMachines.FirstOrDefault(y => y.Guid == x.MachineGuid), User = _allUsers.SingleOrDefault(y => y.Guid == x.UserGuid), Rml = _rmlsModels.SingleOrDefault(y => y.Guid == x.RmlGuid), }).OrderByDescending(x => x.JobRun.StartDate).ToList(); modelList.ForEach(x => x.Init()); JobRuns = modelList.ToObservableCollection(); GenerateStatistics(); } } catch (Exception ex) { LogManager.Log(ex, "Error loading job runs."); } finally { IsFree = true; } } } private void ExportToExcel() { SaveFileDialog dlg = new SaveFileDialog { Title = "Job Runs Statistic Report", Filter = "CSV Files|*.csv", FileName = "Statistics_Job_runs", DefaultExt = ".csv" }; if (dlg.ShowDialog().GetValueOrDefault()) { try { var csv = new CsvDynamicWriter(); // ===== Fixed column indices (preserve your original order before outputs) ===== const int IDX_ID = 0; const int IDX_Gen = 1; const int IDX_Machine = 2; const int IDX_Source = 3; const int IDX_JobName = 4; const int IDX_JobKind = 5; const int IDX_Thread = 6; const int IDX_Length = 7; const int IDX_NumberOfUnits = 8; const int IDX_StartTime = 9; const int IDX_Duration = 10; const int IDX_Distance = 11; const int IDX_StartPosition = 12; const int IDX_EndPosition = 13; const int IDX_Status = 14; // ===== Dynamic outputs start here; one slot per enum value in stable order ===== var liquids = (LiquidTypes[])Enum.GetValues(typeof(LiquidTypes)); const int OUTPUT_BASE = 15; // "Failure Reason" will appear AFTER all potential output columns int IDX_FailureReason = OUTPUT_BASE + liquids.Length; // Optional: header name normalization for specific liquids (keeps your legacy "Transparent Ink" name) Func outputHeader = lt => { return "Output " + lt; // e.g., "Output Cyan", "Output LightCyan", "Output Lubricant" }; var selection = JobRuns; foreach (var jobRunModel in selection) { // ===== Fixed fields ===== csv.Write(jobRunModel.JobRun.ID.ToString(), "ID", "", IDX_ID); csv.Write(((MachineTypes)jobRunModel.JobRun.MachineType).ToShortName(), "Gen", "", IDX_Gen); csv.Write(jobRunModel.Machine != null ? jobRunModel.Machine.SerialNumber : "", "Machine", "", IDX_Machine); csv.Write(jobRunModel.JobRun.Source.ToString(), "Source", "", IDX_Source); csv.Write(jobRunModel.JobRun.JobName, "Job Name", "", IDX_JobName); csv.Write(((JobDesignations)jobRunModel.JobRun.JobDesignation).ToDescription(), "Job Kind", "", IDX_JobKind); csv.Write(jobRunModel.Rml != null ? jobRunModel.Rml.Name : "", "Thread", "", IDX_Thread); csv.Write(jobRunModel.LogicalLengthMeters.ToString(), "Length", "0", IDX_Length); csv.Write(Math.Max(jobRunModel.JobRun.NumberOfUnits, 1).ToString(), "Number Of Units", "0", IDX_NumberOfUnits); csv.Write(jobRunModel.JobRun.StartDate.ToLocalTime().ToString(), "Start Time", "", IDX_StartTime); csv.Write(jobRunModel.Duration.ToStringUnlimitedHours(), "Duration", "", IDX_Duration); csv.Write(jobRunModel.Distance.ToString(), "Distance", "0", IDX_Distance); csv.Write(jobRunModel.ActualStartPosition.ToString(), "Start Position", "0", IDX_StartPosition); csv.Write(jobRunModel.ActualEndPosition.ToString(), "End Position", "0", IDX_EndPosition); csv.Write(jobRunModel.JobRun.JobRunStatus.ToString(), "Status", "", IDX_Status); // ===== Dynamic Outputs (only write columns with value > 0) ===== // Use reflection to read {Liquid}Quantity from jobRunModel.JobRun, case-insensitive. var jr = jobRunModel.JobRun; var qtyProps = jr.GetType() .GetProperties() .Where(p => p.Name.EndsWith("Quantity", StringComparison.OrdinalIgnoreCase)) .ToDictionary(p => p.Name.ToLowerInvariant()); for (int i = 0; i < liquids.Length; i++) { var lt = liquids[i]; var propKey = (lt.ToString() + "Quantity").ToLowerInvariant(); if (qtyProps.TryGetValue(propKey, out var pi)) { var obj = pi.GetValue(jr); double val = 0; if (obj != null) { try { val = Convert.ToDouble(obj); } catch { val = 0; } } if (val > 0) { var col = outputHeader(lt); csv.Write(val.ToString(), col, "0", OUTPUT_BASE + i); } } } // ===== Failure reason (last) ===== csv.Write(jobRunModel.JobRun.FailedMessage, "Failure Reason", "", IDX_FailureReason); csv.Next(); } csv.Save(dlg.FileName); _notification.ShowInfo("Report generated successfully."); } catch (Exception ex) { LogManager.Log(ex, "Error generating Statistics Job Runs report."); _notification.ShowError($"Error generating Statistics Job Runs report..\n{ex.Message}"); } } } #region GenerateS_StatisticsValueCollection /// /// Generates the statistics. /// protected void GenerateStatistics() { StatisticsValueCollection.Clean(); if (JobRuns.Count() == 0) return; GenerateTotalRunsCount(); GenerateTotalRunsLength(); GenerateTotalThreadConsumption(); GenerateRunsDuration(); GenerateAverageUploadDuration(); GenerateAverageHeatingDuration(); GeneratePieCharts(); CreateThreadConsumptionPerThread(); GenerateAllLiquidQuantities(); } protected void GenerateTotalRunsCount() {//Total Runs: int val = JobRuns.Count(); StatisticsValueCollection.AddStatisticsValue("Total Runs ", val, " "); } /// /// Generates the total length of the job runs. /// protected void GenerateTotalRunsLength() { double val = JobRuns.Where(z => z.JobRun.EndPosition > 0).Sum(x => x.Distance); StatisticsValueCollection.AddStatisticsValue("Total Runs Length", val, " m"); } /// /// Generates the duration and average of the job runs. /// protected void GenerateRunsDuration() { var selection = JobRuns.Where(z => z.JobRun.EndPosition > 0 && z.JobRun.EndDate != null && z.JobRun.ActualStartDate != null); double val = 0d; double average = 0d; if (selection != null && selection.Count() > 0) { val = selection.Sum(x => (x.JobRun.EndDate - x.JobRun.ActualStartDate).Value.TotalHours); average = selection.Average(x => (x.JobRun.EndDate - x.JobRun.ActualStartDate).Value.TotalMilliseconds); } StatisticsValueCollection.AddStatisticsValue("Total Dyeing Time", val, " hours"); StatisticsValueCollection.AddStatisticsValue("Average Dyeing Time", Math.Max(TimeSpan.FromMilliseconds(average).TotalHours, 0), " hours"); } /// /// Generates the average upload duration of the job runs. /// protected void GenerateAverageUploadDuration() { var average = (long)JobRuns.Where(z => z.JobRun.EndPosition > 0 && z.UploadDuration != null).Average(x => x.UploadDuration.Value.TotalMilliseconds); StatisticsValueCollection.AddStatisticsValue("Average Upload Duration", Math.Max(TimeSpan.FromMilliseconds(average).TotalMinutes, 0), " minutes"); } /// /// Generates the average duration heating of the job runs. /// protected void GenerateAverageHeatingDuration() { var average = JobRuns.Where(z => z.JobRun.EndPosition > 0 && z.HeatingDuration != null && z.HeatingDuration.Value.Ticks > 0).Average(x => x.HeatingDuration.Value.TotalMilliseconds); StatisticsValueCollection.AddStatisticsValue("Average Heating Duration", Math.Max(TimeSpan.FromMilliseconds(average).TotalMinutes, 0), " minutes"); } /// /// Generates the total thread consumption by EndPosition. /// protected void GenerateTotalThreadConsumption() { double val = JobRuns.Where(z => z.JobRun.EndPosition > 0).Sum(x => x.JobRun.EndPosition); StatisticsValueCollection.AddStatisticsValue("Total Dyeing Length", val, " m"); } /// /// Generates the pie charts in percentage: JobSource, JobRunStatus, Gradient. /// protected void GeneratePieCharts() { int PPCCount = JobRuns.Count(x => x.JobRun.Source == JobSource.Local); int MSCount = JobRuns.Count(x => x.JobRun.Source == JobSource.Remote); StatisticsValueCollection.GeneratePieJobSource(PPCCount, MSCount); int failedCount = JobRuns.Count(x => x.JobRun.JobRunStatus == JobRunStatus.Failed); int abortedCount = JobRuns.Count(x => x.JobRun.JobRunStatus == JobRunStatus.Aborted); int completedCount = JobRuns.Count(x => x.JobRun.JobRunStatus == JobRunStatus.Completed); StatisticsValueCollection.GeneratePieJobRunStatus(failedCount, abortedCount, completedCount); int gradientCount = JobRuns.Count(x => x.JobRun.IsGradient == true); int solidCount = JobRuns.Count(x => x.JobRun.IsGradient == false); StatisticsValueCollection.GeneratePieGradientSolid(gradientCount, solidCount); } /// /// Creates the thread consumption per thread. /// protected void CreateThreadConsumptionPerThread() { var temp = JobRuns.Where(z => z.JobRun.EndPosition > 0 && z.Rml != null).GroupBy(x => x.Rml.Name); List result = JobRuns.Where(z => z.JobRun.EndPosition > 0 && z.Rml != null && !String.IsNullOrEmpty(z.Rml.Name)).GroupBy(x => x.Rml.Name).Select(y => new StatisticsValue { Name = y.Key, Value = y.Sum(x => x.JobRun.EndPosition), Unit = "m" }).ToList(); StatisticsValueCollection.CreateThreadConsumptionPerThread(result); } /// /// Generates all liquid quantities. /// protected void GenerateAllLiquidQuantities() { var runs = JobRuns.Where(z => z.JobRun.EndPosition > 0 && z.JobRun.LiquidQuantitiesFast.Count > 0).ToList(); Dictionary total_quantities = new Dictionary(); foreach (LiquidTypes ltype in (LiquidTypes[])Enum.GetValues(typeof(LiquidTypes))) { total_quantities[ltype] = 0; } foreach (var run in runs) { foreach (var lq in run.JobRun.LiquidQuantitiesFast) { if (lq.Quantity < 0) { Debug.WriteLine($"Warning: JobRun '{run.JobRun.ID}' of machine '{run.Machine?.SerialNumber}' with user '{run.User?.Email}' started on '{run.JobRun.StartDate.ToLocalTime()}' ended on '{run.JobRun.EndDate.ToLocalTime()}' contains an invalid value '{lq.Quantity}' for {lq.LiquidType} quantity."); } total_quantities[lq.LiquidType] += Convert.ToUInt64(Math.Max(lq.Quantity, 0)); } } List allLiquidQuantities = total_quantities.Select(x => new TotalLiquidQuantityModel() { LiquidType = x.Key, Quantity = x.Value }).ToList(); allLiquidQuantities = allLiquidQuantities.Where(x => x.Quantity > 0).ToList(); StatisticsValueCollection.GenerateStatisticsLiquidQuantity(allLiquidQuantities); } #endregion } }