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    }