<taskModel xmlns="http://ce.org/cea-2018" about="urn:cetask.wpi.edu:examples:policytaskmodel:ConstraintInit">
	<!-- definitions for all objects and
			functions related to constraints
		 Part of the initialization code for the task model in policytaskmodel.xml
		 (Project for CS 525U)
		 Author: Paul Freitas
		 Date: 4/8/08 -->
		 
	<script init="true">
		//****************************************************
		//Constraint class
		//****************************************************
		function Constraint() {
			this.constraintType = 'Constraint';
			
			this.getConflicts = function(matrix,constraints) {
				return undefined;
			}
			
			this.checkConstraint = function (matrix,constraints) {
				return false;
			}
			
			this.equals = function(otherC) {
				if(otherC.constraintType == this.constraintType) {
					return true;
				}
				return false;
			}
			
			this.toString = function() {
				var retVal = "";
				var pieces = eval(this.constraintType + ".templateString").split('%');
				
				retVal += pieces[0];
				for(var i = 1; i &lt; pieces.length; i++) {
					retVal += eval("this." + pieces[i]);
					i++;
					retVal += pieces[i];
				}
				
				return retVal;
			}
		}
		
		Constraint.templateString = "";
		
		function ConflictOfInterestConstraint(a1,a2) {
			this.action1 = a1;
			this.action2 = a2;
			this.constraintType = 'ConflictOfInterestConstraint';
			
			this.checkConstraint = function (matrix,constraints) {
				//check basic rows in matrix
				for(var i = 0; i &lt; matrix.rownames.length; i++) {
					var r = matrix.rownames[i];
					if(matrix.get(r,this.action1) == ACDecision.PERMIT //note: possibly a 'warning' value if the decision is 'notapplicable'?
					&amp;&amp; matrix.get(r,this.action2) == ACDecision.PERMIT) {
						return false;
					}
				}
				
				//check double role stuff--since this only supports two actions, don't need to examine more than 2 rows at a time
				for(var i = 0; i &lt; matrix.rownames.length; i++) {
					var r1 = matrix.rownames[i];
					for(var j = i + 1; j &lt; matrix.rownames.length; j++) {
						var r2 = matrix.rownames[j];
						//check that the role combination does not violate any separation of duties constraints
						if(notSeparatedDuties(r1,r2,constraints)) {
							if((matrix.get(r1,this.action1) == ACDecision.PERMIT || matrix.get(r2,this.action1) == ACDecision.PERMIT)
							&amp;&amp; (matrix.get(r1,this.action2) == ACDecision.PERMIT || matrix.get(r2,this.action2) == ACDecision.PERMIT)) {
								return false
							}
						}
					}
				}
				return true;
			}
			
			this.getConflicts = function (matrix,constraints,currCRs) {
				//check basic rows in matrix
				var cds = new Array(0);
				for(var i = 0; i &lt; matrix.rownames.length; i++) {
					var r = matrix.rownames[i];
					if(matrix.get(r,this.action1) == ACDecision.PERMIT //note: possibly a 'warning' value if the decision is 'notapplicable'?
					&amp;&amp; matrix.get(r,this.action2) == ACDecision.PERMIT) {
						//single-role conflict-only ways to fix this are to change the decision or remove the constraint
						var cresolvers1 = new Array(0);
						var cresolvers2 = new Array(0);
						var newCR = new RemConstraintCR(this);
						var dup = checkDupCR(currCRs,newCR);
						if(dup != -1) {
							newCR = currCRs[dup];
						} else {
							currCRs.push(newCR);
						}
						cresolvers1.push(newCR);
						cresolvers2.push(newCR);
						
						newCR = new ChangeDecCR(r,this.action1,ACDecision.DENY);
						dup = checkDupCR(currCRs,newCR);
						if(dup != -1) {
							newCR = currCRs[dup];
						} else {
							currCRs.push(newCR);
						}
						cresolvers1.push(newCR);
						
						newCR = new ChangeDecCR(r,this.action2,ACDecision.DENY);
						dup = checkDupCR(currCRs,newCR);
						if(dup != -1) {
							newCR = currCRs[dup];
						} else {
							currCRs.push(newCR);
						}
						cresolvers2.push(newCR);
						
						var newCD = new ConflictDesignator(this,[r],this.action1,cresolvers1);
						cds.push(newCD);
						newCD = new ConflictDesignator(this,[r],this.action2,cresolvers2);
						cds.push(newCD);
					}
				}
				
				//check double role stuff--since this constraint only supports two actions, don't need to examine more than 2 rows at a time
				for(var i = 0; i &lt; matrix.rownames.length; i++) {
					var r1 = matrix.rownames[i];
					for(var j = i + 1; j &lt; matrix.rownames.length; j++) {
						var r2 = matrix.rownames[j];
						//check that the role combination does not violate any separation of duties constraints
						if(notSeparatedDuties(r1,r2,constraints)) {
							if(matrix.getDecision(this.action1,r1,r2) == ACDecision.PERMIT
							 &amp;&amp; matrix.getDecision(this.action2,r1,r2) == ACDecision.PERMIT) {
							 	//check that this conflict has not already been caught
							 	if(!containsCDinSet(cds,this,[r1,r2],[this.action1,this.action2])) {						 	
									//double-role conflict-same ways of clearing up, plus add a new SepDuties constraint
									var cresolvers1 = new Array(0);
									var cresolvers2 = new Array(0);
									var newCR = new RemConstraintCR(this);
									var dup = checkDupCR(currCRs,newCR);
									if(dup != -1) {
										newCR = currCRs[dup];
									} else {
										currCRs.push(newCR);
									}
									cresolvers1.push(newCR);
									cresolvers2.push(newCR);
									
									newCR = new AddConstraintCR(new SeparationOfDutiesConstraint(r1,r2));
									dup = checkDupCR(currCRs,newCR);
									if(dup != -1) {
										newCR = currCRs[dup];
									} else {
										currCRs.push(newCR);
									}
									cresolvers1.push(newCR);
									cresolvers2.push(newCR);
									
									newCR = new ChangeDecCR(r,this.action1,ACDecision.DENY);
									dup = checkDupCR(currCRs,newCR);
									if(dup != -1) {
										newCR = currCRs[dup];
									} else {
										currCRs.push(newCR);
									}
									cresolvers1.push(newCR);
									
									newCR = new ChangeDecCR(r,this.action2,ACDecision.DENY);
									dup = checkDupCR(currCRs,newCR);
									if(dup != -1) {
										newCR = currCRs[dup];
									} else {
										currCRs.push(newCR);
									}
									cresolvers2.push(newCR);
									
									var newCD = new ConflictDesignator(this,[r1,r2],this.action1,cresolvers1);
									cds.push(newCD);
									newCD = new ConflictDesignator(this,[r1,r2],this.action2,cresolvers2);
									cds.push(newCD);
								}
							}
						}
					}
				}
				return cds;
			}
			
			this.equals = function(otherC) {
				if(otherC.constraintType == this.constraintType) {
					if((this.action1 == otherC.action1 &amp;&amp; this.action2 == otherC.action2)
						|| (this.action1 == otherC.action2 &amp;&amp; this.action2 == otherC.action1)) {
						return true;
					}
				}
				return false;
			}
		};
		
		ConflictOfInterestConstraint.prototype = new Constraint();
		
		ConflictOfInterestConstraint.templateString = "No one may both %action1% and %action2%.";
		
		function SeparationOfDutiesConstraint(r1,r2) {
			this.role1 = r1;
			this.role2 = r2;
			this.constraintType = 'SeparationOfDutiesConstraint';
			
			this.checkConstraint = function (matrix,constraints) {
				return true;
			}
			
			this.getConflicts = function (matrix,constraints,currCRs) {
				//can't be a conflict from this...this can only remove conflicts
				return new Array(0);
			}
			
			this.contains =  function(role) {
				if(this.role1 == role || this.role2 == role) {
					return true;
				}
				return false;
			}
			
			this.equals = function(otherC) {
				if(otherC.constraintType == this.constraintType) {
					if((this.role1 == otherC.role1 &amp;&amp; this.role2 == otherC.role2)
						|| (this.role1 == otherC.role2 &amp;&amp; this.role2 == otherC.role1)) {
						return true;
					}
				}
				return false;
			}
		}
		
		SeparationOfDutiesConstraint.prototype = new Constraint();
		
		SeparationOfDutiesConstraint.templateString = "No user may be both a %role1% and a %role2%.";
		
		function TestConstraint(r1,a1,r2) {
			this.role1 = r1;
			this.action1 = a1;
			this.role2 = r2;
			this.constraintType = 'TestConstraint';
			
			this.checkConstraint = function (matrix,constraints) {
				return true;
			}
			
			this.getConflicts = function (matrix,constraints,currCRs) {
				//can't be a conflict from this...this can only remove conflicts
				return new Array(0);
			}
			
			this.contains =  function(role) {
				if(this.role1 == role || this.role2 == role) {
					return true;
				}
				return false;
			}
			
			this.equals = function(otherC) {
				if(otherC.constraintType == this.constraintType) {
					if((this.role1 == otherC.role1 &amp;&amp; this.role2 == otherC.role2)
						|| (this.role1 == otherC.role2 &amp;&amp; this.role2 == otherC.role1)) {
						return true;
					}
				}
				return false;
			}
		}
		
		TestConstraint.prototype = new Constraint();
		
		TestConstraint.templateString = "No %role1% may %action1% if %role2% may %action1%. NO %role2%.";
	
		//****************************************************
		// GENERIC Constraint UTILITIES
		//****************************************************
		function notSeparatedDuties(role1,role2,constraints) {
			for(var i = 0; i &lt; constraints.length; i++) {
				if(constraints[i].constraintType == 'SeparationOfDutiesConstraint'
				&amp;&amp; constraints[i].contains(role1) &amp;&amp; constraints[i].contains(role2)) {
					return false;
				}
			}
			
			return true;
		}
	</script>
</taskModel>