using System;
using System.Linq;
using Artemis.Storage.Entities.Profile.Abstract;
using Artemis.Storage.Entities.Profile.Conditions;
namespace Artemis.Core
{
///
/// A group containing zero to many s which it evaluates using a boolean specific
/// operator
///
public class DataModelConditionGroup : DataModelConditionPart
{
private bool _disposed;
///
/// Creates a new instance of the class
///
///
public DataModelConditionGroup(DataModelConditionPart parent)
{
Parent = parent;
Entity = new DataModelConditionGroupEntity();
}
///
/// Creates a new instance of the class
///
///
///
public DataModelConditionGroup(DataModelConditionPart parent, DataModelConditionGroupEntity entity)
{
Parent = parent;
Entity = entity;
BooleanOperator = (BooleanOperator) Entity.BooleanOperator;
foreach (var childEntity in Entity.Children)
{
if (childEntity is DataModelConditionGroupEntity groupEntity)
AddChild(new DataModelConditionGroup(this, groupEntity));
else if (childEntity is DataModelConditionListEntity listEntity)
AddChild(new DataModelConditionList(this, listEntity));
else if (childEntity is DataModelConditionPredicateEntity predicateEntity)
AddChild(new DataModelConditionPredicate(this, predicateEntity));
else if (childEntity is DataModelConditionListPredicateEntity listPredicateEntity)
AddChild(new DataModelConditionListPredicate(this, listPredicateEntity));
}
}
///
/// Gets or sets the boolean operator of this group
///
public BooleanOperator BooleanOperator { get; set; }
internal DataModelConditionGroupEntity Entity { get; set; }
///
public override bool Evaluate()
{
if (_disposed)
throw new ObjectDisposedException("DataModelConditionGroup");
// Empty groups are always true
if (Children.Count == 0)
return true;
// Groups with only one child ignore the boolean operator
if (Children.Count == 1)
return Children[0].Evaluate();
switch (BooleanOperator)
{
case BooleanOperator.And:
return Children.All(c => c.Evaluate());
case BooleanOperator.Or:
return Children.Any(c => c.Evaluate());
case BooleanOperator.AndNot:
return Children.All(c => !c.Evaluate());
case BooleanOperator.OrNot:
return Children.Any(c => !c.Evaluate());
default:
throw new ArgumentOutOfRangeException();
}
}
#region IDisposable
///
protected override void Dispose(bool disposing)
{
_disposed = true;
foreach (var child in Children)
child.Dispose();
base.Dispose(disposing);
}
#endregion
///
internal override bool EvaluateObject(object target)
{
if (_disposed)
throw new ObjectDisposedException("DataModelConditionGroup");
// Empty groups are always true
if (Children.Count == 0)
return true;
// Groups with only one child ignore the boolean operator
if (Children.Count == 1)
return Children[0].EvaluateObject(target);
return BooleanOperator switch
{
BooleanOperator.And => Children.All(c => c.EvaluateObject(target)),
BooleanOperator.Or => Children.Any(c => c.EvaluateObject(target)),
BooleanOperator.AndNot => Children.All(c => !c.EvaluateObject(target)),
BooleanOperator.OrNot => Children.Any(c => !c.EvaluateObject(target)),
_ => throw new ArgumentOutOfRangeException()
};
}
internal override void Save()
{
Entity.BooleanOperator = (int) BooleanOperator;
Entity.Children.Clear();
Entity.Children.AddRange(Children.Select(c => c.GetEntity()));
foreach (var child in Children)
child.Save();
}
internal override DataModelConditionPartEntity GetEntity()
{
return Entity;
}
}
///
/// Represents a boolean operator
///
public enum BooleanOperator
{
///
/// All the conditions in the group should evaluate to true
///
And,
///
/// Any of the conditions in the group should evaluate to true
///
Or,
///
/// All the conditions in the group should evaluate to false
///
AndNot,
///
/// Any of the conditions in the group should evaluate to false
///
OrNot
}
}