001 package org.kuali.rice.krms.util;
002
003 import org.kuali.rice.core.api.util.tree.Node;
004 import org.kuali.rice.krms.api.repository.LogicalOperator;
005 import org.kuali.rice.krms.api.repository.proposition.PropositionType;
006 import org.kuali.rice.krms.api.repository.type.KrmsTypeDefinition;
007 import org.kuali.rice.krms.dto.PropositionEditor;
008 import org.kuali.rice.krms.dto.PropositionParameterEditor;
009 import org.kuali.rice.krms.dto.RuleEditor;
010 import org.kuali.rice.krms.impl.repository.KrmsRepositoryServiceLocator;
011 import org.kuali.rice.krms.tree.node.RuleEditorTreeNode;
012 import org.kuali.student.enrollment.class2.courseoffering.service.decorators.PermissionServiceConstants;
013
014 import java.util.ArrayList;
015 import java.util.Arrays;
016 import java.util.List;
017
018 /**
019 * Created with IntelliJ IDEA.
020 * User: SW
021 * Date: 2012/12/03
022 * Time: 4:39 PM
023 * To change this template use File | Settings | File Templates.
024 */
025 public class PropositionTreeUtil {
026
027 public static void setTypeForCompoundOpCode(PropositionEditor proposition, String compoundOpCode) {
028 proposition.setCompoundOpCode(compoundOpCode);
029 if (LogicalOperator.AND.getCode().equalsIgnoreCase(compoundOpCode)) {
030 proposition.setType("kuali.krms.proposition.type.compound.and");
031 } else if (LogicalOperator.OR.getCode().equalsIgnoreCase(compoundOpCode)) {
032 proposition.setType("kuali.krms.proposition.type.compound.or");
033 }
034 try {
035 KrmsTypeDefinition type = KrmsRepositoryServiceLocator.getKrmsTypeRepositoryService().getTypeByName(PermissionServiceConstants.KS_SYS_NAMESPACE, proposition.getType());
036 proposition.setTypeId(type.getId());
037 } catch (Exception e) {
038 //ignore if service not available.
039 }
040
041 }
042
043 public static Node<RuleEditorTreeNode, String> findParentPropositionNode(Node<RuleEditorTreeNode, String> currentNode, String selectedPropKey) {
044 Node<RuleEditorTreeNode, String> bingo = null;
045 if (selectedPropKey != null) {
046 // if it's in children, we have the parent
047 List<Node<RuleEditorTreeNode, String>> children = currentNode.getChildren();
048 for (Node<RuleEditorTreeNode, String> child : children) {
049 RuleEditorTreeNode dataNode = child.getData();
050 if (selectedPropKey.equalsIgnoreCase(dataNode.getProposition().getKey())) {
051 return currentNode;
052 }
053 }
054
055 // if not found check grandchildren
056 for (Node<RuleEditorTreeNode, String> kid : children) {
057 bingo = findParentPropositionNode(kid, selectedPropKey);
058 if (bingo != null) {
059 break;
060 }
061 }
062 }
063 return bingo;
064 }
065
066 /**
067 * @return the {@link org.kuali.rice.krms.impl.repository.PropositionBo} from the form
068 */
069 public static PropositionEditor getProposition(RuleEditor ruleEditor) {
070
071 if (ruleEditor != null) {
072 String selectedPropKey = ruleEditor.getSelectedKey();
073 return findProposition(ruleEditor.getEditTree().getRootElement(), selectedPropKey);
074 }
075
076 return null;
077 }
078
079 public static PropositionEditor findProposition(Node<RuleEditorTreeNode, String> currentNode, String selectedPropKey) {
080
081 if (selectedPropKey == null) {
082 return null;
083 } else if (selectedPropKey.isEmpty()) {
084 return currentNode.getChildren().get(0).getData().getProposition();
085 }
086
087 // if it's in children, we have the parent
088 for (Node<RuleEditorTreeNode, String> child : currentNode.getChildren()) {
089 PropositionEditor proposition = child.getData().getProposition();
090 if (selectedPropKey.equalsIgnoreCase(proposition.getKey())) {
091 return proposition;
092 } else if ("S".equals(proposition.getPropositionTypeCode()) && proposition.isEditMode()) {
093 return proposition;
094 } else if (!proposition.isEditMode()) {
095 // if not found check grandchildren
096 proposition = findProposition(child, selectedPropKey);
097 if (proposition != null) {
098 return proposition;
099 }
100 }
101 }
102
103 return null;
104 }
105
106 /**
107 * Find and return the node containing the proposition that is in currently in edit mode
108 *
109 * @param node the node to start searching from (typically the root)
110 * @return the node that is currently being edited, if any. Otherwise, null.
111 */
112 public static Node<RuleEditorTreeNode, String> findEditedProposition(Node<RuleEditorTreeNode, String> node) {
113 Node<RuleEditorTreeNode, String> result = null;
114 if (node.getData() != null && node.getData().getProposition() != null && node.getData().getProposition()
115 .isEditMode()) {
116 result = node;
117 } else {
118 for (Node<RuleEditorTreeNode, String> child : node.getChildren()) {
119 result = findEditedProposition(child);
120 if (result != null) {
121 break;
122 }
123 }
124 }
125 return result;
126 }
127
128 public static void resetEditModeOnPropositionTree(RuleEditor ruleEditor) {
129 Node<RuleEditorTreeNode, String> root = ruleEditor.getEditTree().getRootElement();
130 resetEditModeOnPropositionTree(root);
131 }
132
133 /**
134 * disable edit mode for all Nodes beneath and including the passed in Node
135 *
136 * @param currentNode
137 */
138 public static void resetEditModeOnPropositionTree(Node<RuleEditorTreeNode, String> currentNode) {
139 if (currentNode.getData() != null) {
140 RuleEditorTreeNode dataNode = currentNode.getData();
141 dataNode.getProposition().setEditMode(false);
142 }
143 List<Node<RuleEditorTreeNode, String>> children = currentNode.getChildren();
144 for (Node<RuleEditorTreeNode, String> child : children) {
145 resetEditModeOnPropositionTree(child);
146 }
147 }
148
149 public static Node<RuleEditorTreeNode, String> findPropositionTreeNode(Node<RuleEditorTreeNode, String> currentNode, String selectedPropId) {
150 Node<RuleEditorTreeNode, String> bingo = null;
151 if (currentNode.getData() != null) {
152 RuleEditorTreeNode dataNode = currentNode.getData();
153 if (selectedPropId.equalsIgnoreCase(dataNode.getProposition().getId())) {
154 return currentNode;
155 }
156 }
157
158 for (Node<RuleEditorTreeNode, String> child : currentNode.getChildren()) {
159 bingo = findPropositionTreeNode(child, selectedPropId);
160 if (bingo != null) break;
161 }
162 return bingo;
163 }
164
165 public static String configureLogicExpression(PropositionEditor proposition) {
166 // Depending on the type of proposition (simple/compound), and the editMode,
167 // Create a treeNode of the appropriate type for the node and attach it to the
168 // sprout parameter passed in.
169 // If the prop is a compound proposition, calls itself for each of the compoundComponents
170 String logicExpression = proposition.getKey();
171 if (PropositionType.COMPOUND.getCode().equalsIgnoreCase(proposition.getPropositionTypeCode())) {
172 logicExpression += "(";
173 boolean first = true;
174 for (PropositionEditor child : proposition.getCompoundEditors()) {
175 // add an opcode node in between each of the children.
176 if (!first) {
177 if (LogicalOperator.AND.getCode().equalsIgnoreCase(proposition.getCompoundOpCode())) {
178 logicExpression += " AND ";
179 } else if (LogicalOperator.OR.getCode().equalsIgnoreCase(proposition.getCompoundOpCode())) {
180 logicExpression += " OR ";
181 }
182 }
183 first = false;
184 // call to build the childs node
185 logicExpression += configureLogicExpression(child);
186 }
187 logicExpression += ")";
188 }
189 return logicExpression;
190 }
191
192 /**
193 * This method creates a partially populated Simple PropositionBo with
194 * three parameters: a term type paramter (value not assigned)
195 * a operation parameter
196 * a constant parameter (value set to empty string)
197 * The returned PropositionBo has an generatedId. The type code and ruleId properties are assigned the
198 * same value as the sibling param passed in.
199 * Each PropositionParameter has the id generated, and type, sequenceNumber,
200 * propId default values set. The value is set to "".
201 *
202 * @param sibling -
203 * @return a PropositionBo partially populated.
204 */
205 public static PropositionEditor createSimplePropositionBoStub(PropositionEditor sibling, Class<? extends PropositionEditor> propClass) throws IllegalAccessException, InstantiationException {
206 // create a simple proposition Bo
207 PropositionEditor prop = propClass.newInstance();
208 prop.setPropositionTypeCode(PropositionType.SIMPLE.getCode());
209 prop.setNewProp(true);
210 prop.setEditMode(true);
211 if (sibling != null) {
212 prop.setRuleId(sibling.getRuleId());
213 }
214
215 prop.setParameters(createParameterList());
216
217 return prop;
218 }
219
220 public static List<PropositionParameterEditor> createParameterList() {
221 // create blank proposition parameters
222 PropositionParameterEditor pTerm = new PropositionParameterEditor("T", new Integer("0"));
223 PropositionParameterEditor pOp = new PropositionParameterEditor("O", new Integer("2"));
224 PropositionParameterEditor pConst = new PropositionParameterEditor("C", new Integer("1"));
225
226 return Arrays.asList(pTerm, pConst, pOp);
227 }
228
229 public static PropositionEditor createCompoundPropositionBoStub(PropositionEditor existing, boolean addNewChild, Class<? extends PropositionEditor> propClass) throws InstantiationException, IllegalAccessException {
230 // create a simple proposition Bo
231 PropositionEditor prop = createCompoundPropositionBoStub(existing, propClass);
232
233 if (addNewChild) {
234 PropositionEditor newProp = createSimplePropositionBoStub(existing, propClass);
235 prop.getCompoundEditors().add(newProp);
236 prop.setEditMode(false); // set the parent edit mode back to null or we end up with 2 props in edit mode
237 }
238
239 return prop;
240 }
241
242 public static PropositionEditor createCompoundPropositionBoStub(PropositionEditor existing, Class<? extends PropositionEditor> propClass) throws IllegalAccessException, InstantiationException {
243 // create a simple proposition Bo
244 PropositionEditor prop = propClass.newInstance();
245 prop.setNewProp(true);
246 prop.setPropositionTypeCode(PropositionType.COMPOUND.getCode());
247 prop.setRuleId(existing.getRuleId());
248 prop.setCompoundOpCode(LogicalOperator.AND.getCode()); // default to and
249 prop.setDescription("");
250 prop.setEditMode(true);
251
252 List<PropositionEditor> components = new ArrayList<PropositionEditor>();
253 components.add(existing);
254 prop.setCompoundEditors(components);
255 return prop;
256 }
257
258 public static void cancelNewProp(PropositionEditor proposition) {
259 int i = 0;
260 if (proposition.getCompoundEditors() != null) {
261 while (i < proposition.getCompoundEditors().size()) {
262 PropositionEditor child = proposition.getCompoundEditors().get(i);
263 if (child.isNewProp()) {
264 proposition.getCompoundEditors().remove(child);
265 continue;
266 } else {
267 cancelNewProp(child);
268 }
269 i++;
270 }
271 }
272 }
273
274 public static void resetNewProp(PropositionEditor proposition) {
275 if (proposition.getCompoundEditors() != null) {
276 for (PropositionEditor child : proposition.getCompoundEditors()) {
277 child.setNewProp(false);
278 resetNewProp(child);
279 }
280 }
281 }
282 }