using System.Collections; using Artemis.Core; using Artemis.Core.Events; using Artemis.VisualScripting.Nodes.List.Screens; namespace Artemis.VisualScripting.Nodes.List; [Node("List Operator (Advanced)", "Checks if any/all/no values in the input list match a condition", "List", InputType = typeof(IEnumerable), OutputType = typeof(bool))] public class ListOperatorPredicateNode : Node, IDisposable { private readonly object _scriptLock = new(); private readonly ListOperatorPredicateStartNode _startNode; public ListOperatorPredicateNode() { _startNode = new ListOperatorPredicateStartNode {X = -200}; InputList = CreateInputPin(); Output = CreateOutputPin(); InputList.PinConnected += InputListOnPinConnected; } public InputPin InputList { get; } public OutputPin Output { get; } public NodeScript? Script { get; private set; } public override void Initialize(INodeScript script) { Storage ??= new ListOperatorEntity(); lock (_scriptLock) { Script = Storage?.Script != null ? new NodeScript("Is match", "Determines whether the current list item is a match", Storage.Script, script.Context, new List {_startNode}) : new NodeScript("Is match", "Determines whether the current list item is a match", script.Context, new List {_startNode}); } } /// public override void Evaluate() { if (Storage == null) return; if (InputList.Value == null) { Output.Value = Storage.Operator == ListOperator.None; return; } lock (_scriptLock) { if (Script == null) return; if (Storage.Operator == ListOperator.Any) Output.Value = InputList.Value.Cast().Any(EvaluateItem); else if (Storage.Operator == ListOperator.All) Output.Value = InputList.Value.Cast().All(EvaluateItem); else if (Storage.Operator == ListOperator.None) Output.Value = InputList.Value.Cast().All(v => !EvaluateItem(v)); } } private bool EvaluateItem(object item) { if (Script == null) return false; _startNode.Item = item; Script.Run(); return Script.Result; } private void UpdateStartNode() { Type? type = InputList.ConnectedTo.FirstOrDefault()?.Type; // List must be generic or there's no way to tell what objects it contains in advance, that's not supported for now if (type is not {IsGenericType: true}) return; Type listType = type.GetGenericArguments().Single(); _startNode?.ChangeType(listType); } private void InputListOnPinConnected(object? sender, SingleValueEventArgs e) { lock (_scriptLock) { UpdateStartNode(); Script?.LoadConnections(); } } #region IDisposable /// public void Dispose() { Script?.Dispose(); Script = null; } #endregion }