using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Xamarin.PropertyEditing
{
///
/// Represents groups of availability constraints that are ORed together.
///
///
/// The individual availability constraints are ANDed together within the group to produce the groups' result.
/// The groups are ORed together, so only one needs to have its constituents all true.
///
public class MultiAvailabilityConstraint
: IAvailabilityConstraint
{
public MultiAvailabilityConstraint (IEnumerable> constraintGroups)
{
if (constraintGroups == null)
throw new ArgumentNullException (nameof(constraintGroups));
List properties = new List ();
this.constraints = new List> ();
foreach (var g in constraintGroups) {
var group = new List ();
foreach (var c in g) {
if (c.ConstrainingProperties != null) {
foreach (var p in c.ConstrainingProperties) {
if (!properties.Contains (p))
properties.Add (p);
}
}
group.Add (c);
}
this.constraints.Add (group);
}
ConstrainingProperties = properties;
}
public IReadOnlyList ConstrainingProperties {
get;
}
public async Task GetIsAvailableAsync (IObjectEditor editor)
{
HashSet> tasks = new HashSet> ();
for (int i = 0; i < this.constraints.Count; i++) {
tasks.Add (Task.WhenAll (this.constraints[i].Select (c => c.GetIsAvailableAsync (editor)).ToArray ())
.ContinueWith (t => {
if (t.IsFaulted)
return false;
return Array.TrueForAll (t.Result, b => b);
}, TaskScheduler.Default));
}
// The groups of constraints are ||ed, each group's constraints are &&ed
while (tasks.Count > 0) {
var task = await Task.WhenAny (tasks).ConfigureAwait (false);
if (task.IsFaulted)
return false;
if (task.Result)
return true;
tasks.Remove (task);
}
return false;
}
private readonly List> constraints;
}
}