diff --git a/MBS.Framework/Logic/Conditional/Condition.cs b/MBS.Framework/Logic/Conditional/Condition.cs new file mode 100644 index 0000000..3e45de0 --- /dev/null +++ b/MBS.Framework/Logic/Conditional/Condition.cs @@ -0,0 +1,184 @@ +// +// Condition.cs - represents a conditional statement which defines a comparison of a named property with a constant value +// +// Author: +// Michael Becker +// +// Copyright (c) 2011-2020 Mike Becker's Software +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +namespace MBS.Framework.Logic.Conditional +{ + /// + /// Represents a conditional statement which defines a comparison of a named property with a constant value. + /// + public class Condition : IConditionalStatement + { + private string mvarPropertyName = String.Empty; + /// + /// The name of the property against which to test when the method is called + /// passing in a property reference. + /// + public string PropertyName + { + get { return mvarPropertyName; } + set { mvarPropertyName = value; } + } + + private ConditionComparison mvarComparison = ConditionComparison.Equal; + /// + /// The type of comparison to use when testing this . + /// + public ConditionComparison Comparison + { + get { return mvarComparison; } + set { mvarComparison = value; } + } + + private object mvarValue = null; + /// + /// The value against which to test when the method is called. + /// + public object Value + { + get { return mvarValue; } + set { mvarValue = value; } + } + + /// + /// Creates a with the specified property name, comparison, and value. + /// + /// The name of the property against which to test when the method is called passing in a property reference. + /// The type of comparison to use. + /// The value against which to test when the method is called. + public Condition(string propertyName, ConditionComparison comparison, object value) + { + mvarPropertyName = propertyName; + mvarComparison = comparison; + mvarValue = value; + } + + /// + /// Evaluates the conditional statement based on the given criteria. + /// + /// The set of values against which to evaluate the conditional statement. + /// True if the conditions are satisfied; false otherwise. + public bool Test(params System.Collections.Generic.KeyValuePair[] propertyValues) + { + bool retval = true; + foreach (System.Collections.Generic.KeyValuePair propertyValue in propertyValues) + { + if (propertyValue.Key == mvarPropertyName) + { + retval &= Test(propertyValue.Value); + } + } + return retval; + } + /// + /// Evaluates the conditional statement based on the given criteria. + /// + /// The set of values against which to evaluate the conditional statement. + /// True if the conditions are satisfied; false otherwise. + public bool Test(System.Collections.Generic.Dictionary propertyValues) + { + bool retval = true; + foreach (System.Collections.Generic.KeyValuePair propertyValue in propertyValues) + { + if (propertyValue.Key == mvarPropertyName) + { + retval &= Test(propertyValue.Value); + } + } + return retval; + } + /// + /// Evaluates the conditional statement based on the given criterion. + /// + /// The value against which to evaluate the conditional statement. + /// True if the conditions are satisfied; false otherwise. + public bool Test(object propertyValue) + { + // would you like meatballs with your spaghetti code? + bool returnValue = false; + + if ((mvarComparison & ConditionComparison.Equal) == ConditionComparison.Equal) + { + if (propertyValue == null) + { + // our comparison object is null, so we can't .Equals it + // just do regular == with the constant null in that case + returnValue |= (mvarValue == null); + } + else + { + returnValue |= (propertyValue.Equals(mvarValue)); + } + } + if ((mvarComparison & ConditionComparison.ReferenceEqual) == ConditionComparison.ReferenceEqual) + { + if (propertyValue == null) + { + // our comparison object is null, so we can't .Equals it + // just do regular == with the constant null in that case + returnValue |= (mvarValue == null); + } + else + { + returnValue |= (propertyValue == mvarValue); + } + } + if (((mvarComparison & ConditionComparison.GreaterThan) == ConditionComparison.GreaterThan) && (propertyValue is IComparable)) + { + if (propertyValue == null) + { + // can ANYTHING ever be greater than or less than null? + returnValue |= false; + } + else + { + // we need to directly invoke IComparable.CompareTo here since we can't (usually) + // do > or < on objects... not sure what to do if the object doesn't implement + // IComparable though + returnValue |= ((propertyValue as IComparable).CompareTo(mvarValue) > 0); + } + } + if (((mvarComparison & ConditionComparison.LessThan) == ConditionComparison.LessThan) && (propertyValue is IComparable)) + { + if (propertyValue == null) + { + // can ANYTHING ever be greater than or less than null? + returnValue |= false; + } + else + { + // we need to directly invoke IComparable.CompareTo here since we can't (usually) + // do > or < on objects... not sure what to do if the object doesn't implement + // IComparable though + returnValue |= ((propertyValue as IComparable).CompareTo(mvarValue) < 0); + } + } + if ((mvarComparison & ConditionComparison.Not) == ConditionComparison.Not) + { + // we have a Not in there, so negate our return value + returnValue = !returnValue; + } + + // did you have as much fun reading this as I did writing it? + bool from_hell = returnValue; + return from_hell; + } + } +} diff --git a/MBS.Framework/Logic/Conditional/ConditionCombination.cs b/MBS.Framework/Logic/Conditional/ConditionCombination.cs new file mode 100644 index 0000000..2ef42fb --- /dev/null +++ b/MBS.Framework/Logic/Conditional/ConditionCombination.cs @@ -0,0 +1,42 @@ +// +// ConditionCombination.cs - indicates the type of combination applied to a series of conditional statements +// +// Author: +// Michael Becker +// +// Copyright (c) 2011-2020 Mike Becker's Software +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +namespace MBS.Framework.Logic.Conditional +{ + /// + /// Indicates the type of combination applied to a series of conditional statements. + /// + public enum ConditionCombination + { + /// + /// Returns true if all of the conditional statements in this group are true. + /// + And, + /// + /// Returns true if at least one of the conditional statements in this group are true. + /// + Or, + /// + /// Combines the conditional statements in this group and returns the inverted value of the combined result. + /// + Xor + } +} diff --git a/MBS.Framework/Logic/Conditional/ConditionComparison.cs b/MBS.Framework/Logic/Conditional/ConditionComparison.cs new file mode 100644 index 0000000..561c1b2 --- /dev/null +++ b/MBS.Framework/Logic/Conditional/ConditionComparison.cs @@ -0,0 +1,53 @@ +// +// ConditionComparison.cs - indicates the type of comparison to use with a conditional statement +// +// Author: +// Michael Becker +// +// Copyright (c) 2011-2020 Mike Becker's Software +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; + +namespace MBS.Framework.Logic.Conditional +{ + /// + /// Indicates the type of comparison to use with a conditional statement. + /// + [Flags()] + public enum ConditionComparison + { + /// + /// Returns true if the two values are equal by value. + /// + Equal = 1, + /// + /// Returns true if the two values are equal by reference (or by value if they are value types). + /// + ReferenceEqual = 2, + /// + /// Returns true if the first value is greater than the second value. + /// + GreaterThan = 4, + /// + /// Returns true if the first value is less than the second value. + /// + LessThan = 8, + /// + /// Negates the conditional comparison. + /// + Not = 16 + } +} diff --git a/MBS.Framework/Logic/Conditional/ConditionGroup.cs b/MBS.Framework/Logic/Conditional/ConditionGroup.cs new file mode 100644 index 0000000..472af55 --- /dev/null +++ b/MBS.Framework/Logic/Conditional/ConditionGroup.cs @@ -0,0 +1,179 @@ +// +// ConditionGroup.cs - a group of IConditionalStatements joined by a ConditionCombination +// +// Author: +// Michael Becker +// +// Copyright (c) 2011-2020 Mike Becker's Software +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +namespace MBS.Framework.Logic.Conditional +{ + /// + /// A group of s joined by a . + /// + public class ConditionGroup : IConditionalStatement + { + /// + /// Creates a new with no conditional statements specified and a + /// default of . + /// + public ConditionGroup() + { + // I know it's initialized to this but I'm doing it here for clarity's sake (and because + // it's documented here... if you change it, make sure to update the documentation! don't + // rely on the field initializer) + mvarCombination = ConditionCombination.And; + } + /// + /// Creates a new with the specified + /// and s. + /// + /// The used to join s when testing this . + /// The s and s that are part of this . + public ConditionGroup(ConditionCombination combination, params IConditionalStatement[] statements) + { + mvarCombination = combination; + for (int i = 0; i < statements.Length; i++) + { + mvarConditions.Add(statements[i]); + } + } + + private ConditionalStatementCollection mvarConditions = new ConditionalStatementCollection(); + /// + /// Gets all s in this . + /// + public ConditionalStatementCollection Conditions + { + get { return mvarConditions; } + } + + private ConditionCombination mvarCombination = ConditionCombination.And; + /// + /// The type of combination used to join the s in this + /// . + /// + public ConditionCombination Combination + { + get { return mvarCombination; } + set { mvarCombination = value; } + } + + /// + /// Evaluates the conditional statement based on the given criteria. + /// + /// The set of values against which to evaluate the conditional statement. + /// True if the conditions are satisfied; false otherwise. + public bool Test(params System.Collections.Generic.KeyValuePair[] propertyValues) + { + bool retval = false; + if (mvarCombination == ConditionCombination.And) + { + retval = true; + } + for (int i = 0; i < mvarConditions.Count; i++) + { + switch (mvarCombination) + { + case ConditionCombination.And: + { + retval &= mvarConditions[i].Test(propertyValues); + break; + } + case ConditionCombination.Or: + { + retval |= mvarConditions[i].Test(propertyValues); + break; + } + case ConditionCombination.Xor: + { + retval ^= mvarConditions[i].Test(propertyValues); + break; + } + } + } + return retval; + } + /// + /// Evaluates the conditional statement based on the given criteria. + /// + /// The set of values against which to evaluate the conditional statement. + /// True if the conditions are satisfied; false otherwise. + public bool Test(System.Collections.Generic.Dictionary propertyValues) + { + bool retval = false; + if (mvarCombination == ConditionCombination.And) + { + retval = true; + } + for (int i = 0; i < mvarConditions.Count; i++) + { + switch (mvarCombination) + { + case ConditionCombination.And: + { + retval &= mvarConditions[i].Test(propertyValues); + break; + } + case ConditionCombination.Or: + { + retval |= mvarConditions[i].Test(propertyValues); + break; + } + case ConditionCombination.Xor: + { + retval ^= mvarConditions[i].Test(propertyValues); + break; + } + } + } + return retval; + } + + /// + /// Evaluates the conditional statement based on the given criterion. + /// + /// The value against which to evaluate the conditional statement. + /// True if the conditions are satisfied; false otherwise. + public bool Test(object value) + { + bool retval = true; + + for (int i = 0; i < mvarConditions.Count; i++) + { + switch (mvarCombination) + { + case ConditionCombination.And: + { + retval &= mvarConditions[i].Test(value); + break; + } + case ConditionCombination.Or: + { + retval |= mvarConditions[i].Test(value); + break; + } + case ConditionCombination.Xor: + { + retval ^= mvarConditions[i].Test(value); + break; + } + } + } + return retval; + } + } +} diff --git a/MBS.Framework/Logic/Conditional/ConditionalStatementCollection.cs b/MBS.Framework/Logic/Conditional/ConditionalStatementCollection.cs new file mode 100644 index 0000000..b1cd585 --- /dev/null +++ b/MBS.Framework/Logic/Conditional/ConditionalStatementCollection.cs @@ -0,0 +1,32 @@ +// +// ConditionalStatementCollection.cs - a collection of IConditionalStatements +// +// Author: +// Michael Becker +// +// Copyright (c) 2011-2020 Mike Becker's Software +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +namespace MBS.Framework.Logic.Conditional +{ + /// + /// A collection of s. + /// + public class ConditionalStatementCollection + : System.Collections.ObjectModel.Collection + { + + } +} diff --git a/MBS.Framework/Logic/Conditional/IConditionalStatement.cs b/MBS.Framework/Logic/Conditional/IConditionalStatement.cs new file mode 100644 index 0000000..e375913 --- /dev/null +++ b/MBS.Framework/Logic/Conditional/IConditionalStatement.cs @@ -0,0 +1,49 @@ +// +// IConditionalStatement.cs - interface defining the minimum functionality required to implement a conditional statement +// +// Author: +// Michael Becker +// +// Copyright (c) 2020 Mike Becker's Software +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +namespace MBS.Framework.Logic.Conditional +{ + /// + /// Interface defining the minimum functionality required to implement a conditional statement (either a itself or a + /// of multiple s. + /// + public interface IConditionalStatement + { + /// + /// Evaluates the conditional statement based on the given criteria. + /// + /// The set of values against which to evaluate the conditional statement. + /// True if the conditions are satisfied; false otherwise. + bool Test(params System.Collections.Generic.KeyValuePair[] propertyValues); + /// + /// Evaluates the conditional statement based on the given criteria. + /// + /// The set of values against which to evaluate the conditional statement. + /// True if the conditions are satisfied; false otherwise. + bool Test(System.Collections.Generic.Dictionary propertyValues); + /// + /// Evaluates the conditional statement based on the given criterion. + /// + /// The value against which to evaluate the conditional statement. + /// True if the conditions are satisfied; false otherwise. + bool Test(object value); + } +} diff --git a/MBS.Framework/MBS.Framework.csproj b/MBS.Framework/MBS.Framework.csproj index 99712db..589ae3e 100644 --- a/MBS.Framework/MBS.Framework.csproj +++ b/MBS.Framework/MBS.Framework.csproj @@ -61,10 +61,17 @@ + + + + + + +