@@ -5,6 +5,7 @@ namespace ConstraintsMatcher
55 using System ;
66 using System . Collections . Generic ;
77 using System . Linq ;
8+ using System . Text . RegularExpressions ;
89
910 public class Matcher
1011 {
@@ -30,6 +31,7 @@ public Matcher(IModel model)
3031 public bool PreCheck ( IModel constraintsModel )
3132 {
3233 var Nodes = new List < INode > ( ) ;
34+ //Find the root
3335 foreach ( var node in constraintsModel . Nodes )
3436 {
3537 var inEdges = constraintsModel . Edges . Where ( x => x . To == node ) . ToList ( ) ;
@@ -44,26 +46,68 @@ public bool PreCheck(IModel constraintsModel)
4446 return false ;
4547 }
4648 this . root = Nodes . FirstOrDefault ( ) ;
49+ // Check if root is correct
4750 if ( ( this . root . Class . Name == "NotNode" ) || ( this . root . Class . Name == "OrNode" ) || ( this . root . Class . Name == "NoNodes" ) )
4851 {
49- this . ErrorMsg = "The root should be NodeType from modrl or AllNodes." ;
52+ this . ErrorMsg = "The root should be NodeType from model or AllNodes." ;
5053 return false ;
5154 }
55+ // Check ther there is only one outcoming edge from notNode
5256 var notNodes = constraintsModel . Nodes . Where ( x => x . Class . Name == "NotNode" ) ;
5357 foreach ( var notNode in notNodes )
5458 {
5559 if ( constraintsModel . Edges . Where ( x => x . From == notNode ) . ToList ( ) . Count ( ) > 1 )
5660 {
61+ this . ErrorMsg = "There should be only one outgoing edge from Not Node." ;
5762 return false ;
5863 }
5964 }
60- //TODO check if tree
65+ //Check if there is no outgoing edges from noNodes
66+ var noNodes = constraintsModel . Nodes . Where ( x => x . Class . Name == "NoNodes" ) ;
67+ foreach ( var noNode in noNodes )
68+ {
69+ if ( constraintsModel . Edges . Where ( x => x . From == noNode ) . ToList ( ) . Count ( ) > 0 )
70+ {
71+ this . ErrorMsg = "There shouldn't be outgoing edges from NoNodes" ;
72+ return false ;
73+ }
74+ }
75+ // Check if this constraint is a tree
76+ var visited = new HashSet < int > ( ) ;
77+ if ( ! this . CheckIfTree ( constraintsModel , this . root , visited ) )
78+ {
79+ this . ErrorMsg = "Constraints graph should have a tree structure." ;
80+ return false ;
81+ }
82+
6183 return true ;
6284 }
6385
86+ public bool CheckIfTree ( IModel constraintsModel , INode root , HashSet < int > visited )
87+ {
88+ visited . Add ( root . GetHashCode ( ) ) ;
89+ var outgoingEdges = constraintsModel . Edges . Where ( x => x . From == root ) ;
90+ foreach ( var edge in outgoingEdges )
91+ {
92+ if ( visited . Any ( x => x == edge . To . GetHashCode ( ) ) )
93+ {
94+ return false ;
95+ }
96+ if ( ! CheckIfTree ( constraintsModel , ( INode ) edge . To , visited ) )
97+ {
98+ return false ;
99+ }
100+ }
101+ return true ;
102+ }
64103 public bool Check ( INode originRoot , INode constraintsRoot , IModel constraintsModel )
65104 {
66- return this . InnerCheck ( originRoot , constraintsRoot , constraintsModel ) ;
105+ return this . InnerCheck ( originRoot , constraintsRoot , constraintsModel ) ;
106+ }
107+
108+ public bool AttrCheck ( INode originRoot , INode constraintsRoot )
109+ {
110+ return this . AttributesAreIdentic ( originRoot , constraintsRoot ) ;
67111 }
68112
69113 private bool InnerCheck ( INode targetRoot , INode constraintsRoot , IModel constraintsModel )
@@ -73,7 +117,7 @@ private bool InnerCheck(INode targetRoot, INode constraintsRoot, IModel constrai
73117 var areIdentic = ElementsAreIdentic ( targetRoot , constraintsRoot ) ;
74118 if ( constraintsRoot . Class . Name == "AllNodes" )
75119 {
76- areIdentic = true ;
120+ areIdentic = this . AttributesAreIdentic ( targetRoot , constraintsRoot ) ;
77121 }
78122 if ( constraintsRoot . Class . Name == "AnyNodes" )
79123 {
@@ -104,7 +148,7 @@ private bool InnerCheck(INode targetRoot, INode constraintsRoot, IModel constrai
104148 var constraintsToRoot = ( INode ) outConstraintsEdges . FirstOrDefault ( ) . To ;
105149 var targetParentRoot = ( INode ) this . targetModel . Edges . Where ( x => x . To == targetRoot ) . FirstOrDefault ( ) . From ;
106150 var outParentTargetEdges = this . targetModel . Edges . Where ( x => x . From == targetParentRoot ) ;
107- var innerCheck = outParentTargetEdges . Any ( x => ElementsAreIdentic ( constraintParentEdge , x ) && this . InnerCheck ( ( INode ) x . To , constraintsToRoot , constraintsModel ) ) ;
151+ var innerCheck = outParentTargetEdges . Any ( x => ElementsAreIdentic ( x , constraintParentEdge ) && this . InnerCheck ( ( INode ) x . To , constraintsToRoot , constraintsModel ) ) ;
108152 return ! innerCheck ;
109153 }
110154 if ( ( outConstraintsEdges . Count ( ) > 0 ) && ( outConstraintsEdges . FirstOrDefault ( ) . To . Class . Name == "NoNodes" ) )
@@ -146,17 +190,54 @@ private bool FindEdge(IEnumerable<IEdge> outTargetEdges, IEdge edge)
146190 return false ;
147191 }
148192
149- public bool ElementsAreIdentic ( IElement firstElement , IElement secondElement )
193+ public bool ElementsAreIdentic ( IElement targetElement , IElement constraintsElement )
150194 {
151- if ( firstElement . Class . Name != secondElement . Class . Name )
195+ if ( ( targetElement . Class . Name != constraintsElement . Class . Name ) || ! AttributesAreIdentic ( targetElement , constraintsElement ) )
152196 {
153197 return false ;
154198 }
155- foreach ( var attr in firstElement . Attributes )
199+ return true ;
200+ }
201+
202+ public bool AttributesAreIdentic ( IElement targetElement , IElement constraintsElement )
203+ {
204+ foreach ( var targetAttr in targetElement . Attributes )
156205 {
157- if ( secondElement . Attributes . Where ( x => x . Name == attr . Name ) . FirstOrDefault ( ) . StringValue != attr . StringValue )
206+ if ( targetAttr . StringValue != "Link" )
158207 {
159- return false ;
208+ var constraintsAttr = constraintsElement . Attributes . Where ( x => x . Name == targetAttr . Name ) . FirstOrDefault ( ) ;
209+
210+ if ( constraintsAttr . StringValue == "*" )
211+ return true ;
212+
213+ if ( ( constraintsAttr . StringValue . Length > 3 ) && ( constraintsAttr . StringValue . Substring ( 0 , 2 ) == "<=" ) )
214+ {
215+ var value = constraintsAttr . StringValue . Substring ( 2 ) ;
216+ return ( Convert . ToInt32 ( targetAttr . StringValue ) <= Convert . ToInt32 ( value ) ) ;
217+ }
218+ else if ( ( constraintsAttr . StringValue . Length > 3 ) && ( constraintsAttr . StringValue . Substring ( 0 , 2 ) == ">=" ) )
219+ {
220+ var value = constraintsAttr . StringValue . Substring ( 2 ) ;
221+ return ( Convert . ToInt32 ( targetAttr . StringValue ) >= Convert . ToInt32 ( value ) ) ;
222+ }
223+ else if ( ( constraintsAttr . StringValue . Length > 2 ) && ( constraintsAttr . StringValue [ 0 ] == '<' ) )
224+ {
225+ var value = constraintsAttr . StringValue . Substring ( 1 ) ;
226+ return ( Convert . ToInt32 ( targetAttr . StringValue ) < Convert . ToInt32 ( value ) ) ;
227+ }
228+ else if ( ( constraintsAttr . StringValue . Length > 2 ) && ( constraintsAttr . StringValue [ 0 ] == '>' ) )
229+ {
230+ var value = constraintsAttr . StringValue . Substring ( 1 ) ;
231+ return ( Convert . ToInt32 ( targetAttr . StringValue ) > Convert . ToInt32 ( value ) ) ;
232+ }
233+ else
234+ {
235+ Regex regEx = new Regex ( constraintsAttr . StringValue ) ;
236+ if ( ! regEx . IsMatch ( targetAttr . StringValue ) )
237+ {
238+ return false ;
239+ }
240+ }
160241 }
161242 }
162243 return true ;
0 commit comments