using Comal.Classes; using InABox.Clients; using InABox.Core; using InABox.DynamicGrid; using InABox.WPF; using Microsoft.CodeAnalysis.VisualBasic.Syntax; using org.omg.PortableInterceptor; using PRSDesktop.Forms; using PRSDesktop.WidgetGroups; using System; using System.Collections.Generic; using System.ComponentModel; using System.Globalization; using System.Linq; using System.Runtime.CompilerServices; using System.Threading.Tasks; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Media; using System.Windows.Media.Imaging; using InABox.Configuration; using Client = InABox.Clients.Client; using System.Windows; using InABox.Wpf; namespace PRSDesktop.Dashboards; public class EquipmentSchedulesDashboardProperties : IUserConfigurationSettings, IDashboardProperties { public bool OnlyShowSchedules { get; set; } = true; public DynamicGridSelectedFilterSettings Filters { get; set; } = new(); } public class ScheduleViewModel : INotifyPropertyChanged { private Guid employeeID; private string? employeeName; private string? employeeMobile; private string? employeeEmail; private BitmapImage? employeeImage; public bool HasEmployee => EmployeeID != Guid.Empty; public Guid ID { get; set; } public string Title { get; set; } public DateTime DueDate { get; set; } public BitmapImage? EmployeeImage { get => employeeImage; set { employeeImage = value; NotifyPropertyChanged(); } } public Guid EmployeeID { get => employeeID; set { employeeID = value; NotifyPropertyChanged(nameof(HasEmployee)); } } public string? EmployeeName { get => employeeName; set { employeeName = value; NotifyPropertyChanged(); } } public string? EmployeeMobile { get => employeeMobile; set { employeeMobile = value; NotifyPropertyChanged(); NotifyPropertyChanged(nameof(EmployeeContact)); } } public string? EmployeeEmail { get => employeeEmail; set { employeeEmail = value; NotifyPropertyChanged(); NotifyPropertyChanged(nameof(EmployeeContact)); } } public string? EmployeeContact { get { var str = ""; if (EmployeeEmail is not null) str = EmployeeEmail; if(EmployeeMobile is not null) { if (string.IsNullOrWhiteSpace(str)) { str = EmployeeMobile; } else { str += $", {EmployeeMobile}"; } } return string.IsNullOrWhiteSpace(str) ? null : str; } } public event PropertyChangedEventHandler? PropertyChanged; private void NotifyPropertyChanged([CallerMemberName] string propertyName = "") { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } public class EquipmentScheduleViewModel { public bool HasLocation { get; set; } public Guid ID { get; set; } public string Code { get; set; } public string Description { get; set; } public List Schedules { get; set; } } [ValueConversion(typeof(DateTime), typeof(SolidColorBrush))] class ScheduleBackgroundConverter : IValueConverter { public Color GetColor(DateTime date) { var diff = date - DateTime.Today; if (diff < TimeSpan.Zero) return Colors.Salmon; else if (diff.TotalDays <= 7) return Colors.Orange; else if (diff.Days <= 30) return Colors.LightYellow; else return Colors.LightGreen; } public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var date = (DateTime)value; var color = GetColor(date); return new SolidColorBrush(color); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } /// /// Interaction logic for EquipmentSchedulesDashboard.xaml /// public partial class EquipmentSchedulesDashboard : UserControl, IDashboardWidget, IHeaderDashboard, IBasePanel { public EquipmentSchedulesDashboardProperties Properties { get; set; } = null!; public DashboardHeader Header { get; set; } = new(); public event LoadSettings? LoadSettings; public event SaveSettings? SaveSettings; public event DataModelUpdateEvent? OnUpdateDataModel; private Dictionary Equipment = new(); private Dictionary EmployeeImages = new(); private Dictionary Employees = new(); private List Models = new(); public EquipmentSchedulesDashboard() { InitializeComponent(); } public void Setup() { LoadEmployeeImages(); SetupHeader(); } #region IBasePanel public string SectionName => "EquipmentSchedules"; public DataModel DataModel(Selection selection) { return new AutoDataModel(new Filter().All()); } public bool IsReady { get; set; } public void CreateToolbarButtons(IPanelHost host) { } public Dictionary Selected() { return new(); } public void Heartbeat(TimeSpan time) { } #endregion #region Header private CheckBox ShowSchedulesBox = null!; private FilterButton FilterBtn = null!; public void SetupHeader() { ShowSchedulesBox = new CheckBox { Content = "Only show schedules?", IsChecked = Properties.OnlyShowSchedules, VerticalAlignment = VerticalAlignment.Center }; ShowSchedulesBox.Checked += ShowSchedulesBox_Checked; ShowSchedulesBox.Unchecked += ShowSchedulesBox_Checked; FilterBtn = new FilterButton( new GlobalConfiguration(nameof(EquipmentSchedulesDashboard)), new UserConfiguration(nameof(EquipmentSchedulesDashboard))) { Width = 25, Height = 25, Padding = new() }; FilterBtn.BuiltInFilters.Add(new("Exclude Disposed", () => new Filter(x => x.Disposed).IsEqualTo(null))); FilterBtn.SetSettings(Properties.Filters, false); FilterBtn.OnFiltersSelected += FilterBtn_OnFiltersSelected; FilterBtn.OnFilterRefresh += FilterBtn_OnFilterRefresh; Header.BeginUpdate() .Clear() .Add(ShowSchedulesBox) .AddRight(FilterBtn) .EndUpdate(); } private void ShowSchedulesBox_Checked(object sender, RoutedEventArgs e) { Properties.OnlyShowSchedules = ShowSchedulesBox.IsChecked == true; Refresh(); } private void FilterBtn_OnFilterRefresh() { Refresh(); } private void FilterBtn_OnFiltersSelected(DynamicGridSelectedFilterSettings filters) { Properties.Filters = filters; } #endregion private void LoadEmployeeImages() { Task.Run(() => { var employees = new Client() .Query( LookupFactory.DefineFilter(), Columns.None().Add( x => x.ID, x => x.Thumbnail.ID, x => x.Name, x => x.Mobile, x => x.Email)) .ToObjects().ToList(); var documents = new Client() .Query( new Filter(x => x.ID).InList(employees.Select(x => x.Thumbnail.ID).ToArray()), Columns.None().Add(x => x.ID).Add(x => x.Data)) .ToDictionary(x => x.ID, x => x.Data); return new { Employees = employees, Documents = documents }; }).ContinueWith((task) => { EmployeeImages = task.Result.Employees.ToDictionary( x => x.ID, x => { var document = task.Result.Documents.GetValueOrDefault(x.Thumbnail.ID); if (document is null) return null; return ImageUtils.BitmapImageFromBytes(document); }); Employees = task.Result.Employees.ToDictionary(x => x.ID, x => x); lock (Models) { var anonymous = PRSDesktop.Resources.anonymous.AsBitmapImage(); foreach (var model in Models) { foreach (var schedule in model.Schedules) { var employee = Employees?.GetValueOrDefault(schedule.EmployeeID); schedule.EmployeeImage = EmployeeImages?.GetValueOrDefault(schedule.EmployeeID) ?? anonymous; schedule.EmployeeMobile = employee?.Mobile; schedule.EmployeeName = employee?.Name; schedule.EmployeeEmail = employee?.Email; } } } }, TaskScheduler.FromCurrentSynchronizationContext()); } public void Refresh() { var eqFilter = FilterBtn.GetFilter(); var results = Client.QueryMultiple( new KeyedQueryDef( eqFilter, Columns.None().Add(x => x.ID) .Add(x => x.Code) .Add(x => x.Description) .Add(x => x.TrackerLink.ID) .Add(x => x.TrackerLink.Location.Latitude) .Add(x => x.TrackerLink.Location.Longitude) .Add(x => x.TrackerLink.Location.Timestamp)), new KeyedQueryDef( new Filter(x => x.DocumentClass).IsEqualTo(typeof(Equipment).EntityName()) .And(x => x.IncludeInAggregate).IsEqualTo(true), Columns.None().Add(x => x.ID) .Add(x => x.Title) .Add(x => x.DueDate) .Add(x => x.DocumentID) .Add(x => x.EmployeeLink.ID))); var equipmentItems = results.Get().Rows.Select(x => x.ToObject()); Equipment = equipmentItems.ToDictionary(x => x.ID, x => x); var schedules = results.Get().Rows .Select(x => x.ToObject()) .GroupBy(x => x.DocumentID) .ToDictionary(x => x.Key, x => x.OrderBy(x => x.DueDate).ToList()); var anonymous = PRSDesktop.Resources.anonymous.AsBitmapImage(); lock (Models) { Models = new List(); foreach (var equipmentItem in equipmentItems) { var equipmentSchedules = schedules.GetValueOrDefault(equipmentItem.ID); if(equipmentSchedules is null && Properties.OnlyShowSchedules) { continue; } var model = new EquipmentScheduleViewModel { Code = equipmentItem.Code, Description = equipmentItem.Description, ID = equipmentItem.ID, HasLocation = equipmentItem.TrackerLink.ID != Guid.Empty }; model.Schedules = (equipmentSchedules ?? Enumerable.Empty()) .Select(x => { var employee = Employees.GetValueOrDefault(x.EmployeeLink.ID); return new ScheduleViewModel { Title = x.Title, DueDate = x.DueDate, ID = x.ID, EmployeeImage = EmployeeImages.GetValueOrDefault(x.EmployeeLink.ID) ?? anonymous, EmployeeID = x.EmployeeLink.ID, EmployeeEmail = employee?.Email, EmployeeMobile = employee?.Mobile, EmployeeName = employee?.Name }; }) .ToList() ?? []; Models.Add(model); } } EquipmentList.ItemsSource = Models; } public void Shutdown(CancelEventArgs? cancel) { } private void Border_ContextMenuOpening(object sender, ContextMenuEventArgs e) { if (sender is not FrameworkElement element || element.Tag is not Guid equipmentID) return; var menu = new ContextMenu(); menu.AddItem("View Equipment", null, equipmentID, ViewEquipment_Click); menu.AddItem("Add Schedule", null, equipmentID, CreateSchedule_Click); menu.IsOpen = true; e.Handled = true; } private void CreateSchedule_Click(Guid equipmentID) { var schedule = new Schedule(); schedule.DocumentClass = typeof(Equipment).EntityName(); schedule.DocumentID = equipmentID; if (DynamicGridUtils.EditEntity(schedule)) { Refresh(); } } private void Grid_ContextMenuOpening(object sender, ContextMenuEventArgs e) { if (sender is not FrameworkElement element || element.Tag is not Guid equipmentID) return; var menu = new ContextMenu(); menu.AddItem("Add Schedule", null, equipmentID, CreateSchedule_Click); menu.IsOpen = true; e.Handled = true; } private void Schedule_ContextMenuOpening(object sender, ContextMenuEventArgs e) { if (sender is not FrameworkElement element || element.Tag is not Guid scheduleID) return; var menu = new ContextMenu(); menu.AddItem("View Schedule", null, scheduleID, ViewSchedule_Click); menu.IsOpen = true; e.Handled = true; } private void Employee_ContextMenuOpening(object sender, ContextMenuEventArgs e) { if (sender is not FrameworkElement element || element.Tag is not Guid employeeID) return; if (employeeID == Guid.Empty) return; var menu = new ContextMenu(); menu.AddItem("View Employee", null, employeeID, ViewEmployee_Click); menu.IsOpen = true; e.Handled = true; } private void ViewEquipment_Click(Guid equipmentID) { if (DynamicGridUtils.EditEntity(equipmentID)) { Refresh(); } } private void ViewSchedule_Click(Guid scheduleID) { if (DynamicGridUtils.EditEntity(scheduleID)) { Refresh(); } } private void ViewEmployee_Click(Guid employeeID) { if (DynamicGridUtils.EditEntity(employeeID)) { Refresh(); } } private void EquipmentLocation_Click(object sender, System.Windows.RoutedEventArgs e) { var equipmentID = (Guid)(sender as Button)!.Tag; if (!Equipment.TryGetValue(equipmentID, out var equipment)) return; var form = new MapForm( equipment.TrackerLink.Location.Latitude, equipment.TrackerLink.Location.Longitude, equipment.TrackerLink.Location.Timestamp); form.ShowDialog(); } } public class EquipmentSchedulesDashboardElement : DashboardElement { }