11using Requests . Options ;
2+ using System . Collections ;
23
34namespace Requests
45{
56 /// <summary>
67 /// Class to manage and merge more than one TRequest.
78 /// </summary>
89 /// <typeparam name="TRequest">A RequestObject class</typeparam>
9- public class RequestContainer < TRequest > : IRequest where TRequest : IRequest
10+ public class RequestContainer < TRequest > : IEnumerable < TRequest > , IRequest where TRequest : IRequest
1011 {
1112 private readonly List < TRequest > _requests = new ( ) ;
1213 private bool _isrunning = true ;
1314 private bool _isCanceled = false ;
1415 private bool _disposed = false ;
15- private Task _task = Task . CompletedTask ;
16+ private TaskCompletionSource ? _task ;
17+ private CancellationTokenSource _taskCancelationTokenSource = new ( ) ;
1618 private RequestState _state = RequestState . Paused ;
1719
1820 /// <summary>
1921 /// Merged task out the requests
2022 /// </summary>
21- public Task Task => _task ;
23+ public Task Task => _task ? . Task ?? Task . CompletedTask ;
2224
2325 /// <summary>
2426 /// State of this <see cref="RequestContainer{TRequest}"/>
@@ -28,6 +30,8 @@ public RequestState State
2830 get { return _state ; }
2931 protected set
3032 {
33+ if ( _state == value )
34+ return ;
3135 _state = value ;
3236 SynchronizationContext . Post ( ( o ) => StateChanged ? . Invoke ( ( IRequest ) o ! , value ) , this ) ;
3337 }
@@ -44,7 +48,12 @@ protected set
4448 public RequestPriority Priority => RequestPriority . Normal ;
4549
4650 /// <summary>
47- /// The synchronization context captured upon construction. This will never be null.
51+ /// Gets the number of <see cref="IRequest"/> conntained in the <see cref="RequestContainer{TRequest}"/>
52+ /// </summary>
53+ public int Count => _requests . Count ;
54+
55+ /// <summary>
56+ /// The synchronization context captured upon construction. This will never be null.
4857 /// </summary>
4958 protected SynchronizationContext SynchronizationContext { get ; }
5059
@@ -57,13 +66,17 @@ protected set
5766 /// Constructor to merge <see cref="IRequest"/> together
5867 /// </summary>
5968 /// <param name="requests"><see cref="IRequest"/>s to merge</param>
60- public RequestContainer ( params TRequest [ ] requests ) : this ( ) => Add ( requests ) ;
69+ public RequestContainer ( params TRequest [ ] requests ) : this ( ) => AddRange ( requests ) ;
6170
6271 /// <summary>
6372 /// Get all <see cref="IRequest"/> in this Container
6473 /// </summary>
6574 /// <returns>returns a <see cref="IRequest"/> array</returns>
66- public IReadOnlyList < TRequest > GetRequests ( ) => _requests ;
75+ public TRequest this [ int key ]
76+ {
77+ get => _requests [ key ] ;
78+ set => _requests [ key ] = value ;
79+ }
6780
6881 /// <summary>
6982 /// Creates a new <see cref="RequestContainer{TRequest}"/> that megres <see cref="RequestContainer{TRequest}"/> together.
@@ -72,17 +85,16 @@ protected set
7285 /// <returns></returns>
7386 public static RequestContainer < TRequest > MergeContainers ( params RequestContainer < TRequest > [ ] requestContainers )
7487 {
75- List < TRequest > requests = new ( ) ;
76- Array . ForEach ( requestContainers , requestContainer => requests . AddRange ( requestContainer . _requests ) ) ;
77- return new RequestContainer < TRequest > ( requests . ToArray ( ) ) ;
88+ RequestContainer < TRequest > newContainer = new ( ) ;
89+ Array . ForEach ( requestContainers , requestContainer => newContainer . AddRange ( requestContainer . ToArray ( ) ) ) ;
90+ return newContainer ;
7891 }
7992
8093 /// <summary>
8194 /// Main Contructor for <see cref="RequestContainer{TRequest}"/>.
8295 /// </summary>
8396 public RequestContainer ( ) => SynchronizationContext = SynchronizationContext . Current ?? new ( ) ;
8497
85-
8698 /// <summary>
8799 /// Adds a <see cref="IRequest"/> to the <see cref="RequestContainer{TRequest}"/>.
88100 /// </summary>
@@ -98,56 +110,80 @@ public virtual void Add(TRequest request)
98110
99111 request . StateChanged += OnStateChanged ;
100112 _requests . Add ( request ) ;
101- _task = Task . WhenAll ( _requests . Select ( request => request . Task ) ) ;
102- }
103-
104- private void OnStateChanged ( object ? sender , RequestState state )
105- {
106- if ( state == State )
107- return ;
108- if ( state != RequestState . Failed )
109- {
110- int [ ] states = _requests . Select ( req => ( int ) req . State ) . ToArray ( ) ;
111- int [ ] counter = new int [ 7 ] ;
112- foreach ( int value in states )
113- counter [ value ] ++ ;
114-
115- if ( counter [ ( int ) RequestState . Running ] > 1 )
116- state = RequestState . Running ;
117- else if ( counter [ ( int ) RequestState . Idle ] > 1 )
118- state = RequestState . Idle ;
119- else
120- {
121- int max = counter . Max ( ) ;
122- state = ( RequestState ) counter . ToList ( ) . IndexOf ( max ) ;
123- }
124- }
125- if ( state != State )
126- State = state ;
113+ NewTaskCompletion ( ) ;
114+ OnStateChanged ( this , request . State ) ;
127115 }
128116
129- async Task IRequest . StartRequestAsync ( )
117+ private void NewTaskCompletion ( )
130118 {
131- _isrunning = true ;
132- foreach ( TRequest ? request in _requests )
133- await request . StartRequestAsync ( ) ;
119+ _taskCancelationTokenSource . Cancel ( ) ;
120+ _taskCancelationTokenSource = new ( ) ;
121+ if ( Task . IsCompleted )
122+ _task = new ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
123+ Task . WhenAll ( _requests . Select ( request => request . Task ) ) . ContinueWith ( task => _task ? . TrySetResult ( ) , _taskCancelationTokenSource . Token ) ;
134124 }
135125
136126 /// <summary>
137127 /// Adds a range <see cref="IRequest"/> to the <see cref="RequestContainer{TRequest}"/>.
138128 /// </summary>
139129 /// <param name="requests">The <see cref="IRequest"/> to add.</param>
140- public virtual void Add ( params TRequest [ ] requests )
130+ public virtual void AddRange ( params TRequest [ ] requests )
141131 {
142132 if ( _isCanceled )
143133 Array . ForEach ( requests , request => request . Cancel ( ) ) ;
144134 else if ( _disposed )
145135 Array . ForEach ( requests , request => request . Dispose ( ) ) ;
146136 else if ( ! _isrunning )
147137 Array . ForEach ( requests , request => request . Pause ( ) ) ;
148-
138+ Array . ForEach ( requests , request => request . StateChanged += OnStateChanged ) ;
149139 _requests . AddRange ( requests ) ;
150- _task = Task . WhenAll ( _requests . Select ( request => request . Task ) ) ;
140+ NewTaskCompletion ( ) ;
141+ State = CalculateState ( ) ;
142+ }
143+
144+
145+ private void OnStateChanged ( object ? sender , RequestState state )
146+ {
147+ if ( state == State )
148+ return ;
149+ if ( state != RequestState . Failed )
150+ state = CalculateState ( ) ;
151+ State = state ;
152+ }
153+
154+ private RequestState CalculateState ( )
155+ {
156+ RequestState state ;
157+ IEnumerable < int > states = _requests . Select ( req => ( int ) req . State ) ;
158+ int [ ] counter = new int [ 7 ] ;
159+ foreach ( int value in states )
160+ counter [ value ] ++ ;
161+
162+ if ( counter [ 6 ] > 0 )
163+ state = RequestState . Failed ;
164+ else if ( counter [ 1 ] > 0 )
165+ state = RequestState . Running ;
166+ else if ( counter [ 5 ] > 0 )
167+ state = RequestState . Cancelled ;
168+ else if ( counter [ 0 ] > 0 )
169+ state = RequestState . Idle ;
170+ else if ( counter [ 4 ] > 0 )
171+ state = RequestState . Waiting ;
172+ else if ( counter [ 2 ] == _requests . Count )
173+ state = RequestState . Compleated ;
174+ else if ( counter [ 3 ] > 0 )
175+ state = RequestState . Paused ;
176+ else
177+ state = ( RequestState ) Array . IndexOf ( counter , counter . Max ( ) ) ;
178+
179+ return state ;
180+ }
181+
182+ async Task IRequest . StartRequestAsync ( )
183+ {
184+ _isrunning = true ;
185+ foreach ( TRequest ? request in _requests )
186+ await request . StartRequestAsync ( ) ;
151187 }
152188
153189 /// <summary>
@@ -156,10 +192,18 @@ public virtual void Add(params TRequest[] requests)
156192 /// <param name="requests">Request to remove</param>
157193 public virtual void Remove ( params TRequest [ ] requests )
158194 {
159- Array . ForEach ( requests , request => _requests . Remove ( request ) ) ;
160- if ( _requests . Count > 0 )
161- _task = Task . WhenAll ( _requests . Select ( request => request . Task ) ) ;
162- else _task = Task . CompletedTask ;
195+ Array . ForEach ( requests , request =>
196+ {
197+ _requests . Remove ( request ) ;
198+ request . StateChanged -= StateChanged ;
199+ } ) ;
200+ if ( _requests . Count > 0 && ! Task . IsCompleted )
201+ NewTaskCompletion ( ) ;
202+ else
203+ _task = null ;
204+ if ( State is not RequestState . Compleated and not RequestState . Paused )
205+ State = CalculateState ( ) ;
206+
163207 }
164208
165209 /// <summary>
@@ -180,6 +224,7 @@ public void Start()
180224 foreach ( TRequest ? request in _requests )
181225 request . Start ( ) ;
182226 }
227+
183228 /// <summary>
184229 /// Put every <see cref="IRequest"/> in Container on hold
185230 /// </summary>
@@ -203,5 +248,14 @@ public void Dispose()
203248 request . Dispose ( ) ;
204249 GC . SuppressFinalize ( this ) ;
205250 }
251+
252+ /// <summary>
253+ /// Returns an enumerator that iterates through the <see cref="RequestContainer{TRequest}"/>
254+ /// </summary>
255+ /// <returns> A <see cref="RequestContainer{TRequest}"/> .Enumerator for the <see cref="RequestContainer{TRequest}"/> .</returns>
256+ public IEnumerator < TRequest > GetEnumerator ( ) => _requests . GetEnumerator ( ) ;
257+
258+ /// <inheritdoc/>
259+ IEnumerator IEnumerable . GetEnumerator ( ) => _requests . GetEnumerator ( ) ;
206260 }
207261}
0 commit comments