using LiveCharts; using LiveCharts.Wpf; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Media; using Tango.BL; using Tango.BL.Enumerations; using Tango.Core.Helpers; using Tango.MachineStudio.Common; using Tango.MachineStudio.Statistics.Models; using System.Data.Entity; using Tango.MachineStudio.Common.Notifications; using Tango.BL.Entities; namespace Tango.MachineStudio.Statistics.ViewModels { public class MainViewVM : StudioViewModel { private ObservablesContext _context; private List _job_runs; private bool rendered; private INotificationProvider _notification; private bool _loaded; private LabeledSeriesCollection _timelineJobStatusSeries; public LabeledSeriesCollection TimelineJobStatusSeries { get { return _timelineJobStatusSeries; } set { _timelineJobStatusSeries = value; RaisePropertyChangedAuto(); } } private LabeledSeriesCollection _pieJobFailedReasons; public LabeledSeriesCollection PieJobFailedReasons { get { return _pieJobFailedReasons; } set { _pieJobFailedReasons = value; RaisePropertyChangedAuto(); } } private LabeledSeriesCollection _printPerWeekSeries; public LabeledSeriesCollection PrintPerWeekSeries { get { return _printPerWeekSeries; } set { _printPerWeekSeries = value; RaisePropertyChangedAuto(); } } private DateTime _startDate; public DateTime StartDate { get { return _startDate; } set { _startDate = value; RaisePropertyChangedAuto(); OnDateRangeChanged(); } } private DateTime _endDate; public DateTime EndDate { get { return _endDate; } set { _endDate = value; RaisePropertyChangedAuto(); OnDateRangeChanged(); } } private DateTime _minDate; public DateTime MinDate { get { return _minDate; } set { _minDate = value; RaisePropertyChangedAuto(); } } private DateTime _maxDate; public DateTime MaxDate { get { return _maxDate; } set { _maxDate = value; RaisePropertyChangedAuto(); } } public MainViewVM(INotificationProvider notificationProvider) { _notification = notificationProvider; StartDate = DateTime.Now.AddMonths(-1); EndDate = DateTime.Now; } public override void OnApplicationReady() { } private List GetJobRunsByDateRange(DateTime startDate, DateTime endTime, JobRunStatus? status = null) { return _job_runs.Where(x => x.StartDate.ToLocalTime() >= startDate && x.StartDate.ToLocalTime() <= endTime && (status == null || x.JobRunStatus == status)).ToList(); } private List GetJobRunsByDate(DateTime date, JobRunStatus? status = null) { return _job_runs.Where(x => x.StartDate.ToLocalTime().Date == date.Date && (status == null || x.JobRunStatus == status)).ToList(); } private IEnumerable CreateDates(DateTime start, DateTime end) { for (DateTime date = start.Date; date.Date <= end.Date; date = date.AddDays(1)) { yield return date; } } public override async void OnNavigatedTo() { base.OnNavigatedTo(); if (rendered) return; rendered = true; using (_notification.PushTaskItem("Loading statistics...")) { IsFree = false; await Task.Factory.StartNew(() => { _context = ObservablesContext.CreateDefault(); _job_runs = _context.JobRuns.OrderBy(x => x.StartDate).ToList().Select(x => new JobRunModel(x)).ToList(); foreach (var run in _job_runs) { run.LoadMachine(_context).GetAwaiter().GetResult(); } }); if (_job_runs.Count > 0) { MinDate = _job_runs.Min(x => x.StartDate); MaxDate = _job_runs.Max(x => x.StartDate); } InvokeUIOnIdle(() => { OnDateRangeChanged(); }); _loaded = true; IsFree = true; } } private void OnDateRangeChanged() { if (_job_runs != null && _job_runs.Count > 0 && _loaded) { GenerateTimelineJobStatusChart(); GeneratePieFailedReasonsChart(); GeneratePrintPerWeekChart(); } } private void GenerateTimelineJobStatusChart() { TimelineJobStatusSeries = new LabeledSeriesCollection() { Title = "Job Runs Status", ChartTitle = "Number Of Runs", LabelsTitle = "Date", SeriesColors = new List() { Colors.Green, Colors.Orange, Colors.Red, }, }; Series completed_job_runs = new ColumnSeries() { Title = "Completed", Values = new ChartValues(), Fill = Brushes.Green, MinWidth = 1, }; Series aborted_job_runs = new ColumnSeries() { Title = "Aborted", Values = new ChartValues(), Fill = Brushes.Orange, MinWidth = 1, }; Series failed_job_runs = new ColumnSeries() { Title = "Failed", Values = new ChartValues(), Fill = Brushes.Red, MinWidth = 1, }; if (EndDate - StartDate > TimeSpan.FromDays(40)) { completed_job_runs = new LineSeries() { Title = "Completed", Values = new ChartValues(), Fill = new SolidColorBrush(Colors.Green) { Opacity = 0.5 }, MinWidth = 1, PointGeometry = null, StrokeThickness = 0, }; aborted_job_runs = new LineSeries() { Title = "Aborted", Values = new ChartValues(), Fill = new SolidColorBrush(Colors.Orange) { Opacity = 0.5 }, MinWidth = 1, PointGeometry = null, StrokeThickness = 0, }; failed_job_runs = new LineSeries() { Title = "Failed", Values = new ChartValues(), Fill = new SolidColorBrush(Colors.Red) { Opacity = 0.5 }, MinWidth = 1, PointGeometry = null, StrokeThickness = 0, }; } foreach (var date in CreateDates(StartDate, EndDate)) { completed_job_runs.Values.Add(GetJobRunsByDate(date, JobRunStatus.Completed).Count()); aborted_job_runs.Values.Add(GetJobRunsByDate(date, JobRunStatus.Aborted).Count()); failed_job_runs.Values.Add(GetJobRunsByDate(date, JobRunStatus.Failed).Count()); TimelineJobStatusSeries.Labels.Add(date.ToShortDateString()); } TimelineJobStatusSeries.SeriesCollection.Add(failed_job_runs); TimelineJobStatusSeries.SeriesCollection.Add(aborted_job_runs); TimelineJobStatusSeries.SeriesCollection.Add(completed_job_runs); } private void GeneratePieFailedReasonsChart() { var groups = GetJobRunsByDateRange(StartDate, EndDate, JobRunStatus.Failed).GroupBy(x => x.FailedMessage).OrderBy(x => x.Count()); List colors = new List(); int max = groups.Count() > 0 ? groups.Max(x => x.Count()) : 0; for (int i = 0; i < groups.Count(); i++) { int count = groups.ElementAt(i).Count(); double alpha = Math.Max(((double)(count) / max * 200), 20); colors.Add(Color.FromArgb((byte)alpha, 200, 0, 0)); } PieJobFailedReasons = new LabeledSeriesCollection() { Title = "Job Failure Reasons", SeriesColors = colors, }; int index = 0; foreach (var group in groups) { int count = group.Count(); var series = new PieSeries() { Title = group.First().FailedMessage, Values = new ChartValues() { count }, Fill = new SolidColorBrush(colors[index++]), DataLabels = true, ToolTip = group.First().FailedMessage, }; PieJobFailedReasons.SeriesCollection.Add(series); } } private void GeneratePrintPerWeekChart() { List range_job_runs = GetJobRunsByDateRange(StartDate, EndDate); Dictionary> weeks_print_avg = new Dictionary>(); //Init machines weeks averages dictionary. foreach (var machine in range_job_runs.Select(x => x.Machine).OrderBy(x => x.Name).DistinctBy(x => x.Guid)) { weeks_print_avg[machine] = new List(); } //Create all available dates List all_dates = range_job_runs.Select(x => x.StartDate).ToList(); //get first Sunday. DateTime current_sunday = all_dates.FirstOrDefault(x => x.DayOfWeek == DayOfWeek.Sunday); if (current_sunday != null && all_dates.Count > 0) { //Iterate over each week starting from the earliest Sunday. while (current_sunday <= all_dates.Last()) { var week_job_runs = range_job_runs.Where(x => x.EndPosition > 10 && x.StartDate >= current_sunday && x.StartDate <= current_sunday.AddDays(7)).ToList(); foreach (var machine_job_runs in week_job_runs.GroupBy(x => x.Machine)) { weeks_print_avg[machine_job_runs.Key].Add(machine_job_runs.Select(x => x.EndPosition).Average()); } current_sunday = current_sunday.AddDays(8); } } Dictionary week_print_avg = new Dictionary(); //Init machines week average dictionary. foreach (var machine in weeks_print_avg) { if (machine.Value.Count > 0) { week_print_avg[machine.Key] = machine.Value.Average(); } } //Init chart series PrintPerWeekSeries = new LabeledSeriesCollection() { Title = "Average Printed Thread Per Week (m)", ChartTitle = "Average Print Per Week (m)", LabelsTitle = "Date", SeriesColors = new List() { }, }; //Init series colors intensity by number of prints. double max = week_print_avg.Count > 0 ? week_print_avg.Max(x => x.Value) : 0; foreach (var machine in week_print_avg) { double a = (machine.Value / max); PrintPerWeekSeries.SeriesColors.Add(Color.FromArgb((byte)(255d * (machine.Value / max)), 0, 200, 0)); } //Init columns. int index = 0; foreach (var machine in week_print_avg) { var series = new ColumnSeries() { Title = machine.Key.Name, Values = new ChartValues() { (int)machine.Value }, Fill = new SolidColorBrush(PrintPerWeekSeries.SeriesColors[index++]), DataLabels = true, ToolTip = machine.Key.SerialNumber, }; PrintPerWeekSeries.SeriesCollection.Add(series); } } } }