using Comal.Classes; using InABox.Core; using InABox.Database; using InABox.Scripting; using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.Text; using System.Threading.Tasks; namespace PRS.Shared.Events; public class ScheduledEventDayOfWeek : BaseObject { [EditorSequence(1)] [Editable(Editable.Disabled)] public DayOfWeek DayOfWeek { get; set; } [EditorSequence(2)] [TimeOfDayEditor] public TimeSpan StartTime { get; set; } = TimeSpan.Zero; [EditorSequence(3)] [TimeOfDayEditor] public TimeSpan EndTime { get; set; } = new TimeSpan(23, 59, 59); [EditorSequence(4)] public bool Enabled { get; set; } = true; public ScheduledEventDayOfWeek() { } public ScheduledEventDayOfWeek(DayOfWeek dayOfWeek) { DayOfWeek = dayOfWeek; } static ScheduledEventDayOfWeek() { DefaultColumns.Add(x => x.DayOfWeek); DefaultColumns.Add(x => x.StartTime); DefaultColumns.Add(x => x.EndTime); } } /// /// Properties class to manage the timing of a scheduled event. /// /// /// /// This is fairly complex. First, we have the and properties. These function as expected. /// If is 3, and is , the event happens every three hours. Similarly, /// if is 4, and is , the event happens every four months. /// /// /// However, the other properties are dependent on . If is , /// or (that is, anything a day or smaller), the /// is used, which says which days of the week the schedule should occur, and at what time on those days. /// If the period is , then only the is used, and the event occurs /// at that time. Otherwise, the event occurs at regular intervals according to the frequency and period, beginning at /// and running until . /// /// /// Alternatively, if the period is greater than a day, is used, and whenever the schedule executes, it is updated by the /// frequency and period from the due date, and not from when the schedule actually occurred. /// /// public class ScheduledEventProperties : BaseObject { [EditorSequence(1)] public int Frequency { get; set; } = 1; [EditorSequence(2)] public SchedulePeriod Period { get; set; } = SchedulePeriod.Hour; [EditorSequence(3)] public DateTime NextSchedule { get; set; } [EditorSequence(4)] [Editable(Editable.Disabled)] [TimestampEditor] public DateTime LastExecution { get; set; } [EmbeddedListEditor(typeof(ScheduledEventDayOfWeek), AddRows = false)] public List DayOfWeekSettings { get; set; } = new() { new(DayOfWeek.Monday), new(DayOfWeek.Tuesday), new(DayOfWeek.Wednesday), new(DayOfWeek.Thursday), new(DayOfWeek.Friday), new(DayOfWeek.Saturday), new(DayOfWeek.Sunday), }; [OnDeserializing] private void OnDeserialisingMethod(StreamingContext context) { DayOfWeekSettings.Clear(); } } public class ScheduledEvent : IEvent, IPropertiesEvent { public ScheduledEventProperties Properties { get; set; } = new(); public IEventDataModelDefinition DataModelDefinition() { return new ScheduledEventDataModelDefinition(); } public Notification GenerateNotification(ScheduledEventDataModel model) { var notification = new Notification(); notification.Title = $"Scheduled event {model.Event.Code}: {model.Event.Description} has run."; notification.Description = $"Scheduled event {model.Event.Code}: {model.Event.Description} has run."; return notification; } public ScheduledEventProperties GetProperties() { return Properties; } public void SetProperties(ScheduledEventProperties properties) { Properties = properties; } } public class ScheduledEventDataModelDefinition : IEventDataModelDefinition { public IEventVariable? GetVariable(string name) { return null; } public IEnumerable GetVariables() { return []; } } public class ScheduledEventDataModel(Event ev) : IEventDataModel { public Event Event { get; set; } = ev; public bool TryGetVariable(string name, out object? value) { value = null; return false; } } #region Triggers [Caption("Custom Script")] public class ScriptScheduledEventTrigger : IEventTrigger { public string Description => "Custom Script"; private ScriptDocument? _scriptDocument; private ScriptDocument? ScriptDocument { get { if(_scriptDocument is null && Script is not null) { _scriptDocument = new(Script); _scriptDocument.Compile(); } return _scriptDocument; } } private string? _script; public string? Script { get => _script; set { if(_script != value) { _script = value; _scriptDocument = null; } } } public IEnumerable ReferencedVariables => []; public string DefaultScript() { return @"using PRS.Shared.Events; public class Module { public bool Check(ScheduledEventDataModel model) { // Return true if the requirements are met for this event trigger. return true; } }"; } public bool Check(ScheduledEventDataModel dataModel) { if (ScriptDocument is null) return false; return ScriptDocument.Execute(methodname: "Check", parameters: [dataModel]); } } #endregion #region Actions [Caption("Custom Script")] public class ScriptScheduledEventAction : IEventAction { private ScriptDocument? _scriptDocument; private ScriptDocument? ScriptDocument { get { if(_scriptDocument is null && Script is not null) { _scriptDocument = new(Script); _scriptDocument.SetValue("Result", null); _scriptDocument.Compile(); } return _scriptDocument; } } private string? _script; public string? Script { get => _script; set { if(_script != value) { _script = value; _scriptDocument = null; } } } public IEnumerable ReferencedVariables => []; public string Description => "Custom Script"; public string DefaultScript() { return @"using PRS.Shared.Events; public class Module { public object? Result { get; set; } public bool Execute(ScheduledEventDataModel model) { // Do anything you want, and then save return-value to 'Result', or leave it as 'null' if no return value is needed. return true; } }"; } public object? Execute(IEventDataModel dataModel) { if (ScriptDocument is null) return null; var model = dataModel.RootModel(); if(ScriptDocument.Execute(methodname: "Execute", parameters: [model])) { return ScriptDocument.GetValue("Result"); } else { return null; } } } #endregion