using System; using System.Linq; using Artemis.Core.Internal; using Artemis.Storage.Entities.Profile.Abstract; using Artemis.Storage.Entities.Profile.Conditions; namespace Artemis.Core { public class EventCondition : CorePropertyChanged, INodeScriptCondition { private readonly string _displayName; private readonly EventConditionEntity _entity; private EventDefaultNode _eventNode; private TimeLineEventOverlapMode _eventOverlapMode; private DataModelPath? _eventPath; private DateTime _lastProcessedTrigger; public EventCondition(ProfileElement profileElement) { _entity = new EventConditionEntity(); _displayName = profileElement.GetType().Name; ProfileElement = profileElement; Script = new NodeScript($"Activate {_displayName}", $"Whether or not the event should activate the {_displayName}", profileElement.Profile); } internal EventCondition(EventConditionEntity entity, ProfileElement profileElement) { _entity = entity; _displayName = profileElement.GetType().Name; ProfileElement = profileElement; Load(); } /// /// Gets the script that drives the event condition /// public NodeScript Script { get; private set; } /// /// Gets or sets the path to the event that drives this event condition /// public DataModelPath? EventPath { set => SetAndNotify(ref _eventPath, value); get => _eventPath; } /// /// Gets or sets how the condition behaves when events trigger before the timeline finishes /// public TimeLineEventOverlapMode EventOverlapMode { get => _eventOverlapMode; set => SetAndNotify(ref _eventOverlapMode, value); } /// /// Updates the event node, applying the selected event /// public void UpdateEventNode() { if (EventPath?.GetValue() is not IDataModelEvent dataModelEvent) return; if (Script.Nodes.FirstOrDefault(n => n is EventDefaultNode) is EventDefaultNode existing) { existing.UpdateDataModelEvent(dataModelEvent); _eventNode = existing; } else { _eventNode = new EventDefaultNode(); _eventNode.UpdateDataModelEvent(dataModelEvent); } if (_eventNode.Pins.Any() && !Script.Nodes.Contains(_eventNode)) Script.AddNode(_eventNode); else Script.RemoveNode(_eventNode); } private bool Evaluate() { if (EventPath?.GetValue() is not IDataModelEvent dataModelEvent || dataModelEvent.LastTrigger <= _lastProcessedTrigger) return false; _lastProcessedTrigger = dataModelEvent.LastTrigger; if (!Script.ExitNodeConnected) return true; Script.Run(); return Script.Result; } /// public IConditionEntity Entity => _entity; /// public ProfileElement ProfileElement { get; } /// public bool IsMet { get; private set; } /// public void Update() { if (EventOverlapMode == TimeLineEventOverlapMode.Toggle) { if (Evaluate()) IsMet = !IsMet; } else { IsMet = Evaluate(); } } /// public void ApplyToTimeline(bool isMet, bool wasMet, Timeline timeline) { if (!isMet) { if (EventOverlapMode == TimeLineEventOverlapMode.Toggle) timeline.JumpToEnd(); return; } // Event overlap mode doesn't apply in this case if (timeline.IsFinished) { timeline.JumpToStart(); return; } // If the timeline was already running, look at the event overlap mode if (EventOverlapMode == TimeLineEventOverlapMode.Restart) timeline.JumpToStart(); else if (EventOverlapMode == TimeLineEventOverlapMode.Copy) timeline.AddExtraTimeline(); else if (EventOverlapMode == TimeLineEventOverlapMode.Toggle && !wasMet) timeline.JumpToStart(); // The remaining overlap mode is 'ignore' which requires no further action } /// public void Dispose() { Script.Dispose(); EventPath?.Dispose(); } #region Storage /// public void Load() { EventOverlapMode = (TimeLineEventOverlapMode) _entity.EventOverlapMode; Script = new NodeScript($"Activate {_displayName}", $"Whether or not the event should activate the {_displayName}", _entity.Script, ProfileElement.Profile); EventPath = new DataModelPath(_entity.EventPath); } /// public void Save() { _entity.EventOverlapMode = (int) EventOverlapMode; Script.Save(); _entity.Script = Script.Entity; EventPath?.Save(); _entity.EventPath = EventPath?.Entity; } /// public void LoadNodeScript() { Script.Load(); UpdateEventNode(); Script.LoadConnections(); } #endregion } }