001package org.kuali.rice.krms.util;
002
003import org.kuali.rice.core.api.util.tree.Node;
004import org.kuali.rice.krms.api.repository.LogicalOperator;
005import org.kuali.rice.krms.api.repository.proposition.PropositionType;
006import org.kuali.rice.krms.api.repository.type.KrmsTypeDefinition;
007import org.kuali.rice.krms.dto.PropositionEditor;
008import org.kuali.rice.krms.dto.PropositionParameterEditor;
009import org.kuali.rice.krms.dto.RuleEditor;
010import org.kuali.rice.krms.impl.repository.KrmsRepositoryServiceLocator;
011import org.kuali.rice.krms.tree.node.RuleEditorTreeNode;
012import org.kuali.student.enrollment.class2.courseoffering.service.decorators.PermissionServiceConstants;
013
014import java.util.ArrayList;
015import java.util.Arrays;
016import 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 */
025public 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}