/// /// Copyright (c) 2020 Sensus Slovensko a.s. /// using System; using System.Collections.Generic; using System.Windows.Forms; using log4net; using NHibernate; using Config.Entities; using Config.CalendarEvent; using Events.Entities; using TBF.Resources; using TBF.UiBridge; namespace TBF.UI.Calendar { public partial class CalendarTabPageCtrl : UserControl { static readonly ILog log = LogManager.GetLogger(typeof(CalendarTabPageCtrl)); IList eventsFromComponents; IList customEvents; /// Custom events loaded from the local config DB Timer timer; DateTime lastTimeCalendarEventsServed; public CalendarTabPageCtrl() { InitializeComponent(); eventsFromComponents = new List(); Localize(); } void Localize() { newEventButton.Text = Strings.New_event; calendarEventsListViewEx.Columns.Add(Strings.Date_and_time, 100); calendarEventsListViewEx.Columns.Add(Strings.Frequency, 70); calendarEventsListViewEx.Columns.Add(Strings.Source, 50); calendarEventsListViewEx.Columns.Add(Strings.Title, 200); calendarEventsListViewEx.Columns.Add(Strings.Action); calendarEventsListViewEx.Columns.Add(Strings.Parameters); calendarEventsListViewEx.Columns.Add(Strings.On_exact_day); calendarEventsListViewEx.Columns.Add(Strings.Read_only); } void AddOne(ICalendarEvent evnt) { ListViewItem lvi = new ListViewItem(evnt.Date.ToString(evnt.AllDay ? Constants.DateFormat : Constants.DateTimeFormat)); lvi.SubItems.Add(Config.CalendarEvent.Utils.Freq2String(evnt.Frequency)); lvi.SubItems.Add(evnt.Source); lvi.SubItems.Add(evnt.Title); lvi.SubItems.Add(Config.CalendarEvent.Utils.Action2String(evnt.AutoAction)); lvi.SubItems.Add(evnt.Parameters); lvi.SubItems.Add(evnt.TriggerOnExactDayOnly ? Strings.yes : Strings.no); lvi.SubItems.Add(evnt.ReadOnly ? Strings.yes : Strings.no); lvi.Tag = evnt; calendarEventsListViewEx.Items.Add(lvi); } public void StartCalendar(IList eventsFromComponents) { this.eventsFromComponents = eventsFromComponents; try { /// Read custom events from the database ISession session = Config.FluentCommon.CreateSession(Users.Entities.DBKind.Config); customEvents = session.QueryOver().List(); TripplicateShiftCustomEvents(customEvents); /// Calendar foreach (var evnt in eventsFromComponents) calendarCtrl1.AddEvent(evnt); foreach (var evnt in customEvents) calendarCtrl1.AddEvent(evnt); /// List view in the right pane calendarEventsListViewEx.Items.Clear(); foreach (var e in customEvents) AddOne(e); foreach (var e in eventsFromComponents) if (!e.Hidden) AddOne(e); /// Serve events (determine if any event was triggered) lastTimeCalendarEventsServed = DateTime.Now; ServeCalendarEventsNotifWarnErrorFatal(lastTimeCalendarEventsServed, session, customEvents); } catch (Exception) { customEvents = new List(); log.ErrorFormat("Failed to load custom events from the LOCAL config database"); } calendarCtrl1.CalendarView = CalendarViews.Month; timer = new System.Windows.Forms.Timer(); timer.Interval = 300000; /// 300000 ms = 300 s = 5 min timer.Tick += new EventHandler(timer_Tick); timer.Start(); } /// /// After StartCalendar() was called this function is invoked every 5 minutes /// /// /// void timer_Tick(object sender, EventArgs args) { DateTime currentTime = DateTime.Now; if ((currentTime.Hour != lastTimeCalendarEventsServed.Hour) || (currentTime.Minute % 30) != (lastTimeCalendarEventsServed.Minute % 30)) { /// Serve events at the beginning of each half hour ServeCalendarEventsNotifWarnErrorFatal(currentTime); lastTimeCalendarEventsServed = currentTime; } } /// /// Triggers events corresponding to triggered motification.warning/error calendar events. /// /// Current time void ServeCalendarEventsNotifWarnErrorFatal(DateTime currentTime, ISession parentSession = null, IList customEventsFromDB = null) { IList eventsToTrigger = new List(); for (int i = eventsFromComponents.Count - 1; i >= 0; i--) { ICalendarEvent calEvent = eventsFromComponents[i]; AutoAction a = calEvent.AutoAction; if (a == AutoAction.Notification || a == AutoAction.Warning || a == AutoAction.Error || a == AutoAction.FatalErr) { if (Config.CalendarEvent.Utils.IsCalendarEventTrigerred(calEvent, currentTime)) { eventsToTrigger.Add(new Events.Entities.Event(null, calEvent.Source, EventClass.Metrology, ToSeverity(calEvent.AutoAction), calEvent.Title, calEvent.Parameters, null, SubscriberGroup.Metrology | SubscriberGroup.Maintenance | SubscriberGroup.Production | SubscriberGroup.Management)); if (calEvent.Frequency == Frequency.Once) { eventsFromComponents.Remove(calEvent); } else { Config.CalendarEvent.Utils.UpdateRecurringDate(calEvent, currentTime); } } } } try { var session = (parentSession != null) ? parentSession : Config.FluentCommon.CreateSession(Users.Entities.DBKind.Config); var customEvents = (customEventsFromDB != null) ? customEventsFromDB : session.QueryOver() .List(); for (int i = customEvents.Count - 1; i >= 0; i--) { CustomEvent calEvent = customEvents[i]; AutoAction a = calEvent.AutoAction; if (a == AutoAction.Notification || a == AutoAction.Warning || a == AutoAction.Error || a == AutoAction.FatalErr) { if (Config.CalendarEvent.Utils.IsCalendarEventTrigerred(calEvent, currentTime)) { eventsToTrigger.Add(new Events.Entities.Event(null, calEvent.Source, EventClass.Undefined, ToSeverity(calEvent.AutoAction), calEvent.Title, calEvent.Parameters, null, SubscriberGroup.Metrology | SubscriberGroup.Maintenance | SubscriberGroup.Production | SubscriberGroup.Management)); if (calEvent.Frequency == Frequency.Once) { session.Delete(calEvent); } else if (calEvent.UpdateRecurringDate(currentTime)) { session.SaveOrUpdate(calEvent); } } } } session.Flush(); } catch (Exception exc) { log.ErrorFormat("Failed to load or update CustomEvent-s in ServeTriggerEvtCalendarEvents(): {0}", exc.Message); } if (eventsToTrigger.Count > 0 && !string.IsNullOrEmpty(global::Events.DB.ConnectionString)) { try { ISession session = global::Events.DB.CreateSession(); global::Events.DB.LoadSubscribers(session); foreach (var e in eventsToTrigger) { TBF.UiBridge.Bridge.TriggerEvent(session, e); } session.Flush(); } catch (Exception exc) { log.ErrorFormat("Failed to trigger events in ServeTriggerEvtCalendarEvents(): {0}", exc.Message); } } } /// /// Returns an array of parameters of selected actions. /// This function is not invoked from UI thread. /// /// Selected AutoAction /// Max. number of calendar events served /// List of strings of triggered actions public static IList ServeCalendarEventsInvokeXY(AutoAction selectedAction, int maxCount = 1) { DateTime currentTime = DateTime.Now; IList parametersList = new List(); if (maxCount <= 0) return parametersList; try { ISession session = Config.FluentCommon.CreateSession(Users.Entities.DBKind.Config); var customEventsFromDB = session.QueryOver().List(); for (int i = customEventsFromDB.Count - 1; i >= 0; i--) { CustomEvent calEvent = customEventsFromDB[i]; if (calEvent.AutoAction == selectedAction && Config.CalendarEvent.Utils.IsCalendarEventTrigerred(calEvent, currentTime)) { parametersList.Add(calEvent.Parameters); if (calEvent.Frequency == Frequency.Once) { session.Delete(calEvent); } else if (calEvent.UpdateRecurringDate(currentTime)) { session.SaveOrUpdate(calEvent); } if (parametersList.Count >= maxCount) break; } } session.Flush(); } catch (Exception exc) { log.ErrorFormat("Failed to load or update CustomEvent-s in ServeSelectedCalendarEvents(): {0}", exc.Message); } if (parametersList.Count > 0) { /// TODO: Invoke calendar redraw in UI thread } return parametersList; } /// /// Convert calendar event AutoAction to event Severity /// /// AutoAction enum value /// Severity enum value Events.Entities.Severity ToSeverity(AutoAction action) { switch (action) { default: case AutoAction.Notification: return global::Events.Entities.Severity.Notification; case AutoAction.Warning: return global::Events.Entities.Severity.Warning; case AutoAction.Error: return global::Events.Entities.Severity.Error; case AutoAction.FatalErr: return global::Events.Entities.Severity.FatalError; } } void TripplicateShiftCustomEvents(IList customEvents) { /// Tripplicate each custom event with frequency 'EveryShift' for (int i = customEvents.Count - 1; i >= 0; i--) { if (customEvents[i].Frequency == Frequency.EveryShift) { DateTime dt = customEvents[i].Date; var ev2 = (CustomEvent)customEvents[i].Clone(); ev2.Date = new DateTime(dt.Year, dt.Month, dt.Day, (dt.Hour + 8) % 24, dt.Minute, 0); ev2.ReadOnly = true; customEvents.Insert(i + 1, ev2); var ev3 = (CustomEvent)customEvents[i].Clone(); ev3.Date = new DateTime(dt.Year, dt.Month, dt.Day, (dt.Hour + 16) % 24, dt.Minute, 0); ev3.ReadOnly = true; customEvents.Insert(i + 2, ev3); } } } private void newEventButton_Click(object sender, EventArgs ea) { EventDetailsForm dlg = new EventDetailsForm(); if (dlg.ShowDialog() == DialogResult.OK && dlg.NewEvent is CustomEvent) { try { ISession session = Config.FluentCommon.CreateSession(Users.Entities.DBKind.Config); session.SaveOrUpdate(dlg.NewEvent as CustomEvent); session.Flush(); customEvents = session.QueryOver().List(); TripplicateShiftCustomEvents(customEvents); /// Calendar calendarCtrl1.ClearEvents(); foreach (var e in eventsFromComponents) calendarCtrl1.AddEvent(e); foreach (var e in customEvents) calendarCtrl1.AddEvent(e); /// List view in the right pane calendarEventsListViewEx.Items.Clear(); foreach (var e in customEvents) AddOne(e); foreach (var e in eventsFromComponents) if (!e.Hidden) AddOne(e); } catch (Exception) { log.ErrorFormat("Failed to save new calendar event to the local config database"); } } } private void calendarEventsListViewEx_MouseDoubleClick(object sender, MouseEventArgs mea) { if (calendarEventsListViewEx.SelectedIndices.Count != 1) return; CustomEvent evnt = calendarEventsListViewEx.SelectedItems[0].Tag as CustomEvent; if (evnt == null || evnt.ReadOnly) return; EventDetailsForm dlg = new EventDetailsForm { Event = evnt }; if (dlg.ShowDialog() != DialogResult.OK) return; try { /// Re-read selected custom event from the database ISession session = Config.FluentCommon.CreateSession(Users.Entities.DBKind.Config); var cEvents = session.QueryOver() .Where(x => (x.Id == evnt.Id)) .List(); if (cEvents.Count == 1) { cEvents[0].Date = dlg.NewEvent.Date; cEvents[0].Frequency = dlg.NewEvent.Frequency; cEvents[0].AllDay = dlg.NewEvent.AllDay; cEvents[0].TriggerOnExactDayOnly = dlg.NewEvent.TriggerOnExactDayOnly; cEvents[0].Source = dlg.NewEvent.Source; cEvents[0].Title = dlg.NewEvent.Title; cEvents[0].AutoAction = dlg.NewEvent.AutoAction; cEvents[0].Parameters = dlg.NewEvent.Parameters; cEvents[0].Rank = dlg.NewEvent.Rank; cEvents[0].Hidden = dlg.NewEvent.Hidden; cEvents[0].ReadOnly = dlg.NewEvent.ReadOnly; cEvents[0].BackColor = dlg.NewEvent.BackColor; cEvents[0].TextColor = dlg.NewEvent.TextColor; cEvents[0].TooltipEnabled = dlg.NewEvent.TooltipEnabled; cEvents[0].CustomRecurringFunction = null; session.SaveOrUpdate(cEvents[0]); session.Flush(); customEvents = session.QueryOver().List(); TripplicateShiftCustomEvents(customEvents); /// Calendar calendarCtrl1.ClearEvents(); foreach (var e in eventsFromComponents) calendarCtrl1.AddEvent(e); foreach (var e in customEvents) calendarCtrl1.AddEvent(e); /// List view in the right pane calendarEventsListViewEx.Items.Clear(); foreach (var e in customEvents) AddOne(e); foreach (var e in eventsFromComponents) if (!e.Hidden) AddOne(e); } } catch (Exception) { MessageBox.Show("Cannot save change to the database", Strings.Error, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } } } }