View Javadoc

1   /**
2    * Copyright 2010 The Kuali Foundation Licensed under the
3    * Educational Community License, Version 2.0 (the "License"); you may
4    * not use this file except in compliance with the License. You may
5    * obtain a copy of the License at
6    *
7    * http://www.osedu.org/licenses/ECL-2.0
8    *
9    * Unless required by applicable law or agreed to in writing,
10   * software distributed under the License is distributed on an "AS IS"
11   * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12   * or implied. See the License for the specific language governing
13   * permissions and limitations under the License.
14   */
15  
16  package org.kuali.student.common.ui.client.widgets.rules;
17  
18  import java.util.List;
19  
20  import org.kuali.student.common.ui.client.widgets.table.Node;
21  import org.kuali.student.core.statement.dto.StatementInfo;
22  import org.kuali.student.core.statement.dto.StatementOperatorTypeKey;
23  
24  public class RuleInfo {
25  
26      private StatementVO statementVO;        //top-level statement (tree ROOT)
27      private EditHistory editHistory;
28      private boolean simplifying;
29  
30      public RuleInfo() {
31          setEditHistory(new EditHistory(statementVO));
32          setStatementVO(createNewStatementVO());
33      }
34  
35      public StatementVO createNewStatementVO() {
36          StatementInfo newStatementTree = new StatementInfo();
37          newStatementTree.setOperator(StatementOperatorTypeKey.AND);
38          newStatementTree.setType(getStatementTypeKey());
39          StatementVO statementVO = new StatementVO();                            
40          statementVO.setStatementInfo(newStatementTree);
41          return statementVO;
42      }
43      
44      public Node getStatementTree() {
45          return (statementVO != null ? statementVO.getTree() : null);
46      }
47      
48      public EditHistory getEditHistory() {
49          return editHistory;
50      }
51  
52      public void setEditHistory(EditHistory editHistory) {
53          this.editHistory = editHistory;
54      }
55      
56      private boolean statementVOIsGroupAble(List<StatementVO> selectedStatementVOs, List<ReqComponentVO> selectedReqComponentVOs) {
57          boolean orable = false;
58          StatementVO enclosingStatement = null;
59          boolean reqComponentsInSameGroup = true;
60          int numStatementsSelection = (selectedStatementVOs == null)? 0 : selectedStatementVOs.size();
61          int numReqComponentSelection = (selectedReqComponentVOs == null)? 0 : selectedReqComponentVOs.size();
62          int numSelection = numStatementsSelection + numReqComponentSelection;
63          
64          // At least 2 items (StatementVO or RC) must be selected.
65          if (numSelection >= 2) {
66              if (numStatementsSelection > 0) {
67                  enclosingStatement = this.statementVO.getParentStatementVO(this.statementVO, selectedStatementVOs.get(0));
68              } else {
69                  enclosingStatement = this.statementVO.getEnclosingStatementVO(this.statementVO, selectedReqComponentVOs.get(0));
70              }
71              
72              if (numStatementsSelection > 0) {
73                  for (StatementVO selectedStatementVO : selectedStatementVOs) {
74                      StatementVO enclosingStatement2 = this.statementVO.getParentStatementVO(this.statementVO, selectedStatementVO);
75                      if (enclosingStatement != enclosingStatement2) {
76                          reqComponentsInSameGroup = false;
77                          break;
78                      }
79                  }
80              }
81              if (numReqComponentSelection > 0) {
82                  for (ReqComponentVO selectedReqCompoentVO : selectedReqComponentVOs) {
83                      StatementVO enclosingStatement2 = this.statementVO.getEnclosingStatementVO(this.statementVO, selectedReqCompoentVO);
84                      if (enclosingStatement != enclosingStatement2) {
85                          reqComponentsInSameGroup = false;
86                          break;
87                      }
88                  }
89              }
90              
91              // the items selected must all belong to the same group
92              if (!reqComponentsInSameGroup) return false;
93              
94              int childCount = (enclosingStatement == null)? 0 : enclosingStatement.getChildCount();
95              
96              // number of selected requirement components must be less the the total number of
97              // requirement components of the enclosing statement
98              if (selectedReqComponentVOs != null && !selectedReqComponentVOs.isEmpty() && childCount > numSelection) {
99                  orable = true;
100             } else {
101                 orable = false;
102             }
103         } else {
104             orable = false;
105         }
106 
107         return orable;
108     }
109 
110     public boolean statementVOIsGroupAble() {
111         List<StatementVO> selectedStatementVOs = getSelectedStatementVOs();
112         List<ReqComponentVO> selectedReqComponentVOs = getSelectedReqComponentVOs();
113         return statementVOIsGroupAble(selectedStatementVOs, selectedReqComponentVOs);
114     }
115     
116     public void insertOR() {
117         List<StatementVO> selectedStatementVOs = getSelectedStatementVOs();
118         List<ReqComponentVO> selectedReqComponentVOs = getSelectedReqComponentVOs();
119 
120         // check if the selections can be grouped by OR operator.
121         if (!statementVOIsGroupAble(selectedStatementVOs, selectedReqComponentVOs)) return;
122         StatementVO enclosingStatementVO = statementVO.getEnclosingStatementVO(statementVO, selectedReqComponentVOs.get(0));
123 
124         // create new statement to hold the new OR group
125         StatementVO newStatementVO = createNewStatementVO();
126         StatementInfo newLuStatementInfo = newStatementVO.getStatementInfo();
127         newLuStatementInfo.setOperator(StatementOperatorTypeKey.OR);
128         newStatementVO.setStatementInfo(newLuStatementInfo);
129 
130         // remove the selected RCs from original statement and move them into the new StatementVO
131         for (ReqComponentVO selectedReqComponentVO : selectedReqComponentVOs) {
132             enclosingStatementVO.removeReqComponentVO(selectedReqComponentVO);
133             newStatementVO.addReqComponentVO(selectedReqComponentVO);
134         }
135 
136         // remove the selected StatementVOs from original statement and move them into the new StatementVO
137         for (StatementVO selectedStatementVO : selectedStatementVOs) {
138             enclosingStatementVO.removeStatementVO(selectedStatementVO);
139             newStatementVO.addStatementVO(selectedStatementVO);
140         }
141         enclosingStatementVO.addStatementVO(newStatementVO);
142     }
143     
144     public void insertAND() {
145         List<StatementVO> selectedStatementVOs = getSelectedStatementVOs();
146         List<ReqComponentVO> selectedReqComponentVOs = getSelectedReqComponentVOs();
147 
148         // check if the selections can be grouped by OR operator.
149         if (!statementVOIsGroupAble(selectedStatementVOs, selectedReqComponentVOs)) return;
150 
151         StatementVO enclosingStatementVO = statementVO.getEnclosingStatementVO(statementVO, selectedReqComponentVOs.get(0));
152         // create new statement to hold the new OR group
153         StatementVO newStatementVO = createNewStatementVO();
154         StatementInfo newLuStatementInfo = newStatementVO.getStatementInfo();
155         newLuStatementInfo.setOperator(StatementOperatorTypeKey.AND);
156         newStatementVO.setStatementInfo(newLuStatementInfo);
157 
158         // remove the selected RCs from original statement and move them into the new StatementVO
159         for (ReqComponentVO selectedReqComponentVO : selectedReqComponentVOs) {
160             enclosingStatementVO.removeReqComponentVO(selectedReqComponentVO);
161             newStatementVO.addReqComponentVO(selectedReqComponentVO);
162         }
163 
164         // remove the selected StatementVOs from original statement and move them into the new StatementVO
165         for (StatementVO selectedStatementVO : selectedStatementVOs) {
166             enclosingStatementVO.removeStatementVO(selectedStatementVO);
167             newStatementVO.addStatementVO(selectedStatementVO);
168         }
169         
170         enclosingStatementVO.addStatementVO(newStatementVO);
171     }
172     
173     public boolean statementVOIsDegroupAble() {
174         List<StatementVO> selectedStatementVOs = getSelectedStatementVOs();
175         List<ReqComponentVO> selectedReqComponentVOs = getSelectedReqComponentVOs();
176         return statementVOIsDegroupAble(selectedStatementVOs, selectedReqComponentVOs);
177     }
178     
179     private boolean statementVOIsDegroupAble(List<StatementVO> selectedStatementVOs, List<ReqComponentVO> selectedReqComponentVOs) {
180         boolean degroupAble = false;
181         boolean selectedRootStatementVO = false;
182         boolean otherItemsExist = false;
183 
184         // at least one item is selected
185         if ((selectedStatementVOs != null && !selectedStatementVOs.isEmpty()) || 
186             (selectedReqComponentVOs != null && !selectedReqComponentVOs.isEmpty())) {
187             degroupAble = true;
188         } else {
189             return false;
190         }
191         
192         // root statement should not be selected if there are other items.
193         for (StatementVO selectedStatement : selectedStatementVOs) {
194             if (selectedStatement == this.statementVO) {
195                 selectedRootStatementVO = true;
196                 break;
197             }
198         }
199 
200         otherItemsExist = this.statementVO.getChildCount() > 0;
201         if (selectedRootStatementVO && otherItemsExist) {
202             degroupAble = degroupAble && false;
203         } else{
204             degroupAble = degroupAble && true;
205         }
206         
207         // must leave at least 2 children in a group unselected or all children are RCs and are selected.
208         // Except for root.  For root, if root statement does not have any sub statements then it is okay to delete
209         for (ReqComponentVO selectedRC : selectedReqComponentVOs) {
210             StatementVO parentStatementVO = this.statementVO.getEnclosingStatementVO(this.statementVO, selectedRC);
211             int numSelectedChildren = 0;
212             int numSelectedChildrenRC = 0;
213             if (parentStatementVO.getStatementVOCount() > 0) {
214                 for (StatementVO subStatementVO : 
215                     parentStatementVO.getStatementVOs()) {
216                     if (subStatementVO.isWrapperStatementVO() &&
217                             subStatementVO.getReqComponentVOs().get(0).isCheckBoxOn()) {
218                         numSelectedChildren++;
219                     } else if (subStatementVO.isCheckBoxOn()) {
220                         numSelectedChildren++;
221                     }
222                 }
223             } else if (parentStatementVO.getReqComponentVOCount() > 0) {
224                 for (ReqComponentVO rcVO : parentStatementVO.getReqComponentVOs()) {
225                     if (rcVO.isCheckBoxOn()) {
226                         numSelectedChildren++;
227                         numSelectedChildrenRC++;
228                     }
229                 }
230             }
231             if (parentStatementVO.getChildCount() - numSelectedChildren > 1) {
232                 degroupAble = degroupAble && true;
233             } else if (numSelectedChildrenRC == parentStatementVO.getChildCount()) {
234                 degroupAble = degroupAble && true;
235             } else if (parentStatementVO == this.statementVO && parentStatementVO.getStatementVOCount() == 0) {
236                 degroupAble = degroupAble && true;
237             } else {
238                 degroupAble = false;
239             }
240         }
241         return degroupAble;
242     }
243     
244     public void deleteItem() {
245         List<StatementVO> selectedStatementVOs = getSelectedStatementVOs();
246         List<ReqComponentVO> selectedReqComponentVOs = getSelectedReqComponentVOs();
247 
248         if (!statementVOIsDegroupAble(selectedStatementVOs, selectedReqComponentVOs)) return;
249 
250         // remove the selected RCs
251         for (ReqComponentVO selectedReqComponent : selectedReqComponentVOs) {
252             StatementVO parentStatementVO = null;
253             parentStatementVO = this.statementVO.getEnclosingStatementVO(this.statementVO, selectedReqComponent);
254             parentStatementVO.removeReqComponentVO(selectedReqComponent);
255         }
256 
257         // remove the selected operator cells/statements.
258         for (StatementVO selectedStatement : selectedStatementVOs) {
259             StatementVO parentStatementVO = null; 
260             parentStatementVO = this.statementVO.getParentStatementVO(this.statementVO, selectedStatement);
261             
262             if (selectedStatement == statementVO) {
263                 statementVO = null;
264             } else if (parentStatementVO != null) {
265                 parentStatementVO.removeStatementVO(selectedStatement);
266                 if (selectedStatement.getStatementVOCount() > 0) {
267                     for (StatementVO subStatement : selectedStatement.getStatementVOs()) {
268                         parentStatementVO.addStatementVO(subStatement);
269                     }
270                 } else if (selectedStatement.getReqComponentVOCount() > 0) {
271                     for (ReqComponentVO leafReqComponent : selectedStatement.getReqComponentVOs()) {
272                         parentStatementVO.addReqComponentVO(leafReqComponent);
273                     }
274                 }
275             }
276         }
277 
278         // clears off the root if the root no longer has any children after the deletions
279      //   if (statementVO.getChildCount() == 0) {
280      //       statementVO = null;
281      //   }
282     }
283 
284     public boolean isAddToGroupOK() {
285         List<StatementVO> selectedStatementVOs = getSelectedStatementVOs();
286         List<ReqComponentVO> selectedReqComponentVOs = getSelectedReqComponentVOs();
287         return isAddToGroupOK(selectedStatementVOs, selectedReqComponentVOs);
288     }
289 
290     private boolean isAddToGroupOK(List<StatementVO> selectedStatementVOs, List<ReqComponentVO> selectedReqComponentVOs) {
291         int numSelectedS = (selectedStatementVOs == null)? 0 : selectedStatementVOs.size();
292         int numSelectedRC = (selectedReqComponentVOs == null)? 0 : selectedReqComponentVOs.size();
293         // one or more rules are selected as well as a single AND or OR cell
294         return (numSelectedS == 1 && numSelectedRC > 0);
295     }
296     
297     public void addToGroup() {
298         List<StatementVO> selectedStatementVOs = getSelectedStatementVOs();
299         List<ReqComponentVO> selectedReqComponentVOs = getSelectedReqComponentVOs();
300         StatementVO selectedS = null;
301 
302         if (!isAddToGroupOK(selectedStatementVOs, selectedReqComponentVOs)) return;
303 
304         selectedS = selectedStatementVOs.get(0);
305         if (selectedReqComponentVOs != null && !selectedReqComponentVOs.isEmpty()) {
306             for (ReqComponentVO selectedRC : selectedReqComponentVOs) {
307                 StatementVO parentS = this.statementVO.getEnclosingStatementVO(this.statementVO, selectedRC);
308                 if (parentS == null) continue;
309 
310                 parentS.removeReqComponentVO(selectedRC);
311                 // The following if else statement cleans up parent statements that
312                 // has no more children other than the selectedS
313                 if (parentS.getChildCount() == 1 &&
314                         parentS.getSelectedStatementVOs() != null &&
315                         parentS.getSelectedStatementVOs().contains(selectedS)) {
316                     // if parent is root replace the current root with the selected statement.
317                     // otherwise remove the parent from grand parent and add the selected statement
318                     if (parentS == statementVO) {
319                         this.statementVO = selectedS;
320                     } else {
321                         StatementVO grandParentS = this.statementVO.getParentStatementVO(this.statementVO, parentS);
322                         grandParentS.removeStatementVO(parentS);
323                         grandParentS.addStatementVO(selectedS);
324                     }
325                 }
326                 selectedS.addReqComponentVO(selectedRC);
327             }
328             statementVO.simplify();
329         }
330     }
331     
332     public List<StatementVO> getSelectedStatementVOs() {
333         return (statementVO == null)? null : statementVO.getSelectedStatementVOs();
334     }
335     
336     public List<ReqComponentVO> getSelectedReqComponentVOs() {
337         return (statementVO == null)? null : statementVO.getSelectedReqComponentVOs();
338     }
339 
340     public StatementVO getStatementVO() {
341         return statementVO;
342     }
343 
344     public void setStatementVO(StatementVO statementVO) {
345         this.statementVO = statementVO;
346     }
347     
348     public String getExpression() {
349         return (statementVO == null)? null : statementVO.convertToExpression();
350     }
351 
352     public boolean isSimplifying() {
353         return simplifying;
354     }
355 
356     public void setSimplifying(boolean simplifying) {
357         this.simplifying = simplifying;
358     }
359 
360     public String getStatementTypeKey() {
361         String statementType = (statementVO == null || statementVO.getStatementInfo() == null)? null :
362             statementVO.getStatementInfo().getType();
363     	return statementType;
364     }
365 }