namespace PamhagenSysCtrl.Helpers.Pipeline { public record struct Path( INode Start, (IEdge Edge, INode Node)[] Hops ) { public readonly int Bends => Hops.Sum(h => (h.Node is not Valve && h.Node is not PipeJoin ? 1 : 0) + (h.Edge.Start.CenterX != h.Edge.End.CenterX && h.Edge.Start.CenterY != h.Edge.End.CenterY ? 1 : 0)); public readonly double Length => Hops.Sum(h => Math.Abs(h.Edge.Start.CenterX - h.Edge.End.CenterX) + Math.Abs(h.Edge.Start.CenterY - h.Edge.End.CenterY)); public readonly INode End => Hops.Last().Node; public readonly IEnumerable Nodes => [Start, .. Hops.Select(h => h.Node)]; public readonly bool Contains(INode node) => Nodes.Any(h => h == node); public readonly bool Matches(INode start, INode end) => Matches(start, null, end); public readonly bool Matches(INode start, INode? intermediate, INode end) => Start == start && End == end && (intermediate == null || Nodes.Any(n => n == intermediate)); public readonly IEnumerable Pumps => Nodes.Select(n => n as Pump).Where(p => p != null).Cast(); public readonly IEnumerable Valves => Nodes.Select(n => n as Valve).Where(v => v != null).Cast(); private readonly IEnumerable InnerAndBorderValves => Nodes .SelectMany(node => PamhagenGraph.TraverseSubgraph(node, (n) => n is ControlledValve || n is ISink || n is Pump)) .Select(e => e.End as ControlledValve) .Where(v => v != null) .Cast() .Distinct(); public readonly IEnumerable InnerValves => Nodes.Select(n => n as ControlledValve).Where(v => v != null).Cast(); public readonly IEnumerable BorderValves => InnerAndBorderValves.Except(InnerValves); public readonly bool HasActivePump => Nodes.Any(n => n is Pump p && p.IsActive); public readonly bool IsReady => InnerValves.All(v => v.IsOpen && v.WantOpen && v.IsLocked) && BorderValves.All(v => v.IsClosed && !v.WantOpen && v.IsLocked); public readonly void LockValves() { foreach (var v in InnerAndBorderValves) { v.LockedForPaths.Add(this); } } public readonly void UnlockValves() { foreach (var v in InnerAndBorderValves) { v.LockedForPaths.Remove(this); } } } }