using System;
using System.Linq;
using Artemis.Storage.Entities.Profile.Abstract;
using Artemis.Storage.Entities.Profile.Conditions;
namespace Artemis.Core;
///
/// Represents a condition that is based on a data model value
///
public class StaticCondition : CorePropertyChanged, INodeScriptCondition
{
private readonly string _displayName;
private readonly StaticConditionEntity _entity;
private StaticPlayMode _playMode;
private StaticStopMode _stopMode;
private bool _wasMet;
///
/// Creates a new instance of the class
///
public StaticCondition(RenderProfileElement profileElement)
{
_entity = new StaticConditionEntity();
_displayName = profileElement.GetType().Name;
ProfileElement = profileElement;
Script = new NodeScript($"Activate {_displayName}", $"Whether or not this {_displayName} should be active", profileElement.Profile);
}
internal StaticCondition(StaticConditionEntity entity, RenderProfileElement profileElement)
{
_entity = entity;
_displayName = profileElement.GetType().Name;
ProfileElement = profileElement;
Script = null!;
Load();
}
///
/// Gets the script that drives the static condition
///
public NodeScript Script { get; private set; }
///
/// Gets or sets the mode in which the render element starts its timeline when display conditions are met
///
public StaticPlayMode PlayMode
{
get => _playMode;
set => SetAndNotify(ref _playMode, value);
}
///
/// Gets or sets the mode in which the render element stops its timeline when display conditions are no longer met
///
public StaticStopMode StopMode
{
get => _stopMode;
set => SetAndNotify(ref _stopMode, value);
}
///
public IConditionEntity Entity => _entity;
///
public RenderProfileElement ProfileElement { get; }
///
public bool IsMet { get; private set; }
///
public void Update()
{
_wasMet = IsMet;
// No need to run the script if the parent isn't met anyway
bool parentConditionMet = ProfileElement.Parent is not RenderProfileElement renderProfileElement || renderProfileElement.DisplayConditionMet;
if (!parentConditionMet)
{
IsMet = false;
return;
}
if (!Script.ExitNodeConnected)
{
IsMet = true;
}
else
{
Script.Run();
IsMet = Script.Result;
}
}
///
public void UpdateTimeline(double deltaTime)
{
if (IsMet && !_wasMet && ProfileElement.Timeline.IsFinished)
ProfileElement.Timeline.JumpToStart();
else if (!IsMet && _wasMet && StopMode == StaticStopMode.SkipToEnd)
ProfileElement.Timeline.JumpToEndSegment();
ProfileElement.Timeline.Update(TimeSpan.FromSeconds(deltaTime), PlayMode == StaticPlayMode.Repeat && IsMet);
}
///
public void OverrideTimeline(TimeSpan position)
{
ProfileElement.Timeline.Override(position, PlayMode == StaticPlayMode.Repeat && position > ProfileElement.Timeline.Length);
}
///
public void Dispose()
{
Script.Dispose();
}
#region Storage
///
public void Load()
{
PlayMode = (StaticPlayMode) _entity.PlayMode;
StopMode = (StaticStopMode) _entity.StopMode;
Script = _entity.Script != null
? new NodeScript($"Activate {_displayName}", $"Whether or not this {_displayName} should be active", _entity.Script, ProfileElement.Profile)
: new NodeScript($"Activate {_displayName}", $"Whether or not this {_displayName} should be active", ProfileElement.Profile);
}
///
public void Save()
{
_entity.PlayMode = (int) PlayMode;
_entity.StopMode = (int) StopMode;
// If the exit node isn't connected and there is only the exit node, don't save the script
if (!Script.ExitNodeConnected && Script.Nodes.Count() == 1)
{
_entity.Script = null;
}
else
{
Script.Save();
_entity.Script = Script.Entity;
}
}
///
public INodeScript? NodeScript => Script;
///
public void LoadNodeScript()
{
Script.Load();
}
#endregion
}
///
/// Represents a mode for render elements to start their timeline when display conditions are met
///
public enum StaticPlayMode
{
///
/// Continue repeating the main segment of the timeline while the condition is met
///
Repeat,
///
/// Only play the timeline once when the condition is met
///
Once
}
///
/// Represents a mode for render elements to stop their timeline when display conditions are no longer met
///
public enum StaticStopMode
{
///
/// When conditions are no longer met, finish the the current run of the main timeline
///
Finish,
///
/// When conditions are no longer met, skip to the end segment of the timeline
///
SkipToEnd
}