using Comal.Classes; using InABox.Clients; using InABox.Core; using InABox.DynamicGrid; using InABox.WPF; using PRS.Shared.Events; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Imaging; namespace PRS.Shared; public class EventGrid : DynamicDataGrid { private readonly BitmapImage _email = InABox.Wpf.Resources.email.AsBitmapImage(); private readonly BitmapImage _notification = InABox.Wpf.Resources.notification.AsBitmapImage(); private readonly BitmapImage _edit = InABox.Wpf.Resources.pencil.AsBitmapImage(); private Button? EnableButton = null; private Dictionary _subscribedSet = new(); public Guid EmployeeID { get; set; } protected override void Init() { base.Init(); HiddenColumns.Add(x => x.Data); HiddenColumns.Add(x => x.Enabled); HiddenColumns.Add(x => x.Visible); ActionColumns.Add(new DynamicMenuColumn(BuildMenu, getImage: Menu_GetImage) { ToolTip = Subscribed_ToolTip }); if (Security.IsAllowed()) { ActionColumns.Add(new DynamicImageColumn(_edit, Edit_Click)); EnableButton = AddButton("Disable", null, Enable_Click); EnableButton.Visibility = Visibility.Collapsed; } } protected override void SelectItems(CoreRow[]? rows) { base.SelectItems(rows); if(EnableButton is not null) { if(rows is not null && rows.Length > 0) { EnableButton.Visibility = Visibility.Visible; EnableButton.Content = rows.Any(x => !x.Get(x => x.Enabled)) ? "Enable" : "Disable"; } else { EnableButton.Visibility = Visibility.Collapsed; } } } private bool Enable_Click(Button button, CoreRow[] rows) { var items = LoadItems(rows); if(items.Any(x => !x.Enabled)) { foreach(var item in items) { item.Enabled = true; } Client.Save(items, "Event enabled."); return true; } else { foreach(var item in items) { item.Enabled = false; } Client.Save(items, "Event disabled."); return true; } } #region UIComponent private class UIComponent : DynamicGridGridUIComponent { protected override Brush? GetCellBackground(CoreRow row, DynamicColumnBase column) { if(row.Get(x => x.Enabled)) { return null; } else { return Colors.Gainsboro.ToBrush(0.5); } } } protected override IDynamicGridUIComponent CreateUIComponent() { return new UIComponent { Parent = this }; } #endregion protected override void DoReconfigure(DynamicGridOptions options) { base.DoReconfigure(options); if (Security.IsAllowed()) { options.AddRows = true; options.EditRows = true; options.DeleteRows = true; } else { options.AddRows = false; options.EditRows = false; options.DeleteRows = false; } } #region Action Columns private FrameworkElement? Subscribed_ToolTip(DynamicActionColumn column, CoreRow? row) { if(row is null) { return column.TextToolTip("Are you subscribed to this event?"); } else { return _subscribedSet.TryGetValue(row.Get(x => x.ID), out var type) ? (type == EventSubscriberType.Notification ? column.TextToolTip("You are subscribed to this event by notification.") : column.TextToolTip("You are subscribed to this event by email.")) : null; } } private void BuildMenu(DynamicMenuColumn column, CoreRow? row) { if (row is null) return; var menu = column.GetMenu(); var eventID = row.Get(x => x.ID); if (_subscribedSet.TryGetValue(eventID, out var type)) { menu.AddItem("Unsubscribe", null, row, Unsubscribe); if(type == EventSubscriberType.Notification) { menu.AddItem("Subscribe by Email", null, (row, EventSubscriberType.Email), ChangeSubscription); } else { menu.AddItem("Subscribe by Notification", null, (row, EventSubscriberType.Notification), ChangeSubscription); } } else { menu.AddItem("Subscribe by Notification", null, (row, EventSubscriberType.Notification), Subscribe); menu.AddItem("Subscribe by Email", null, (row, EventSubscriberType.Email), Subscribe); } } private BitmapImage? Menu_GetImage(CoreRow? row) { if (row is null) return _notification; return _subscribedSet.TryGetValue(row.Get(x => x.ID), out var type) ? (type == EventSubscriberType.Notification ? _notification : _email) : null; } private void ChangeSubscription((CoreRow row, EventSubscriberType Notification) tuple) { Unsubscribe(tuple.row, false); Subscribe(tuple); } private void Subscribe((CoreRow row, EventSubscriberType type) tuple) { var ev = tuple.row.ToObject(); var subscriber = new EventSubscriber(); subscriber.Event.CopyFrom(ev); subscriber.Employee.ID = EmployeeID; subscriber.SubscriberType = tuple.type; Client.Save(subscriber, ""); _subscribedSet.Add(ev.ID, subscriber.SubscriberType); Refresh(false, true); } private void Unsubscribe(CoreRow row) { Unsubscribe(row, true); } private void Unsubscribe(CoreRow row, bool refresh) { var eventID = row.Get(x => x.ID); var subscriber = Client.Query( new Filter(x => x.Employee.ID).IsEqualTo(EmployeeID) .And(x => x.Event.ID).IsEqualTo(eventID), Columns.None().Add(x => x.ID)) .ToObjects().FirstOrDefault(); if(subscriber is not null) { Client.Delete(subscriber, ""); } _subscribedSet.Remove(eventID); if (refresh) { Refresh(false, true); } } private bool Edit_Click(CoreRow? row) { if (row is null) return false; var ev = row.ToObject(); IEventData? data = null; if(ev.Data is not null && ev.Data.Length != 0) { data = EventUtils.Deserialize(ev.Data); } var type = ev.EventType; if(EventEditor.Run(ref type, ref data)) { ev.EventType = type; if(data is not null) { ev.Data = EventUtils.Serialize(data); } else { ev.Data = ""; } SaveItem(ev); return true; } else { return false; } } #endregion private readonly Column EventTypeColumn = new(x => x.EventType); private readonly Column NotificationExpressionColumn = new(x => x.NotificationExpression); private IEventData? EventData; protected override void BeforeLoad(IDynamicEditorForm form, Event[] items) { base.BeforeLoad(form, items); form.ReadOnly = !Security.IsAllowed(); var ev = items.First(); IEventData? data = null; if(ev.Data is not null && ev.Data.Length != 0) { data = EventUtils.Deserialize(ev.Data); } EventData = data; } protected override void CustomiseEditor(IDynamicEditorForm form, Event[] items, DynamicGridColumn column, BaseEditor editor) { base.CustomiseEditor(form, items, column, editor); if(EventTypeColumn.IsEqualTo(column.ColumnName) && editor is EnumLookupEditor enumEditor) { var ev = items.First(); var editButton = new EditorButton(ev, "Edit Event", 100, (e, i) => EditEvent_Click(form, e, i), false); enumEditor.Buttons = [editButton]; } else if(NotificationExpressionColumn.IsEqualTo(column.ColumnName) && editor is ExpressionEditor exprEditor) { exprEditor.OnGetVariables += ExprEditor_OnGetVariables; } } private IEnumerable ExprEditor_OnGetVariables() { return EventData?.Event.DataModelDefinition().GetVariables().Select(x => x.Name) ?? []; } private void EditEvent_Click(IDynamicEditorForm form, object editor, object? item) { if (item is not Event ev) return; var type = ev.EventType; var data = EventData; if(EventEditor.Run(ref type, ref data)) { EventData = data; ev.EventType = type; form.SetEditorValue(nameof(Event.EventType), type); if(data is not null) { ev.Data = EventUtils.Serialize(data); } else { ev.Data = ""; } } else { // We have to 'cancel' by just re-deserialising. if(ev.Data is not null && ev.Data.Length != 0) { EventData = EventUtils.Deserialize(ev.Data); } } } protected override void Reload(Filters criteria, Columns columns, ref SortOrder? sort, CancellationToken token, Action action) { if (!Security.IsAllowed()) { criteria.Add(new Filter(x => x.Visible).IsEqualTo(true)); } base.Reload(criteria, columns, ref sort, token, (data, error) => { if(data is not null) { var ids = data.ExtractValues(x => x.ID); _subscribedSet = Client.Query( new Filter(x => x.Employee.ID).IsEqualTo(EmployeeID) .And(x => x.Event.ID).InList(ids), Columns.None().Add(x => x.Event.ID).Add(x => x.SubscriberType)) .ToObjects().ToDictionary(x => x.Event.ID, x => x.SubscriberType); } action(data, error); }); } }