using Beam.Data; using Beam.Downloaders; using Beam.Dynamic; using Beam.Models; namespace Beam.Fluent { public static partial class DownloadBuilder { /* ──────────────────────────── Stage types ─────────────────────────── */ private sealed record LinkStage( WebResource Source, State Initial, BeamDataContext Data, DownloadContextBuilder CtxBuilder) : ILinkStage, IAlternativeLinkStage { private State? endState; private bool linksFrozen = false; public ITransformStage WithLink() { var link = Data.Templates[Source.Key].Builder.Build(Initial); CtxBuilder.WithLinks([link]); return new TransformStage(Source, Data, CtxBuilder); } public ITransformStage WithLinkGenerator() { var template = Data.Templates[Source.Key]; var generator = StringEnumerable.FromGenerator(new OrderedLinkGenerator( template.Builder, new NumberedStateChanger(template.Factory.Behavior), Initial, endState)); CtxBuilder.WithLinks(generator); linksFrozen = true; return new TransformStage(Source, Data, CtxBuilder); } public IAlternativeTransformStage WithLinks(IEnumerable links) { CtxBuilder.WithLinks(links); return new TransformStage(Source, Data, CtxBuilder); } public ILinkStage WithRange(Range range) { if (linksFrozen) throw new InvalidOperationException($"WithRange must be called before WithLinkGenerator"); if (range.End.Value < range.Start.Value) throw new ArgumentOutOfRangeException(nameof(range), $" start must be < end"); var template = Data.Templates[Source.Key]; var stateChanger = new NumberedStateChanger(template.Factory.Behavior); endState = Initial.Copy(); stateChanger.Apply(Initial, range.Start.Value - 1); stateChanger.Apply(endState, range.End.Value - 1); return this; } } } }