''  ---
''  License
''  ---
''
''  This software was developed at the National Institute of Standards and
''  Technology (NIST) by employees of the Federal Government in the course
''  of their official duties. Pursuant to title 17 Section 105 of the
''  United States Code, this software is not subject to copyright protection
''  and is in the public domain. NIST assumes no responsibility  whatsoever for
''  its use by other parties, and makes no guarantees, expressed or implied,
''  about its quality, reliability, or any other characteristic.
''
''  ---
''  Disclaimer
''  ---
''  This software was developed to facilitate multimodal biometric data collection
''  for the Department of Homeland Security in accordance with Section 303 of the 
''  Border Security Act, codified as 8 U.S.C. 1732.  Specific hardware and software 
''  products identified in this software were used in order to perform the data 
''  collection. In no case does such identification imply recommendation or endorsement 
''  by the National Institute of Standards and Technology, nor does it imply that the 
''  products and equipment identified are necessarily the best available for the purpose.
''

Option Strict On

Imports System.Text
Imports System.Collections.Specialized
Imports System.Runtime.Serialization
Imports System.Xml.Serialization

Imports System.Windows.Forms

Imports Mbark.UI.GlobalUISettings

Namespace Mbark.Sensors

    Public Enum ConditionTypes
        BooleanCondition
    End Enum

    Public Class ConditionValueChangedEventArgs
        Private mOriginatingCondition As Condition
        Private mOldValue As Object
        Private mNewValue As Object

        Public Property NewValue() As Object
            Get
                Return mNewValue
            End Get
            Set(ByVal value As Object)
                mNewValue = value
            End Set
        End Property

        Public Property OldValue() As Object
            Get
                Return mOldValue
            End Get
            Set(ByVal value As Object)
                mOldValue = value
            End Set
        End Property

        Public Property OriginatingCondition() As Condition
            Get
                Return mOriginatingCondition
            End Get
            Set(ByVal value As Condition)
                mOriginatingCondition = value
            End Set
        End Property

        Public Sub New(ByVal condition As Condition, ByVal oldvalue As Object, ByVal newvalue As Object)
            mOriginatingCondition = condition
            mOldValue = oldvalue
            mNewValue = newvalue
        End Sub

    End Class

    Public Class ConditionsConflict
        Private mSuperset As New ConditionCollection
        Private mSubset As New ConditionCollection
        Private mNames As New StringCollection
        Private mSupersetLabels As New StringCollection
        Private mSubsetLabels As New StringCollection

        Private mSupersetLabel As String
        Public Property SupersetLabel() As String
            Get
                Return mSupersetLabel
            End Get
            Set(ByVal value As String)
                mSupersetLabel = value
            End Set
        End Property

        Private mSubsetLabel As String
        Public Property SubsetLabel() As String
            Get
                Return mSubsetLabel
            End Get
            Set(ByVal value As String)
                mSubsetLabel = value
            End Set
        End Property

        Public Sub AddWithDeepCopy( _
            ByVal supersetCondition As Condition, _
            ByVal superset As ConditionCollection, _
            ByVal subsetCondition As Condition, _
            ByVal subset As ConditionCollection)
            Dim name As String

            If supersetCondition Is Nothing Then
                name = subsetCondition.Name
            Else
                name = supersetCondition.Name
            End If

            mNames.Add(name)
            mSupersetLabels.Add(SupersetLabel)
            mSubsetLabels.Add(SubsetLabel)

            If Not supersetCondition Is Nothing Then mSuperset(name) = supersetCondition.DeepCopy(mSuperset)
            If Not subsetCondition Is Nothing Then mSubset(name) = subsetCondition.DeepCopy(mSubset)

            ' Make sure to nab the prerequisites
            mSuperset.DeepCopyPrerequisites(supersetCondition, superset)
            mSubset.DeepCopyPrerequisites(subsetCondition, subset)

        End Sub


        Public ReadOnly Property Subset() As ConditionCollection
            Get
                Return mSubset
            End Get
        End Property
        Public ReadOnly Property Superset() As ConditionCollection
            Get
                Return mSuperset
            End Get
        End Property

        Public ReadOnly Property IsEmpty() As Boolean
            Get
                Return mNames.Count = 0
            End Get
        End Property

        Public Overloads Function ToString(ByVal i As Integer) As String
            Dim writer As New System.IO.StringWriter

            If Not mSuperset(mNames(i)) Is Nothing Then
                With writer
                    .Write(mSupersetLabels(i))
                    .Write(StringConstants.Colon)
                    .Write(StringConstants.Space)
                    .WriteLine(mSuperset(mNames(i)).StandaloneToString)
                End With
            End If

            If Not mSubset(mNames(i)) Is Nothing Then
                With writer
                    .Write(mSubsetLabels(i))
                    .Write(StringConstants.Colon)
                    .Write(StringConstants.Space)
                    .WriteLine(mSubset(mNames(i)).StandaloneToString)
                End With
            End If

            Return writer.ToString
        End Function

        Public Overloads Function ToString() As String
            Dim writer As New System.IO.StringWriter
            For i As Integer = 0 To mNames.Count - 1
                writer.Write(ToString(i))
                If i <> mNames.Count - 1 Then writer.Write(StringConstants.Space)
            Next
            Return writer.ToString()
        End Function

        Public Function ToRtf(ByVal standalone As Boolean) As String
            Dim writer As New System.IO.StringWriter
            If standalone Then writer.Write(Rtf.Header)

            ' Put all of the conditions that share the same label together. We assume that
            ' subset and superset labels will be different. If not, they'll clobber each other here
            Dim labelToConditions As New Hashtable
            For i As Integer = 0 To mNames.Count - 1

                Dim conditions As StringCollection

                If labelToConditions(mSupersetLabels(i)) Is Nothing Then
                    labelToConditions(mSupersetLabels(i)) = New StringCollection
                End If

                If labelToConditions(mSubsetLabels(i)) Is Nothing Then
                    labelToConditions(mSubsetLabels(i)) = New StringCollection
                End If

                If Not mSuperset(mNames(i)) Is Nothing Then
                    conditions = DirectCast(labelToConditions(mSupersetLabels(i)), StringCollection)
                    Dim description As String = mSuperset(mNames(i)).StandaloneToString
                    If Not conditions.Contains(description) AndAlso mSuperset(mNames(i)).IsValid Then conditions.Add(description)
                End If

                If Not mSubset(mNames(i)) Is Nothing Then
                    conditions = DirectCast(labelToConditions(mSubsetLabels(i)), StringCollection)
                    Dim description As String = mSubset(mNames(i)).StandaloneToString
                    ' It only matter if the *superset* condition is valid here
                    If Not conditions.Contains(description) AndAlso mSuperset(mNames(i)).IsValid Then conditions.Add(description)

                End If
            Next

            Dim en As IEnumerator = labelToConditions.Keys.GetEnumerator
            While en.MoveNext
                Dim label As String = DirectCast(en.Current, String)
                writer.Write(Rtf.BoldOn)
                writer.Write(label)
                writer.Write(Rtf.BoldOff)
                writer.Write(StringConstants.Colon)
                writer.Write(StringConstants.Space)
                Dim conds As StringCollection = DirectCast(labelToConditions(label), StringCollection)
                If conds.Count = 0 Then writer.Write(InfrastructureMessages.Messages.None)
                For i As Integer = 0 To conds.Count - 1
                    writer.Write(conds(i))
                    If i <> conds.Count - 1 Then
                        writer.Write(StringConstants.Comma)
                        writer.Write(StringConstants.Space)
                    End If
                Next
                writer.Write(Rtf.NewLine)
            End While

            If standalone Then writer.Write(Rtf.Footer)
            Return writer.ToString
        End Function

    End Class

    Public MustInherit Class Condition

        Private mPrerequisite As Predicate
        Private mOriginatingFactory As ConditionFactory
        Private mDefinition As New ConditionDefinition

        < _
        XmlType("ConditionDefinition"), _
        XmlInclude(GetType(Condition.ConditionDefinition)), _
        XmlInclude(GetType(BooleanCondition.BooleanConditionDefinition)), _
        Serializable()> _
        Public Class ConditionDefinition
            Implements ICloneable

            Public PrerequisiteDefinition As Predicate.Definition
            Public Value As Object
            Public OriginatingFactoryIndex As Integer = -1

            Public Overridable Function Clone() As Object Implements System.ICloneable.Clone
                Dim newDef As New ConditionDefinition
                CloneImplementation(newDef)
                Return newDef
            End Function

            Public Overridable Function DeepCopy() As ConditionDefinition
                Return DirectCast(Clone(), ConditionDefinition)
            End Function

            Protected Sub CloneImplementation(ByVal definition As ConditionDefinition)
                If Not PrerequisiteDefinition Is Nothing Then
                    definition.PrerequisiteDefinition = PrerequisiteDefinition.DeepCopy
                End If
                definition.Value = Value
                definition.OriginatingFactoryIndex = OriginatingFactoryIndex
            End Sub

            Public Overridable Function CreateCondition( _
                ByVal conditions As ConditionCollection, _
                ByVal factory As ConditionFactory) As Condition

            End Function


        End Class

        Public MustOverride Function StandaloneToString() As String
        Public MustOverride Function CompoundToString() As String

        Friend MustOverride Function Definition(ByVal factories As ArrayList) _
        As ConditionDefinition

        Protected Sub New()
        End Sub

        Friend Function DeepCopy(ByVal conditions As ConditionCollection) As Condition
            Dim c As Condition = mOriginatingFactory.Create(conditions)
            c.mDefinition.Value = Me.DeepCopyValue()
            Return c
        End Function

        Friend MustOverride Function DeepCopyValue() As Object

        Public ReadOnly Property IsStatic() As Boolean
            Get
                Return mOriginatingFactory.ConditionIsStatic
            End Get
        End Property

        Public ReadOnly Property Description() As String
            Get
                Return mOriginatingFactory.ConditionDescription(Application.CurrentCulture.Name)
            End Get
        End Property

        Public ReadOnly Property Description(ByVal region As String) As String
            Get
                Return mOriginatingFactory.ConditionDescription(region)
            End Get
        End Property

        Public Property Prerequisite() As Predicate
            Get
                If mPrerequisite Is Nothing Then Return BuiltIns.Predicates.TrueLiteral
                Return mPrerequisite
            End Get
            Set(ByVal value As Predicate)
                mPrerequisite = value
            End Set
        End Property

        Public ReadOnly Property Name() As String
            Get
                Return mOriginatingFactory.ConditionName
            End Get
        End Property

        Public Overridable Property Value() As Object
            Get
                Return mDefinition.Value
            End Get
            Set(ByVal value As Object)

                ' If the condition is valid, and has indeed changed, then change it. Notice the subtle use
                ' of Me.Value instead of mValue, so that we get dynamic dispatch
                '
                If IsValid AndAlso Not Me.Value.Equals(value) Then
                    Dim eventArgs As New ConditionValueChangedEventArgs(Me, mDefinition.Value, value)
                    mDefinition.Value = value
                    RaiseEvent ConditionValueChanged(Me, eventArgs)
                End If
            End Set
        End Property

        Public Event ConditionValueChanged(ByVal sender As Object, ByVal e As ConditionValueChangedEventArgs)

        Public ReadOnly Property IsValid() As Boolean
            Get
                If mPrerequisite Is Nothing Then Return True
                Return mPrerequisite.Evaluate
            End Get
        End Property

        Public Overrides Function ToString() As String
            Dim builder As New StringBuilder
            If Not IsValid Then builder.Append("*")
            builder.Append(Name).Append("=").Append(Value.ToString)
            Return builder.ToString()
        End Function

        Friend Sub WireOriginatingFactory(ByVal factory As ConditionFactory)
            mOriginatingFactory = factory
        End Sub

        Friend ReadOnly Property OriginatingFactory() As ConditionFactory
            Get
                Return mOriginatingFactory
            End Get
        End Property

    End Class

    Public Enum ConditionsMatchStyle
        NonStaticsOnly
        StaticsOnly
        All
        AllWithoutEquivalenceClasses
    End Enum

    Public Class ConditionCollection

        Private mIsReadOnly As Boolean
        Private mConditionsTable As New Hashtable ' name -> condition
        Private mParentTask As SensorTask
        Private mEquivalenceClasses As New ArrayList ' of predicate factories


        <XmlType("ConditionCollectionDefinition"), Serializable()> _
        Public Class Definition
            Implements ICloneable

            Public FactoryDefinitions() As ConditionFactory.ConditionFactoryDefinition
            Public Conditions() As Condition.ConditionDefinition
            Public EquivalenceClasses() As PredicateFactory.PredicateFactoryDefinition

            Public Function Clone() As Object Implements ICloneable.Clone
                Dim newDef As New Definition

                ReDim newDef.FactoryDefinitions(Me.FactoryDefinitions.Length - 1)
                For i As Integer = 0 To Me.FactoryDefinitions.Length - 1
                    newDef.FactoryDefinitions(i) = Me.FactoryDefinitions(i).DeepCopy
                Next

                ReDim newDef.EquivalenceClasses(Me.EquivalenceClasses.Length - 1)
                For i As Integer = 0 To EquivalenceClasses.Length - 1
                    newDef.EquivalenceClasses(i) = Me.EquivalenceClasses(i).DeepCopy
                Next

                ReDim newDef.Conditions(Me.Conditions.Length - 1)
                For i As Integer = 0 To Me.Conditions.Length - 1
                    newDef.Conditions(i) = Me.Conditions(i).DeepCopy
                Next


                Return newDef
            End Function

            Public Function DeepCopy() As Definition
                Return DirectCast(Clone(), Definition)
            End Function

            Public Function CreateConditionCollection() As ConditionCollection

                Dim newConditions As New ConditionCollection

                ' Reconstitute the list of factories
                Dim factories As New ArrayList
                For Each factory As ConditionFactory.ConditionFactoryDefinition In FactoryDefinitions
                    factories.Add(factory.CreateConditionFactory)
                Next


                ' Reconstitute the equivalence classes
                For Each definition As PredicateFactory.PredicateFactoryDefinition In EquivalenceClasses
                    newConditions.AddEquivalenceClass(definition.CreatePredicateFactory())
                Next

                ' Reconstitute the conditions, linking them back to their originating factory
                For Each definition As Condition.ConditionDefinition In Conditions
                    Dim factory As ConditionFactory = DirectCast(factories(definition.OriginatingFactoryIndex), ConditionFactory)
                    newConditions.Add(definition.CreateCondition(newConditions, factory))
                Next


                Return newConditions

            End Function

        End Class

        Friend Function CreateDefinition() As ConditionCollection.Definition

            Dim def As New Definition
            Dim uniqueFactories As New ArrayList
            Dim en As IEnumerator = mConditionsTable.Values.GetEnumerator

            ' Build the list of unique factories
            While en.MoveNext
                Dim condition As Condition = DirectCast(en.Current, Condition)
                If uniqueFactories.IndexOf(condition) = -1 Then uniqueFactories.Add(condition.OriginatingFactory)
            End While

            ' Create the definitions for the factories
            ReDim def.FactoryDefinitions(uniqueFactories.Count - 1)
            For i As Integer = 0 To uniqueFactories.Count - 1
                def.FactoryDefinitions(i) = DirectCast(uniqueFactories(i), ConditionFactory).Definition
            Next

            ' Create definitons for the conditions themselves
            ReDim def.Conditions(mConditionsTable.Count - 1)
            en = mConditionsTable.Values.GetEnumerator
            Dim index As Integer = 0
            While en.MoveNext
                Dim condition As Condition = DirectCast(en.Current, Condition)
                def.Conditions(index) = condition.Definition(uniqueFactories)
                index += 1
            End While

            ' Create the equivalence class defintions
            ReDim def.EquivalenceClasses(mEquivalenceClasses.Count - 1)
            For i As Integer = 0 To mEquivalenceClasses.Count - 1
                def.EquivalenceClasses(i) = DirectCast(mEquivalenceClasses(i), PredicateFactory).Definition
            Next



            Return def

        End Function

        Public ReadOnly Property HasValidConditions() As Boolean
            Get
                Dim en As IEnumerator = mConditionsTable.Values.GetEnumerator
                While en.MoveNext
                    Dim c As Condition = DirectCast(en.Current, Condition)
                    If c.IsValid Then Return True
                End While
                Return False
            End Get
        End Property

        Public Sub DeepCopyPrerequisites(ByVal prereqSource As Condition, ByVal conditions As ConditionCollection)
            If Not prereqSource.Prerequisite Is Nothing Then
                For i As Integer = 0 To prereqSource.Prerequisite.ParticipatingConditionNames.Count - 1
                    Dim prereqName As String = prereqSource.Prerequisite.ParticipatingConditionNames(i)
                    If Not Me.ContainsCondition(prereqName) Then
                        Me(prereqName) = conditions(prereqName).DeepCopy(conditions)
                    End If
                Next
            End If
        End Sub

        Public Property IsReadOnly() As Boolean
            Get
                Return mIsReadOnly
            End Get
            Set(ByVal value As Boolean)
                mIsReadOnly = value
            End Set
        End Property

        Public ReadOnly Property Count() As Integer
            Get
                Return mConditionsTable.Count
            End Get
        End Property

        Public Function FriendlyToString(ByVal supressInvalidConditionsAccordingToTask As SensorTask) As String
            Dim writer As New System.IO.StringWriter

            ' We make a deep copy of the current conditions and wire it up to the task to be tested against since
            ' we don't want to assign a task to the current conditions
            '
            Dim conditions As ConditionCollection = DeepCopy()
            conditions.WireParentTask(supressInvalidConditionsAccordingToTask)

            Dim en As IEnumerator = conditions.ValuesEnumerator
            While en.MoveNext
                Dim c As Condition = DirectCast(en.Current, Condition)
                If Not supressInvalidConditionsAccordingToTask Is Nothing OrElse c.IsValid Then
                    writer.Write(c.CompoundToString)
                    If c.CompoundToString <> String.Empty Then writer.Write(" ")
                End If
            End While
            If writer.ToString = String.Empty Then
                Return InfrastructureMessages.Messages.None
            Else
                Return writer.ToString
            End If
        End Function

        Public Function FriendlyToString() As String
            Return FriendlyToString(Nothing)
        End Function

        ReadOnly Property ContainsCondition(ByVal name As String) As Boolean
            Get
                Return mConditionsTable.ContainsKey(name)
            End Get
        End Property

        Public Sub Add(ByVal condition As Condition)
            Item(condition.Name) = condition
        End Sub

        Default Property Item(ByVal name As String) As Condition
            Get
                Return DirectCast(mConditionsTable(name), Condition)
            End Get
            Set(ByVal Value As Condition)
                If mIsReadOnly Then Debugger.Break()

                ' If the condition already exists, then remove the handler
                If mConditionsTable.Contains(name) Then
                    RemoveHandler Value.ConditionValueChanged, AddressOf HandleConditionValueChanged
                End If

                AddHandler Value.ConditionValueChanged, AddressOf HandleConditionValueChanged
                mConditionsTable(name) = Value
            End Set
        End Property

        Friend ReadOnly Property ValuesEnumerator() As IEnumerator
            Get
                Return mConditionsTable.Values.GetEnumerator
            End Get
        End Property

        Public ReadOnly Property ConditionsEnumerator() As IEnumerator
            Get
                Return mConditionsTable.Values.GetEnumerator
            End Get
        End Property

        Friend ReadOnly Property ParentTask() As SensorTask
            Get
                Return mParentTask
            End Get
        End Property

        Friend Sub WireParentTask(ByVal parentTask As SensorTask)
            mParentTask = parentTask
        End Sub

        Public Function EqualsSubset(ByVal subset As ConditionCollection) As Boolean
            Return EqualsSubset(subset, ConditionsMatchStyle.All)
        End Function

        Public Sub AddEquivalenceClass(ByVal predicateFactory As PredicateFactory)
            mEquivalenceClasses.Add(predicateFactory)
        End Sub

        Protected Friend Function EqualsSubset( _
            ByVal subset As ConditionCollection, _
            ByVal style As ConditionsMatchStyle, _
            ByVal conflicts As ConditionsConflict, _
            ByVal shortCircuiting As Boolean) As Boolean

            If conflicts Is Nothing Then shortCircuiting = True

            ' Empty conditions are always satisfied
            If subset.mConditionsTable.Count = 0 Then Return True

            Dim namesOfFailableConditions As New ArrayList
            Dim namesOfNonParticipantConditions As New ArrayList

            ' Assume all conditions are equivalence class participants at first .
            Dim en As IEnumerator = Me.mConditionsTable.Keys.GetEnumerator
            While en.MoveNext
                namesOfNonParticipantConditions.Add(DirectCast(en.Current, String))
            End While

            For i As Integer = 0 To subset.mEquivalenceClasses.Count - 1

                Dim pf As PredicateFactory = DirectCast(subset.mEquivalenceClasses(i), PredicateFactory)
                Dim supersetPredicate As Predicate = pf.CreatePredicate(Me)
                Dim subsetPredicate As Predicate = pf.CreatePredicate(subset)


                ' In this loop, we set up the list of conditions to check. The participating and non-participating
                ' conditions need to be treated slightly differently.
                '
                For j As Integer = 0 To subsetPredicate.ParticipatingConditionNames.Count - 1
                    Dim name As String = subsetPredicate.ParticipatingConditionNames(j)

                    ' Remove those participating conditions from the list of non-participating conditions 
                    ' (unless we're ignore equivalence classes)
                    '
                    If namesOfNonParticipantConditions.Contains(name) AndAlso style <> ConditionsMatchStyle.AllWithoutEquivalenceClasses Then
                        namesOfNonParticipantConditions.Remove(name)
                    End If

                    ' Put all of the participating conditions into the 'failed' list. Conditions are
                    ' assumed to be failed, and are removed from this list as they evaluate to be
                    ' passed. 
                    '
                    ' Notice we don't eliminate redudant names, because a condition might
                    ' participate in multiple equivalence clases, and must pass all of them in order to
                    ' not be checked later.
                    namesOfFailableConditions.Add(name)
                Next

                Dim supersetPasses As Boolean = supersetPredicate.Evaluate
                Dim subsetPasses As Boolean = subsetPredicate.Evaluate

                ' If the condition passes, remove it from the failed list
                If supersetPasses And subsetPasses Then
                    For j As Integer = 0 To subsetPredicate.ParticipatingConditionNames.Count - 1
                        Dim name As String = subsetPredicate.ParticipatingConditionNames(j)
                        namesOfFailableConditions.Remove(name)
                    Next
                End If

            Next

            ' Take all those valid conditions that really are non-participants, and add them to the rest of the 
            ' failed conditions list
            '
            For i As Integer = 0 To namesOfNonParticipantConditions.Count - 1
                Dim subsetCondition As Condition = subset(DirectCast(namesOfNonParticipantConditions(i), String))

                If subsetcondition.IsValid Then
                    namesOfFailableConditions.Add(namesOfNonParticipantConditions(i))
                End If
            Next


            ' Perform the comparisons for non participants, and for those participants failing equivalence class
            ' membership
            '
            Dim toCompare As New ArrayList
            en = subset.ValuesEnumerator
            While en.MoveNext


                Dim subsetCondition As Condition = DirectCast(en.Current, Condition)
                Dim name As String = subsetcondition.name

                If subsetCondition.IsValid Then
                    Dim supersetCondition As Condition = DirectCast(Me(name), Condition)

                    ' Make sure the subset condition exists in the superset
                    '
                    If supersetCondition Is Nothing Then
                        If Not conflicts Is Nothing Then conflicts.AddWithDeepCopy(Nothing, Me, subsetcondition, subset)
                        If shortCircuiting Then Return False
                    End If

                    ' Notice that we only do the comparison if the condition still has an entry in the
                    ' list of potentially failed conditions
                    '
                    Dim doCompare As Boolean = _
                         namesOfFailableConditions.Contains(subsetCondition.Name) AndAlso ( _
                         style = ConditionsMatchStyle.AllWithoutEquivalenceClasses OrElse _
                         style = ConditionsMatchStyle.All OrElse _
                        (style = ConditionsMatchStyle.StaticsOnly AndAlso subsetCondition.IsStatic) OrElse _
                        (style = ConditionsMatchStyle.NonStaticsOnly AndAlso Not subsetCondition.IsStatic))

                    If doCompare Then

                        If Me(subsetCondition.Name) Is Nothing Then Debugger.Break()

                        Dim supersetValue As Object = Me(subsetCondition.Name).Value
                        Dim subsetValue As Object = subsetCondition.Value


                        If subsetCondition.IsValid AndAlso Not supersetValue.Equals(subsetValue) Then

                            If Not conflicts Is Nothing Then
                                conflicts.AddWithDeepCopy(supersetCondition, Me, subsetcondition, subset)
                            End If
                            If shortCircuiting Then Return False
                        End If

                    End If ' doCompare
                End If ' subsetCondition.IsValid

            End While

            If shortCircuiting Then Return True

            Return Not conflicts.IsEmpty

        End Function

        ' Determines if all of the conditions in subset take on the same value as in the superset
        Protected Friend Function EqualsSubset(ByVal subset As ConditionCollection, ByVal style As ConditionsMatchStyle) As Boolean
            Return EqualsSubset(subset, style, Nothing, True)
        End Function

        Public Overrides Function ToString() As String
            Dim writer As New IO.StringWriter
            Dim en As IEnumerator = mConditionsTable.Values.GetEnumerator
            While en.MoveNext
                Dim cond As Condition = DirectCast(en.Current, Condition)
                If cond.IsValid Then
                    writer.Write(cond.Name)
                    writer.Write(StringConstants.EqualsSign)
                    writer.Write(cond.Value.ToString)
                    writer.Write(StringConstants.Space)
                End If
            End While
            If writer.ToString = String.Empty Then
                Return InfrastructureMessages.Messages.None
            Else
                Return writer.ToString
            End If
        End Function

        ' Only deep copy those conditions in the subset
        Public Function SubsetDeepCopy(ByVal subset As ConditionCollection) As ConditionCollection
            Dim cs As New ConditionCollection
            Dim en As IEnumerator = mConditionsTable.Values.GetEnumerator
            While en.MoveNext
                Dim c As Condition = DirectCast(en.Current, Condition)
                If Not subset(c.Name) Is Nothing Then cs(c.Name) = c.DeepCopy(cs)
            End While
            For i As Integer = 0 To Me.mEquivalenceClasses.Count - 1
                cs.AddEquivalenceClass(DirectCast(mEquivalenceClasses(i), PredicateFactory))
            Next
            Return cs
        End Function

        Public Function DeepCopy() As ConditionCollection
            Dim cs As New ConditionCollection
            Dim en As IEnumerator = mConditionsTable.Values.GetEnumerator
            While en.MoveNext
                Dim c As Condition = DirectCast(en.Current, Condition)
                cs(c.Name) = c.DeepCopy(cs)
            End While
            For i As Integer = 0 To Me.mEquivalenceClasses.Count - 1
                cs.AddEquivalenceClass(DirectCast(mEquivalenceClasses(i), PredicateFactory))
            Next
            Return cs
        End Function

        Public Sub AssignSubset(ByVal source As ConditionCollection)
            Dim en As IEnumerator = mConditionsTable.Values.GetEnumerator
            While en.MoveNext
                Dim cond As Condition = DirectCast(en.Current, Condition)
                If Not source(cond.Name) Is Nothing AndAlso Not cond.Value.Equals(source(cond.Name).Value) Then
                    cond.Value = source(cond.Name).DeepCopyValue
                End If
            End While

        End Sub

        Public Event ConditionValueChanged(ByVal sender As Object, ByVal e As ConditionValueChangedEventArgs)

        Private Sub HandleConditionValueChanged(ByVal sender As Object, ByVal e As ConditionValueChangedEventArgs)
            RaiseEvent ConditionValueChanged(sender, e)
        End Sub


    End Class

    Public Class BooleanCondition
        Inherits Condition

        Public Overloads Function Equals(ByVal arg As Boolean) As Boolean
            Return DirectCast(Value, Boolean) = arg
        End Function
        Public Overrides Property Value() As Object
            Get
                If MyBase.Value Is Nothing Then Return False Else Return MyBase.Value
            End Get
            Set(ByVal Value As Object)
                If Prerequisite Is Nothing OrElse Prerequisite.Evaluate Then
                    MyBase.Value = Value
                Else
                    MyBase.Value = Nothing
                End If
            End Set
        End Property

        Private mDefinition As New BooleanConditionDefinition

        Private mStandaloneTrueString As LocalizableString
        Private mStandaloneFalseString As LocalizableString
        Private mStandaloneInvalidString As LocalizableString
        Private mCompoundTrueString As LocalizableString
        Private mCompoundFalseString As LocalizableString
        Private mCompoundInvalidString As LocalizableString

        <Serializable()> Public Class BooleanConditionDefinition
            Inherits Condition.ConditionDefinition

            Public StandaloneTrueStringDefinition As New LocalizableString.Definition
            Public StandaloneFalseStringDefinition As New LocalizableString.Definition
            Public StandaloneInvalidStringDefinition As New LocalizableString.Definition
            Public CompoundTrueStringDefinition As New LocalizableString.Definition
            Public CompoundFalseStringDefinition As New LocalizableString.Definition
            Public CompoundInvalidStringDefinition As New LocalizableString.Definition
            Public BooleanValue As Boolean

            Public Overrides Function Clone() As Object
                Dim newDef As New BooleanConditionDefinition
                CloneImplementation(newDef)
                Return newDef
            End Function

            Protected Overloads Sub CloneImplementation(ByVal definition As BooleanConditionDefinition)
                MyBase.CloneImplementation(definition)
                definition.StandaloneTrueStringDefinition = StandaloneTrueStringDefinition.DeepCopy
                definition.StandaloneFalseStringDefinition = StandaloneFalseStringDefinition.DeepCopy
                definition.StandaloneInvalidStringDefinition = StandaloneInvalidStringDefinition.DeepCopy
                definition.CompoundTrueStringDefinition = CompoundTrueStringDefinition.DeepCopy
                definition.CompoundFalseStringDefinition = CompoundFalseStringDefinition.DeepCopy
                definition.CompoundInvalidStringDefinition = CompoundInvalidStringDefinition.DeepCopy
                definition.BooleanValue = BooleanValue
            End Sub

            Public Overrides Function CreateCondition( _
                ByVal conditions As ConditionCollection, _
                ByVal factory As ConditionFactory) As Condition



                Dim condition As New BooleanCondition( _
                    factory.ConditionName, CType(factory.ConditionInitialValue, Boolean), _
                    StandaloneTrueStringDefinition.CreateLocalizableString, _
                    StandaloneFalseStringDefinition.CreateLocalizableString, _
                    StandaloneInvalidStringDefinition.CreateLocalizableString, _
                    CompoundTrueStringDefinition.CreateLocalizableString, _
                    CompoundFalseStringDefinition.CreateLocalizableString, _
                    CompoundInvalidStringDefinition.CreateLocalizableString)

                If Not PrerequisiteDefinition Is Nothing Then
                    condition.Prerequisite = PrerequisiteDefinition.DeepCopy.CreatePredicate(conditions)
                End If

                condition.WireOriginatingFactory(factory)
                Return condition
            End Function


        End Class


        ' Only factories should be able to create contidions
        Friend Sub New( _
            ByVal name As String, _
            ByVal initialValue As Boolean, _
            ByVal standaloneTrueString As LocalizableString, _
            ByVal standaloneFalseString As LocalizableString, _
            ByVal standaloneInvalidString As LocalizableString, _
            ByVal compoundTrueString As LocalizableString, _
            ByVal compoundFalseString As LocalizableString, _
            ByVal compoundInvalidString As LocalizableString)

            MyBase.New()
            MyBase.Value = initialValue

            mStandaloneTrueString = standaloneTrueString
            mStandaloneFalseString = standaloneFalseString
            mStandaloneInvalidString = standaloneInvalidString

            mCompoundTrueString = compoundTrueString
            mCompoundFalseString = compoundFalseString
            mCompoundInvalidString = compoundInvalidString


        End Sub


        Public Overrides Function StandaloneToString() As String
            If Not IsValid Then Return mStandaloneInvalidString(Application.CurrentCulture.Name)
            If DirectCast(Value, Boolean) Then Return mStandaloneTrueString(Application.CurrentCulture.Name)
            Return mStandaloneFalseString(Application.CurrentCulture.Name)
        End Function

        Public Overrides Function CompoundToString() As String
            If Not IsValid Then Return mCompoundInvalidString(Application.CurrentCulture.Name)
            If DirectCast(Value, Boolean) Then Return mCompoundTrueString(Application.CurrentCulture.Name)
            Return mCompoundFalseString(Application.CurrentCulture.Name)
        End Function


        Friend Overrides Function DeepCopyValue() As Object
            Dim val As Boolean = DirectCast(Value, Boolean)
            If val Then Return CObj(True) Else Return CObj(False)
        End Function


        Friend Overrides Function Definition(ByVal factories As ArrayList) _
        As Condition.ConditionDefinition
            mDefinition.StandaloneTrueStringDefinition = mStandaloneTrueString.CreateDefinition
            mDefinition.StandaloneFalseStringDefinition = mStandaloneFalseString.CreateDefinition
            mDefinition.StandaloneInvalidStringDefinition = mStandaloneInvalidString.CreateDefinition

            mDefinition.CompoundTrueStringDefinition = mCompoundTrueString.CreateDefinition
            mDefinition.CompoundFalseStringDefinition = mCompoundFalseString.CreateDefinition
            mDefinition.CompoundInvalidStringDefinition = mCompoundInvalidString.CreateDefinition

            mDefinition.OriginatingFactoryIndex = factories.IndexOf(OriginatingFactory)
            mDefinition.BooleanValue = CType(Value, Boolean)
            mDefinition.PrerequisiteDefinition = MyBase.Prerequisite.CreateDefinition
            Return mDefinition.DeepCopy
        End Function
    End Class

    Public Class ConditionFactory

        Private mPrerequisiteFactory As PredicateFactory
        Private mDefinition As New ConditionFactoryDefinition
        Private mConditionDescription As New LocalizableString

        'Private Shared mAllFactories As New ArrayList

        Public Sub New()
            MyBase.New()
            'mAllFactories.Add(Me)
        End Sub

        Protected Overrides Sub Finalize()
            'mAllFactories.Remove(Me)
        End Sub

        <Serializable()> Public Class ConditionFactoryDefinition
            Implements ICloneable

            Public ConditionType As ConditionTypes
            Public ConditionInitialValue As Object
            Public ConditionName As String

            Public ConditionDescriptionDefinition As LocalizableString.Definition
            Public ConditionIsStatic As Boolean

            Public PrerequisiteFactoryDefinition As PredicateFactory.PredicateFactoryDefinition
            Public InitializationArgs As Object()

            Public Function Clone() As Object Implements ICloneable.Clone
                Dim newDef As New ConditionFactoryDefinition
                newDef.ConditionType = ConditionType
                newDef.ConditionInitialValue = ConditionInitialValue
                newDef.ConditionName = ConditionName
                newDef.ConditionDescriptionDefinition = ConditionDescriptionDefinition.DeepCopy
                newDef.ConditionIsStatic = ConditionIsStatic
                newDef.PrerequisiteFactoryDefinition = PrerequisiteFactoryDefinition.DeepCopy
                ReDim newDef.InitializationArgs(InitializationArgs.Length - 1)
                For i As Integer = 0 To InitializationArgs.Length - 1
                    newDef.InitializationArgs(i) = InitializationArgs(i)
                Next
                Return newDef
            End Function

            Public Function DeepCopy() As ConditionFactoryDefinition
                Return DirectCast(Clone(), ConditionFactoryDefinition)
            End Function

            Public Function CreateConditionFactory() As ConditionFactory
                Dim factory As New ConditionFactory
                factory.mDefinition = DeepCopy()
                factory.mPrerequisiteFactory = PrerequisiteFactoryDefinition.CreatePredicateFactory
                factory.mConditionDescription = ConditionDescriptionDefinition.CreateLocalizableString
                Return factory
            End Function

        End Class

        Public Property ConditionIsStatic() As Boolean
            Get
                Return mDefinition.ConditionIsStatic
            End Get
            Set(ByVal value As Boolean)
                mDefinition.ConditionIsStatic = value
            End Set
        End Property


        Public Sub InitalizationArgs(ByVal ParamArray args As Object())
            mDefinition.InitializationArgs = args
        End Sub

        Public Property ConditionDescription() As LocalizableString
            Get
                Return mConditionDescription
            End Get
            Set(ByVal value As LocalizableString)
                mConditionDescription = value
            End Set
        End Property

        Public Property ConditionDescription(ByVal region As String) As String
            Get
                Return mConditionDescription(region)
            End Get
            Set(ByVal Value As String)
                mConditionDescription(region) = Value
            End Set
        End Property

        Public Property PrerequisiteFactory() As PredicateFactory
            Get
                If mPrerequisiteFactory Is Nothing Then Return BuiltIns.PredicateFactories.TrueLiteral
                Return mPrerequisiteFactory
            End Get
            Set(ByVal value As PredicateFactory)
                mPrerequisiteFactory = value
            End Set
        End Property

        Public Property ConditionType() As ConditionTypes
            Get
                Return mDefinition.ConditionType
            End Get
            Set(ByVal value As ConditionTypes)
                mDefinition.ConditionType = value
            End Set
        End Property

        Public Property ConditionInitialValue() As Object
            Get
                Return mDefinition.ConditionInitialValue
            End Get
            Set(ByVal value As Object)
                mDefinition.ConditionInitialValue = value
            End Set
        End Property

        Public Property ConditionName() As String
            Get
                Return mDefinition.ConditionName
            End Get
            Set(ByVal value As String)
                mDefinition.ConditionName = value
            End Set
        End Property


        Public Function Create(ByVal conditions As ConditionCollection) _
        As Condition
            Select Case mDefinition.ConditionType
                Case ConditionTypes.BooleanCondition
                    Dim val As Boolean = DirectCast(mDefinition.ConditionInitialValue, Boolean)

                    ' Transform each LocalizableString.Definition to a LocalizableString
                    For i As Integer = 0 To 5
                        Dim arg As Object = mDefinition.InitializationArgs(i)
                        If arg.GetType().Equals(GetType(LocalizableString.Definition)) Then
                            mDefinition.InitializationArgs(i) = DirectCast(arg, LocalizableString.Definition).CreateLocalizableString
                        End If
                    Next

                    Create = New BooleanCondition( _
                        mDefinition.ConditionName, _
                        val, _
                        DirectCast(mDefinition.InitializationArgs(0), LocalizableString), _
                        DirectCast(mDefinition.InitializationArgs(1), LocalizableString), _
                        DirectCast(mDefinition.InitializationArgs(2), LocalizableString), _
                        DirectCast(mDefinition.InitializationArgs(3), LocalizableString), _
                        DirectCast(mDefinition.InitializationArgs(4), LocalizableString), _
                        DirectCast(mDefinition.InitializationArgs(5), LocalizableString))
            End Select

            If Not mPrerequisiteFactory Is Nothing Then Create.Prerequisite = mPrerequisiteFactory.CreatePredicate(conditions)

            Create.WireOriginatingFactory(Me)
        End Function

        Public Function Definition() As ConditionFactoryDefinition
            mDefinition.PrerequisiteFactoryDefinition = PrerequisiteFactory.Definition

            Select Case mDefinition.ConditionType
                Case ConditionTypes.BooleanCondition
                    For i As Integer = 0 To 5
                        ' Transform objects that are localizable strings to their definitions
                        Dim arg As Object = mDefinition.InitializationArgs(i)
                        If arg.GetType().Equals(GetType(LocalizableString)) Then
                            mDefinition.InitializationArgs(i) = DirectCast(arg, LocalizableString).CreateDefinition
                        End If
                    Next
            End Select
            mDefinition.ConditionDescriptionDefinition = mConditionDescription.CreateDefinition

            Return mDefinition.DeepCopy
        End Function



    End Class

    Public Class ConditionFactoryCollection

        <Serializable()> _
        Public Class Definition
            Implements ICloneable

            Public EquivalenceClassFactoryDefinitions() As PredicateFactory.PredicateFactoryDefinition
            Public FactoryDefinitions() As ConditionFactory.ConditionFactoryDefinition

            Public Function Clone() As Object Implements System.ICloneable.Clone
                Dim newDef As New Definition
                ReDim newDef.EquivalenceClassFactoryDefinitions(EquivalenceClassFactoryDefinitions.Length - 1)
                For i As Integer = 0 To EquivalenceClassFactoryDefinitions.Length - 1
                    newDef.EquivalenceClassFactoryDefinitions(i) = EquivalenceClassFactoryDefinitions(i).DeepCopy
                Next

                ReDim newDef.FactoryDefinitions(FactoryDefinitions.Length - 1)
                For i As Integer = 0 To FactoryDefinitions.Length - 1
                    newDef.FactoryDefinitions(i) = FactoryDefinitions(i).DeepCopy()
                Next
                Return newDef
            End Function

            Public Function DeepCopy() As Definition
                Return DirectCast(Clone(), Definition)
            End Function

            Public Function CreateConditionFactoryCollection() As ConditionFactoryCollection
                Dim factories As New ConditionFactoryCollection
                For i As Integer = 0 To FactoryDefinitions.Length - 1
                    factories.Add(FactoryDefinitions(i).CreateConditionFactory())
                Next

                For i As Integer = 0 To EquivalenceClassFactoryDefinitions.Length - 1
                    factories.AddEquivalenceClassFactory(EquivalenceClassFactoryDefinitions(i).CreatePredicateFactory)
                Next

                Return factories

            End Function

        End Class

        Private mDefinition As ConditionFactoryCollection.Definition

        Private mEquivalenceClassFactories As New ArrayList
        Private mFactories As New ArrayList

        Public Sub AddEquivalenceClassFactory(ByVal factory As PredicateFactory)
            mEquivalenceClassFactories.Add(factory)
        End Sub

        Public Sub Add(ByVal factory As ConditionFactory)
            mFactories.Add(factory)
        End Sub
        Public ReadOnly Property Count() As Integer
            Get
                Return mFactories.Count
            End Get
        End Property
        Default Public Property Item(ByVal index As Integer) As ConditionFactory
            Get
                Return DirectCast(mFactories(index), ConditionFactory)
            End Get
            Set(ByVal Value As ConditionFactory)
                mFactories(index) = Value
            End Set
        End Property

        Public Function CreateDefinition() As ConditionFactoryCollection.Definition
            Dim def As New ConditionFactoryCollection.Definition

            ReDim def.EquivalenceClassFactoryDefinitions(mEquivalenceClassFactories.Count - 1)
            For i As Integer = 0 To mEquivalenceClassFactories.Count - 1
                def.EquivalenceClassFactoryDefinitions(i) = DirectCast(mEquivalenceClassFactories(i), PredicateFactory).Definition
            Next

            ReDim def.FactoryDefinitions(mFactories.Count - 1)
            For i As Integer = 0 To mFactories.Count - 1
                def.FactoryDefinitions(i) = DirectCast(mFactories(i), ConditionFactory).Definition
            Next
            Return def
        End Function

        Public Function CreateConditionCollection() As ConditionCollection
            Dim conditions As New ConditionCollection
            For i As Integer = 0 To mFactories.Count - 1
                Dim factory As ConditionFactory = Item(i)
                conditions(factory.ConditionName) = factory.Create(conditions)
            Next
            For i As Integer = 0 To mEquivalenceClassFactories.Count - 1
                Dim factory As PredicateFactory = DirectCast(mEquivalenceClassFactories(i), PredicateFactory)
                conditions.AddEquivalenceClass(factory)
            Next
            Return conditions
        End Function


        Public Shared Function Create(ByVal definition As ConditionFactoryCollection.Definition) As ConditionFactoryCollection
            Dim newFactories As New ConditionFactoryCollection

            For i As Integer = 0 To definition.FactoryDefinitions.Length - 1
                newFactories.Add(definition.FactoryDefinitions(i).CreateConditionFactory())
            Next

            For i As Integer = 0 To definition.EquivalenceClassFactoryDefinitions.Length - 1
                newFactories.AddEquivalenceClassFactory(definition.EquivalenceClassFactoryDefinitions(i).CreatePredicateFactory())
            Next


            Return newFactories

        End Function


        'Public Function CreateConditionCollection(ByVal parentTask As SensorTask) As ConditionCollection
        '    Dim conditions As ConditionCollection = Create()
        '    conditions.WireParentTask(parentTask)
        '    Return conditions
        'End Function


    End Class

End Namespace
