using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tango.BL.Entities;
using Tango.BL.Enumerations;
using Tango.PMR.Diagnostics;
namespace Tango.MachineStudio.Common.EventLogging
{
/// <summary>
/// Represents a database events logger.
/// </summary>
public interface IEventLogger
{
/// <summary>
/// Occurs when a new machine event has been logged.
/// </summary>
event EventHandler<MachinesEvent> NewLog;
/// <summary>
/// Gets or sets a value indicating whether to save the incoming events to database.
/// </summary>
bool SaveToDB { get; set; }
/// <summary>
/// Logs the specified machine event.
/// </summary>
/// <param name="machineEvent">The machine event.</param>
void Log(MachinesEvent machineEvent);
/// <summary>
/// Logs the specified event type.
/// </summary>
/// <param name="eventType">Type of the event.</param>
/// <param name="message">The message.</param>
void Log(EventTypes eventType, String message, bool write_to_db = true);
/// <summary>
/// Logs the specified hardware event.
/// </summary>
/// <param name="hardwareEvent">The hardware event.&lusing LiveCharts;
using LiveCharts.Wpf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Media;
using Tango.BL.Enumerations;
using Tango.MachineStudio.Common;
using Tango.MachineStudio.Statistics.Models;
using Tango.BL.Entities;
using Tango.SharedUI;
using Tango.BL;
using Tango.MachineStudio.Common.Notifications;
using System.Threading.Tasks;
using Tango.Core.Commands;
namespace Tango.MachineStudio.Statistics.ViewModels
{
public class ChartsViewVM : ViewModel
{
private INotificationProvider _notification;
//private ObservablesContext _context;
private List<JobRunStatisticsModel> _job_runs;
private bool _loaded;
#region Properties
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(); RaisePropertyChanged("EndDate"); }
}
private DateTime _endDate;
public DateTime EndDate
{
get { return _endDate; }
set { _endDate = value; RaisePropertyChangedAuto(); RaisePropertyChanged("StartDate"); }
}
public RelayCommand LoadJobRunsCommand { get; set; }
#endregion
public ChartsViewVM(INotificationProvider notificationProvider)
{
_notification = notificationProvider;
StartDate = DateTime.Now.AddMonths(-1);
EndDate = DateTime.Now;
LoadJobRunsCommand = new RelayCommand(async () => await LoadJobRuns(), () => IsFree);
}
#region Generate Charts
private async Task LoadJobRuns()
{
using (_notification.PushTaskItem("Loading statistics..."))
{
try
{
IsFree = false;
await Task.Factory.StartNew(() =>
{
using (var db = ObservablesContext.CreateDefault())
{
DateTime startUtc = new DateTime(StartDate.Year, StartDate.Month, StartDate.Day, 0, 0, 0).ToUniversalTime();
TimeSpan offsetTime = (EndDate.Date == DateTime.Now.Date) ? DateTime.Now.TimeOfDay : new TimeSpan(23, 59, 59);
DateTime endUtc = EndDate.ToUniversalTime() + offsetTime;
_job_runs = db.JobRuns.Where(x => (x.StartDate <= endUtc && x.StartDate >= startUtc)).OrderBy(x => x.StartDate).ToList().Select(x => new JobRunStatisticsModel(x)).ToList();
foreach (var run in _job_runs)
{
run.LoadMachine(db).GetAwaiter().GetResult();
}
}
});
InvokeUIOnIdle(() =>
{
if (_loaded)
{
OnDateRangeChanged();
}
});
_loaded = true;
}
catch (Exception ex)
{
LogManager.Log(ex, "Error loading statistics.");
}
finally
{
IsFree = true;
}
}
}
private List<JobRunStatisticsModel> 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<JobRunStatisticsModel> 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<DateTime> CreateDates(DateTime start, DateTime end)
{
for (DateTime date = start.Date; date.Date <= end.Date; date = date.AddDays(1))
{
yield return date;
}
}
private void GenerateTimelineJobStatusChart()
{
TimelineJobStatusSeries = new LabeledSeriesCollection()
{
Title = "Job Runs Status",
ChartTitle = "Number Of Runs",
LabelsTitle = "Date",
SeriesColors = new List<Color>()
{
Colors.Green,
Colors.Orange,
Colors.Red,
},
};
Series completed_job_runs = new ColumnSeries()
{
Title = "Completed",
Values = new ChartValues<int>(),
Fill = Brushes.Green,
MinWidth = 1,
};
Series aborted_job_runs = new ColumnSeries()
{
Title = "Aborted",
Values = new ChartValues<int>(),
Fill = Brushes.Orange,
MinWidth = 1,
};
Series failed_job_runs = new ColumnSeries()
{
Title = "Failed",
Values = new ChartValues<int>(),
Fill = Brushes.Red,
MinWidth = 1,
};
if (EndDate - StartDate > TimeSpan.FromDays(40))
{
completed_job_runs = new LineSeries()
{
Title = "Completed",
Values = new ChartValues<int>(),
Fill = new SolidColorBrush(Colors.Green) { Opacity = 0.5 },
MinWidth = 1,
PointGeometry = null,
StrokeThickness = 0,
};
aborted_job_runs = new LineSeries()
{
Title = "Aborted",
Values = new ChartValues<int>(),
Fill = new SolidColorBrush(Colors.Orange) { Opacity = 0.5 },
MinWidth = 1,
PointGeometry = null,
StrokeThickness = 0,
};
failed_job_runs = new LineSeries()
{
Title = "Failed",
Values = new ChartValues<int>(),
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<Color> colors = new List<Color>();
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<int>() { count },
Fill = new SolidColorBrush(colors[index++]),
DataLabels = true,
ToolTip = group.First().FailedMessage,
};
PieJobFailedReasons.SeriesCollection.Add(series);
}
}
private void GeneratePrintPerWeekChart()
{
List<JobRunStatisticsModel> range_job_runs = GetJobRunsByDateRange(StartDate, EndDate);
Dictionary<Machine, List<double>> weeks_print_avg = new Dictionary<Machine, List<double>>();
//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<double>();
}
//Create all available dates
List<DateTime> 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<Machine, double> week_print_avg = new Dictionary<Machine, double>();
//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<Color>()
{
},
};
//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>() { (int)machine.Value },
Fill = new SolidColorBrush(PrintPerWeekSeries.SeriesColors[index++]),
DataLabels = true,
ToolTip = machine.Key.SerialNumber,
};
PrintPerWeekSeries.SeriesCollection.Add(series);
}
}
#endregion
#region Filter by Date
public void OnDateRangeChanged()
{
if (_job_runs != null)// && _job_runs.Count > 0)// && _loaded)
{
GenerateTimelineJobStatusChart();
GeneratePieFailedReasonsChart();
GeneratePrintPerWeekChart();
}
}
#endregion
}
}