using Comal.Classes; using InABox.Core; using InABox.Scripting; using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; namespace PRS.Shared.Events; public class SaveEvent : IEvent> where T : Entity { public Type Entity => typeof(T); public IEventDataModelDefinition DataModelDefinition() { return new SaveEventDataModelDefinition(this); } public Notification GenerateNotification(SaveEventDataModel model) { var notification = new Notification(); notification.Title = $"Updated {typeof(T).Name}"; notification.Description = $"Updated {typeof(T).Name}"; if(model.Entity.ID != Guid.Empty) { notification.EntityType = CoreUtils.EntityName(model.EntityType); notification.EntityID = model.Entity.ID; } return notification; } public void SerializeBinary(CoreBinaryWriter writer) { } public void DeserializeBinary(CoreBinaryReader reader) { } } public class SaveEventDataModelDefinition(SaveEvent ev) : IEventDataModelDefinition where T : Entity { private IEventVariable[]? variables; public SaveEvent Event { get; set; } = ev; public IEnumerable GetVariables() { if(variables is null) { variables = DatabaseSchema.AllProperties(Event.Entity).Select(x => new StandardEventVariable(x.Name, x.PropertyType)).ToArray(); variables.SortBy(x => x.Name); } return variables; } public IEventVariable? GetVariable(string name) { if(variables is null) { var prop = DatabaseSchema.Property(Event.Entity, name); if(prop is null) { return null; } else { return new StandardEventVariable(prop.Name, prop.PropertyType); } } else { return variables.FirstOrDefault(x => x.Name == name); } } } public class SaveEventDataModel(T entity) : IEventDataModel, ITypedEventDataModel where T : Entity { public T Entity { get; set; } = entity; public Type EntityType => typeof(T); public bool TryGetVariable(string name, out object? value) { var prop = DatabaseSchema.Property(typeof(T), name); if(prop != null) { value = prop.Getter()(Entity); return true; } else { value = null; return false; } } } #region Triggers [Caption("New Record")] public class CreatedSaveEventTrigger : IEventTrigger, SaveEventDataModel> where T : Entity { public bool Check(SaveEventDataModel dataModel) { return dataModel.Entity.HasOriginalValue(x => x.ID); } public void SerializeBinary(CoreBinaryWriter writer) { } public void DeserializeBinary(CoreBinaryReader reader) { } public string GetDescription() => "New Record"; } [Caption("Property Changed")] public class PropertyChangedSaveEventTrigger : IEventTrigger, SaveEventDataModel> where T : Entity { public IProperty? TriggerProperty { get; set; } public object? OldValue { get; set; } public object? NewValue { get; set; } public bool Check(SaveEventDataModel dataModel) { if(TriggerProperty is null) { return false; } if (!dataModel.Entity.HasOriginalValue(TriggerProperty.Name)) { return false; } if(OldValue is not null && !object.Equals(dataModel.Entity.OriginalValueList[TriggerProperty.Name], OldValue)) { return false; } if(NewValue is not null && !object.Equals(TriggerProperty.Getter()(dataModel.Entity), NewValue)) { return false; } return true; } public void SerializeBinary(CoreBinaryWriter writer) { if(TriggerProperty is null) { writer.Write(false); } else { writer.Write(true); writer.Write(TriggerProperty.Name); } } public void DeserializeBinary(CoreBinaryReader reader) { if(reader.ReadBoolean()) { TriggerProperty = DatabaseSchema.Property(typeof(T), reader.ReadString()); } else { TriggerProperty = null; } } public string GetDescription() { if(TriggerProperty is null) { return $"{typeof(T).GetCaption()} changed"; } else if(OldValue is null && NewValue is null) { return $"{typeof(T).GetCaption()}.{TriggerProperty.Name} changed"; } else if (OldValue is null) { return $"{typeof(T).GetCaption()}.{TriggerProperty.Name} changed to {NewValue}"; } else if (NewValue is null) { return $"{typeof(T).GetCaption()}.{TriggerProperty.Name} changed from {OldValue}"; } else { return $"{typeof(T).GetCaption()}.{TriggerProperty.Name} changed from {OldValue} to {NewValue}"; } } } [Caption("Custom Script")] public class ScriptSaveEventTrigger : IEventTrigger, SaveEventDataModel> where T : Entity { private ScriptDocument? _scriptDocument; private string? _script; public string? Script { get => _script; set { if(_script != value) { _script = value; _scriptDocument = null; } } } public string DefaultScript() { return @" using Comal.Classes; public class Module { public bool Check(SaveEventDataModel<" + typeof(T).Name + @"> model) { // Return true if model.Entity meets the requirements for this event trigger. return true; } }"; } public bool Check(SaveEventDataModel dataModel) { if (Script is null) return false; if(_scriptDocument is null) { _scriptDocument = new(Script); _scriptDocument.Compile(); } return _scriptDocument.Execute(methodname: "Check", parameters: [dataModel]); } public void SerializeBinary(CoreBinaryWriter writer) { writer.Write(Script ?? ""); } public void DeserializeBinary(CoreBinaryReader reader) { var script = reader.ReadString(); if (script.IsNullOrWhiteSpace()) { Script = null; } else { Script = script; } } public string GetDescription() => "Custom Script"; } #endregion #region Actions [Caption("Custom Script")] public class ScriptSaveEventAction : IEventAction> where T : Entity { private ScriptDocument? _scriptDocument; private string? _script; public string? Script { get => _script; set { if(_script != value) { _script = value; _scriptDocument = null; } } } public string DefaultScript() { return @" using Comal.Classes; public class Module { public object? Result { get; set; } public bool Execute(SaveEventDataModel<" + typeof(T).Name + @"> model) { // Do anything you want with model.Entity, 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 (Script is null) return null; if(_scriptDocument is null) { _scriptDocument = new(Script); _scriptDocument.SetValue("Result", null); _scriptDocument.Compile(); } var model = dataModel.RootModel>(); if(_scriptDocument.Execute(methodname: "Execute", parameters: [model])) { return _scriptDocument.GetValue("Result"); } else { return null; } } public IEnumerable ReferencedVariables() { yield break; } public void SerializeBinary(CoreBinaryWriter writer) { writer.Write(Script ?? ""); } public void DeserializeBinary(CoreBinaryReader reader) { var script = reader.ReadString(); if (script.IsNullOrWhiteSpace()) { Script = null; } else { Script = script; } } } [Caption("Create Entity")] public class CreateEntityAction : IEventAction> where T : Entity { public Type? EntityType { get; set; } public List Initializers { get; set; } = new List(); public object? Execute(IEventDataModel dataModel) { if(EntityType is null) { return null; } var entity = (Activator.CreateInstance(EntityType) as Entity)!; foreach(var initializer in Initializers) { initializer.Execute(entity, dataModel); } return entity; } public IEnumerable ReferencedVariables() { return Initializers.SelectMany(x => x.ReferencedVariables()); } public void SerializeBinary(CoreBinaryWriter writer) { if(EntityType is null) { writer.Write(false); } else { writer.Write(true); writer.Write(EntityType.EntityName()); } writer.Write(Initializers.Count); foreach(var init in Initializers) { init.SerializeBinary(writer); } } public void DeserializeBinary(CoreBinaryReader reader) { if(reader.ReadBoolean()) { EntityType = CoreUtils.GetEntity(reader.ReadString()); } else { EntityType = null; } var nInit = reader.ReadInt32(); for(int i = 0; i < nInit; ++i) { var init = new PropertyInitializer(reader, EntityType!); Initializers.Add(init); } } } public class PropertyInitializer { public IProperty Property { get; set; } private CoreExpression? _valueExpression; private CoreExpression ValueExpression { get { _valueExpression ??= new CoreExpression(Value, Property.PropertyType); return _valueExpression; } } private string _value; public string Value { get => _value; [MemberNotNull(nameof(_value))] set { if(value != _value) { _value = value; _valueExpression = null; } } } /// /// Only for use in serialisation. /// public PropertyInitializer(CoreBinaryReader reader, Type entityType) { DeserializeBinary(reader, entityType); } public PropertyInitializer(IProperty property, string value) { Property = property; Value = value; } public void Execute(Entity entity, IEventDataModel dataModel) { Property.Setter()(entity, ValueExpression.Evaluate(dataModel)); } public IEnumerable ReferencedVariables() { return ValueExpression.ReferencedVariables; } public void SerializeBinary(CoreBinaryWriter writer) { writer.Write(Property.Name); writer.Write(Value); } [MemberNotNull(nameof(Property), nameof(_value))] public void DeserializeBinary(CoreBinaryReader reader, Type entityType) { Property = DatabaseSchema.PropertyStrict(entityType, reader.ReadString()); Value = reader.ReadString(); } } #endregion