001/**
002 * Copyright 2005-2013 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.krms.controller;
017
018import org.apache.commons.lang.StringUtils;
019import org.kuali.rice.core.api.util.tree.Node;
020import org.kuali.rice.krad.uif.UifParameters;
021import org.kuali.rice.krad.util.GlobalVariables;
022import org.kuali.rice.krad.util.KRADConstants;
023import org.kuali.rice.krad.web.controller.MaintenanceDocumentController;
024import org.kuali.rice.krad.web.form.MaintenanceDocumentForm;
025import org.kuali.rice.krad.web.form.UifFormBase;
026import org.kuali.rice.krms.api.repository.proposition.PropositionType;
027import org.kuali.rice.krms.api.repository.type.KrmsTypeDefinition;
028import org.kuali.rice.krms.dto.AgendaEditor;
029import org.kuali.rice.krms.dto.PropositionEditor;
030import org.kuali.rice.krms.dto.RuleEditor;
031import org.kuali.rice.krms.dto.RuleManagementWrapper;
032import org.kuali.rice.krms.impl.repository.KrmsRepositoryServiceLocator;
033import org.kuali.rice.krms.service.RuleViewHelperService;
034import org.kuali.rice.krms.util.AgendaUtilities;
035import org.kuali.rice.krms.tree.node.SimplePropositionEditNode;
036import org.kuali.rice.krms.tree.node.SimplePropositionNode;
037import org.kuali.rice.krms.tree.node.RuleEditorTreeNode;
038import org.kuali.rice.krms.util.KRMSConstants;
039import org.kuali.rice.krms.util.PropositionTreeUtil;
040import org.kuali.rice.krms.util.RuleLogicExpressionParser;
041import org.kuali.student.common.uif.util.KSControllerHelper;
042import org.springframework.validation.BindingResult;
043import org.springframework.web.bind.annotation.ModelAttribute;
044import org.springframework.web.bind.annotation.RequestMapping;
045import org.springframework.web.servlet.ModelAndView;
046
047import javax.servlet.http.HttpServletRequest;
048import javax.servlet.http.HttpServletResponse;
049import java.util.ArrayList;
050import java.util.List;
051import java.util.Map;
052
053/**
054 * Controller for the KS KRMS page.
055 *
056 * @author Kuali Student Team
057 */
058public class RuleEditorController extends MaintenanceDocumentController {
059
060    /**
061     * Method used to invoke the CO inquiry view from Manage Course Offering screen while search input is Course Offering
062     * Code (04a screen)
063     *
064     * @param form
065     * @param result
066     * @param request
067     * @param response
068     * @return
069     * @throws Exception
070     */
071    @RequestMapping(params = "methodToCall=goToRuleView")
072    public ModelAndView goToRuleView(@ModelAttribute("KualiForm") UifFormBase form, @SuppressWarnings("unused") BindingResult result,
073                                     @SuppressWarnings("unused") HttpServletRequest request, @SuppressWarnings("unused") HttpServletResponse response) throws Exception {
074
075        //Clear the client state on new edit rule.
076        form.getClientStateForSyncing().clear();
077
078        RuleEditor ruleEditor = AgendaUtilities.retrieveSelectedRuleEditor((MaintenanceDocumentForm) form);
079        this.getViewHelper(form).refreshInitTrees(ruleEditor);
080
081        if (!form.getActionParameters().containsKey(UifParameters.NAVIGATE_TO_PAGE_ID)) {
082            form.getActionParameters().put(UifParameters.NAVIGATE_TO_PAGE_ID, KRMSConstants.KRMS_RULE_MAINTENANCE_PAGE_ID);
083        }
084        return super.navigate(form, result, request, response);
085    }
086
087    /**
088     * Deletes selected rule from agenda on Manage Course Requistes page
089     *
090     * @param form
091     * @param result
092     * @param request
093     * @param response
094     * @return
095     * @throws Exception
096     */
097    @RequestMapping(params = "methodToCall=deleteRule")
098    public ModelAndView deleteRule(@ModelAttribute("KualiForm") UifFormBase form, @SuppressWarnings("unused") BindingResult result,
099                                   @SuppressWarnings("unused") HttpServletRequest request, @SuppressWarnings("unused") HttpServletResponse response) throws Exception {
100
101        MaintenanceDocumentForm document = (MaintenanceDocumentForm) form;
102        RuleManagementWrapper ruleWrapper = AgendaUtilities.getRuleWrapper(document);
103        String ruleKey = AgendaUtilities.getRuleKey(document);
104
105        AgendaEditor agenda = AgendaUtilities.getSelectedAgendaEditor(ruleWrapper, ruleKey);
106        if (agenda != null) {
107            RuleEditor ruleEditor = agenda.getRuleEditors().get(ruleKey);
108
109            //Only add rules to delete list that are already persisted.
110            if (ruleEditor.getId() != null) {
111                agenda.getDeletedRules().add(ruleEditor);
112            }
113
114            RuleEditor dummyRule = new RuleEditor(ruleEditor.getKey(), true, ruleEditor.getRuleTypeInfo());
115            dummyRule.setParent(ruleEditor.getParent());
116            agenda.getRuleEditors().put(ruleEditor.getKey(), dummyRule);
117        }
118
119        return getUIFModelAndView(document);
120    }
121
122    /**
123     * Navigates to rule maintenance page with rule type to initialize adding of new rule.
124     *
125     * @param form
126     * @param result
127     * @param request
128     * @param response
129     * @return
130     * @throws Exception
131     */
132    @RequestMapping(params = "methodToCall=addRule")
133    public ModelAndView addRule(@ModelAttribute("KualiForm") UifFormBase form, @SuppressWarnings("unused") BindingResult result,
134                                @SuppressWarnings("unused") HttpServletRequest request, @SuppressWarnings("unused") HttpServletResponse response) throws Exception {
135
136        //Clear the client state on new edit rule.
137        form.getClientStateForSyncing().clear();
138
139        RuleEditor ruleEditor = AgendaUtilities.retrieveSelectedRuleEditor((MaintenanceDocumentForm) form);
140
141        this.getViewHelper(form).refreshInitTrees(ruleEditor);
142
143        if (!form.getActionParameters().containsKey(UifParameters.NAVIGATE_TO_PAGE_ID)) {
144            form.getActionParameters().put(UifParameters.NAVIGATE_TO_PAGE_ID, KRMSConstants.KRMS_RULE_MAINTENANCE_PAGE_ID);
145        }
146        return super.navigate(form, result, request, response);
147    }
148
149    /**
150     * Call the super method to avoid the agenda tree being reloaded from the db.
151     *
152     * @param form
153     * @param result
154     * @param request
155     * @param response
156     * @return
157     * @throws Exception
158     */
159    @RequestMapping(params = "methodToCall=ajaxRefresh")
160    public ModelAndView ajaxRefresh(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
161                                    HttpServletRequest request, HttpServletResponse response)
162            throws Exception {
163        return getUIFModelAndView(form);
164    }
165
166    /**
167     * Retrieves selected rule editor from data object.
168     *
169     * @param form
170     * @return the current rule editor
171     */
172    protected RuleEditor getRuleEditor(UifFormBase form) {
173        if (form instanceof MaintenanceDocumentForm) {
174            MaintenanceDocumentForm maintenanceDocumentForm = (MaintenanceDocumentForm) form;
175            Object dataObject = maintenanceDocumentForm.getDocument().getNewMaintainableObject().getDataObject();
176
177            if (dataObject instanceof RuleEditor) {
178                return (RuleEditor) dataObject;
179            } else if (dataObject instanceof RuleManagementWrapper) {
180                RuleManagementWrapper wrapper = (RuleManagementWrapper) dataObject;
181                return wrapper.getRuleEditor();
182            }
183        }
184
185        return null;
186    }
187
188    //
189    // Rule Editor Controller methods
190    //
191
192    /**
193     * Method to copy rule.
194     *
195     * @param form
196     * @param result
197     * @param request
198     * @param response
199     * @return
200     * @throws Exception
201     */
202    @RequestMapping(params = "methodToCall=copyRule")
203    public ModelAndView copyRule(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
204                                 HttpServletRequest request, HttpServletResponse response) throws Exception {
205        return super.refresh(form, result, request, response);
206    }
207
208    /**
209     * This method starts an edit on proposition.
210     *
211     * @param form
212     * @param result
213     * @param request
214     * @param response
215     * @return
216     * @throws Exception
217     */
218    @RequestMapping(params = "methodToCall=goToEditProposition")
219    public ModelAndView goToEditProposition(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
220                                            HttpServletRequest request, HttpServletResponse response) throws Exception {
221
222        RuleViewHelperService viewHelper = this.getViewHelper(form);
223        RuleEditor ruleEditor = getRuleEditor(form);
224
225        PropositionTreeUtil.resetEditModeOnPropositionTree(ruleEditor.getPropositionEditor());
226        PropositionEditor proposition = PropositionTreeUtil.getProposition(ruleEditor);
227        proposition.setEditMode(true);
228
229        if (!PropositionType.COMPOUND.getCode().equalsIgnoreCase(proposition.getPropositionTypeCode())) {
230
231            String propositionTypeId = proposition.getTypeId();
232            if (propositionTypeId == null) {
233                proposition.setType(null);
234            } else {
235
236                KrmsTypeDefinition type = KrmsRepositoryServiceLocator.getKrmsTypeRepositoryService().getTypeById(propositionTypeId);
237                if (type != null) {
238                    proposition.setType(type.getName());
239                }
240            }
241
242        }
243
244        //refresh the tree
245        viewHelper.refreshInitTrees(ruleEditor);
246
247        return getUIFModelAndView(form);
248    }
249
250    /**
251     * Method to initialize the adding of proposition to rule.
252     *
253     * @param form
254     * @param result
255     * @param request
256     * @param response
257     * @return
258     * @throws Exception
259     */
260    @RequestMapping(params = "methodToCall=addProposition")
261    public ModelAndView addProposition(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
262                                       HttpServletRequest request, HttpServletResponse response) throws Exception {
263
264        RuleEditor ruleEditor = getRuleEditor(form);
265        String selectedPropKey = ruleEditor.getSelectedKey();
266
267        // find parent
268        Node<RuleEditorTreeNode, String> root = ruleEditor.getEditTree().getRootElement();
269        Node<RuleEditorTreeNode, String> parent = PropositionTreeUtil.findParentPropositionNode(root, selectedPropKey);
270
271        //PropositionTreeUtil.resetEditModeOnPropositionTree(ruleEditor);
272        RuleViewHelperService viewHelper = this.getViewHelper(form);
273
274        //Special case when only one proposition in tree or no proposition selected
275        if (selectedPropKey.isEmpty() && parent == null && root.getChildren().size() > 0) {
276            //Special case when now proposition selected and more than one proposition in tree
277            if (root.getChildren().get(root.getChildren().size() - 1).getNodeType().contains("compoundNode")) {
278                parent = root.getChildren().get(root.getChildren().size() - 1);
279                selectedPropKey = parent.getChildren().get(parent.getChildren().size() - 1).getData().getProposition().getKey();
280            } //Special case when one proposition in tree and no proposition selected
281            else {
282                parent = root;
283                selectedPropKey = root.getChildren().get(root.getChildren().size() - 1).getData().getProposition().getKey();
284            }
285        } //If root compound proposition selected
286        else if (parent != null) {
287            if (parent.getNodeType().equals("treeRoot") && !parent.getChildren().get(parent.getChildren().size() - 1).getNodeType().contains("simple")) {
288                parent = root.getChildren().get(root.getChildren().size() - 1);
289                selectedPropKey = parent.getChildren().get(parent.getChildren().size() - 1).getData().getProposition().getKey();
290            }
291        }
292
293        // add new child at appropriate spot
294        if (parent != null) {
295            List<Node<RuleEditorTreeNode, String>> children = parent.getChildren();
296            for (int index = 0; index < children.size(); index++) {
297                Node<RuleEditorTreeNode, String> child = children.get(index);
298
299                // if our selected node is a simple proposition, add a new one after
300                if (propKeyMatches(child, selectedPropKey)) {
301                    // handle special case of adding to a lone simple proposition.
302                    // in this case, we need to change the root level proposition to a compound proposition
303                    // move the existing simple proposition as the first compound component,
304                    // then add a new blank simple prop as the second compound component.
305                    PropositionEditor blank = null;
306                    if (parent.equals(root) && (isSimpleNode(child.getNodeType()))) {
307
308                        // create a new compound proposition
309                        blank = viewHelper.createCompoundPropositionBoStub(child.getData().getProposition(), true);
310                        // don't set compound.setEditMode(true) as the Simple Prop in the compound prop is the only prop in edit mode
311                        ruleEditor.setProposition(blank);
312                    }
313                    // handle regular case of adding a simple prop to an existing compound prop
314                    else if (!parent.equals(root)) {
315
316                        // build new Blank Proposition
317                        blank = viewHelper.createSimplePropositionBoStub(child.getData().getProposition());
318                        //add it to the parent
319                        PropositionEditor parentProp = parent.getData().getProposition();
320                        parentProp.getCompoundEditors().add(((index / 2) + 1), blank);
321                    } else {
322                        return getUIFModelAndView(form);
323                    }
324                    this.getViewHelper(form).refreshInitTrees(ruleEditor);
325                    if (blank != null) {
326                        ruleEditor.setSelectedKey(blank.getKey());
327                    } else {
328                        ruleEditor.setSelectedKey(null);
329                    }
330                    break;
331                }
332            }
333        } else {
334            // special case, if root has no children, add a new simple proposition
335            // todo: how to add compound proposition. - just add another to the firs simple
336            if (root.getChildren().isEmpty()) {
337                PropositionEditor blank = viewHelper.createSimplePropositionBoStub(null);
338                blank.setRuleId(ruleEditor.getId());
339                ruleEditor.setPropId(blank.getId());
340                ruleEditor.setProposition(blank);
341            }
342            this.getViewHelper(form).refreshInitTrees(ruleEditor);
343        }
344        return getUIFModelAndView(form);
345    }
346
347    /**
348     * Returns <code>true</code> if proposition key matches tree node key
349     *
350     * @param node
351     * @param propKey
352     * @return if proposition key matches tree node key; <code>false</code> otherwise
353     */
354    private boolean propKeyMatches(Node<RuleEditorTreeNode, String> node, String propKey) {
355        if (propKey != null && node != null && node.getData() != null && propKey.equalsIgnoreCase(node.getData().getProposition().getKey())) {
356            return true;
357        }
358        return false;
359    }
360
361    /**
362     * This method return the index of the position of the child that matches the id
363     *
364     * @param parent
365     * @param propKey
366     * @return index if found, -1 if not found
367     */
368    private int findChildIndex(Node<RuleEditorTreeNode, String> parent, String propKey) {
369        int index;
370        List<Node<RuleEditorTreeNode, String>> children = parent.getChildren();
371        for (index = 0; index < children.size(); index++) {
372            Node<RuleEditorTreeNode, String> child = children.get(index);
373            // if our selected node is a simple proposition, add a new one after
374            if (propKeyMatches(child, propKey)) {
375                return index;
376            }
377        }
378        return -1;
379    }
380
381    /**
382     * Moves proposition up in tree structure.
383     *
384     * @param form
385     * @param result
386     * @param request
387     * @param response
388     * @return
389     * @throws Exception
390     */
391    @RequestMapping(params = "methodToCall=movePropositionUp")
392    public ModelAndView movePropositionUp(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
393                                          HttpServletRequest request, HttpServletResponse response)
394            throws Exception {
395        moveSelectedProposition(form, true);
396
397        return getUIFModelAndView(form);
398    }
399
400    /**
401     * Moves proposition down in tree structure.
402     *
403     * @param form
404     * @param result
405     * @param request
406     * @param response
407     * @return
408     * @throws Exception
409     */
410    @RequestMapping(params = "methodToCall=movePropositionDown")
411    public ModelAndView movePropositionDown(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
412                                            HttpServletRequest request, HttpServletResponse response)
413            throws Exception {
414        moveSelectedProposition(form, false);
415
416        return getUIFModelAndView(form);
417    }
418
419    /**
420     * Moves proposition up or down.
421     * <p/>
422     * Rough algorithm for moving a node up.
423     * <p/>
424     * find the following:
425     * node := the selected node
426     * parent := the selected node's parent, its containing node (via when true or when false relationship)
427     * parentsOlderCousin := the parent's level-order predecessor (sibling or cousin)
428     *
429     * @param form
430     * @param up   whether the desired move is in an up direction
431     * @throws Exception
432     */
433    private void moveSelectedProposition(UifFormBase form, boolean up) throws Exception {
434
435        RuleEditor ruleEditor = getRuleEditor(form);
436        String selectedPropKey = ruleEditor.getSelectedKey();
437
438        // find parent
439        Node<RuleEditorTreeNode, String> parent = PropositionTreeUtil.findParentPropositionNode(ruleEditor.getEditTree().getRootElement(), selectedPropKey);
440
441        // add new child at appropriate spot
442        if (parent != null) {
443            List<Node<RuleEditorTreeNode, String>> children = parent.getChildren();
444            for (int index = 0; index < children.size(); index++) {
445                Node<RuleEditorTreeNode, String> child = children.get(index);
446                // if our selected node is a simple proposition, add a new one after
447                if (propKeyMatches(child, selectedPropKey) &&
448                        (isSimpleNode(child.getNodeType()) ||
449                                (RuleEditorTreeNode.COMPOUND_NODE_TYPE.equalsIgnoreCase(child.getNodeType())) ||
450                                (child.getNodeType().contains(RuleEditorTreeNode.FIRST_IN_GROUP)) ||
451                                (child.getNodeType().contains(RuleEditorTreeNode.LAST_IN_GROUP)))) {
452
453                    //remove it from its current spot
454                    PropositionEditor parentProp = parent.getData().getProposition();
455                    PropositionEditor workingProp = null;
456                    if (index != 0 && up) {
457                        workingProp = parentProp.getCompoundEditors().remove(index / 2);
458                    } else if (!up && index != (children.size() - 1)) {
459                        workingProp = parentProp.getCompoundEditors().remove(index / 2);
460                    }
461                    if ((index > 0) && up) {
462                        parentProp.getCompoundEditors().add((index / 2) - 1, workingProp);
463                    } else if ((index < (children.size() - 1) && !up)) {
464                        parentProp.getCompoundEditors().add((index / 2) + 1, workingProp);
465                    }
466                    // redisplay the tree (editMode = true)
467                    this.getViewHelper(form).refreshInitTrees(ruleEditor);
468                    break;
469                }
470            }
471        }
472        //Compare rule with parent rule.
473        compareRulePropositions((MaintenanceDocumentForm) form, ruleEditor);
474
475    }
476
477    /**
478     * Returns <code>true</code> if node is of type simple
479     *
480     * @param nodeType
481     * @return if node is of type simple; <code>false</code> otherwise
482     */
483    public boolean isSimpleNode(String nodeType) {
484        if (nodeType.contains(SimplePropositionNode.NODE_TYPE) ||
485                SimplePropositionEditNode.NODE_TYPE.equalsIgnoreCase(nodeType)) {
486            return true;
487        }
488        return false;
489    }
490
491    /**
492     * Moves proposition left in tree structure.
493     * <p/>
494     * Rough algorithm for moving a node up.
495     * <p/>
496     * find the following:
497     * node := the selected node
498     * parent := the selected node's parent, its containing node (via when true or when false relationship)
499     * parentsOlderCousin := the parent's level-order predecessor (sibling or cousin)
500     *
501     * @param form
502     * @param result
503     * @param request
504     * @param response
505     * @return
506     * @throws Exception
507     */
508    @RequestMapping(params = "methodToCall=movePropositionLeft")
509    public ModelAndView movePropositionLeft(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
510                                            HttpServletRequest request, HttpServletResponse response)
511            throws Exception {
512
513        RuleEditor ruleEditor = getRuleEditor(form);
514        String selectedpropKey = ruleEditor.getSelectedKey();
515
516        // find agendaEditor.getAgendaItemLine().getRule().getPropositionTree().getRootElement()parent
517        Node<RuleEditorTreeNode, String> root = ruleEditor.getEditTree().getRootElement();
518        Node<RuleEditorTreeNode, String> parent = PropositionTreeUtil.findParentPropositionNode(root, selectedpropKey);
519        if ((parent != null) && (!parent.getNodeType().contains(RuleEditorTreeNode.ROOT_TYPE))) {
520            Node<RuleEditorTreeNode, String> granny = PropositionTreeUtil.findParentPropositionNode(root, parent.getData().getProposition().getKey());
521            if (!granny.equals(root)) {
522                int oldIndex = findChildIndex(parent, selectedpropKey);
523                int newIndex = findChildIndex(granny, parent.getData().getProposition().getKey());
524                if (oldIndex >= 0 && newIndex >= 0) {
525                    PropositionEditor prop = parent.getData().getProposition().getCompoundEditors().remove(oldIndex / 2);
526                    if ((parent.getChildren().size() == 1) || (parent.getChildren().size() == 3)) {
527                        PropositionTreeUtil.removeCompoundProp(ruleEditor.getPropositionEditor());
528                    }
529                    if (granny.getData().getProposition().getCompoundEditors().isEmpty()) {
530                        granny.getData().getProposition().getCompoundEditors().add(newIndex, prop);
531                    } else {
532                        granny.getData().getProposition().getCompoundEditors().add((newIndex / 2) + 1, prop);
533                    }
534                    this.getViewHelper(form).refreshInitTrees(ruleEditor);
535                }
536            }
537
538        }
539        //Compare rule with parent rule.
540        compareRulePropositions((MaintenanceDocumentForm) form, ruleEditor);
541        return getUIFModelAndView(form);
542    }
543
544    /**
545     * Move proposition right in tree structure.
546     * <p/>
547     * Rough algorithm for moving a node Right
548     * if the selected node is above a compound proposition, move it into the compound proposition as the first child
549     * if the node is above a simple proposition, do nothing.
550     * find the following:
551     * node := the selected node
552     * parent := the selected node's parent, its containing node
553     * nextSibling := the node after the selected node
554     *
555     * @param form
556     * @param result
557     * @param request
558     * @param response
559     * @return
560     * @throws Exception
561     */
562    @RequestMapping(params = "methodToCall=movePropositionRight")
563    public ModelAndView movePropositionRight(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
564                                             HttpServletRequest request, HttpServletResponse response)
565            throws Exception {
566
567        RuleEditor ruleEditor = getRuleEditor(form);
568        String selectedpropKey = ruleEditor.getSelectedKey();
569
570        // find parent
571        Node<RuleEditorTreeNode, String> parent = PropositionTreeUtil.findParentPropositionNode(
572                ruleEditor.getEditTree().getRootElement(), selectedpropKey);
573        if (parent != null) {
574            int index = findChildIndex(parent, selectedpropKey);
575            // if we are the last child, do nothing, otherwise
576            if (index >= 0 && index + 1 < parent.getChildren().size()) {
577                Node<RuleEditorTreeNode, String> nextSibling = parent.getChildren().get(index + 2);
578                // if selected node above a compound node, move it into it as first child
579                if (nextSibling.getNodeType().contains(RuleEditorTreeNode.COMPOUND_NODE_TYPE)) {
580                    // remove selected node from it's current spot
581                    PropositionEditor prop = parent.getData().getProposition().getCompoundEditors().remove(index / 2);
582                    // add it to it's siblings children
583                    nextSibling.getData().getProposition().getCompoundEditors().add(0, prop);
584                }
585                //Remove single parents and refresh the tree.
586                PropositionTreeUtil.removeCompoundProp(parent.getData().getProposition());
587                this.getViewHelper(form).refreshInitTrees(ruleEditor);
588            }
589        }
590        //Compare rule with parent rule.
591        compareRulePropositions((MaintenanceDocumentForm) form, ruleEditor);
592        return getUIFModelAndView(form);
593    }
594
595    /**
596     * Introduces a new compound proposition between the selected proposition and its parent.
597     * Additionally, it puts a new blank simple proposition underneath the compound proposition
598     * as a sibling to the selected proposition.
599     *
600     * @param form
601     * @param result
602     * @param request
603     * @param response
604     * @return
605     * @throws Exception
606     */
607    @RequestMapping(params = "methodToCall=togglePropositionSimpleCompound")
608    public ModelAndView togglePropositionSimpleCompound(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
609                                                        HttpServletRequest request, HttpServletResponse response)
610            throws Exception {
611
612        RuleEditor ruleEditor = getRuleEditor(form);
613        String selectedPropKey = ruleEditor.getSelectedKey();
614
615        PropositionTreeUtil.resetEditModeOnPropositionTree(ruleEditor.getPropositionEditor());
616        RuleViewHelperService viewHelper = this.getViewHelper(form);
617
618        if (!StringUtils.isBlank(selectedPropKey)) {
619            // find parent
620            Node<RuleEditorTreeNode, String> parent = PropositionTreeUtil.findParentPropositionNode(
621                    ruleEditor.getEditTree().getRootElement(), selectedPropKey);
622            if (parent != null) {
623
624                int index = findChildIndex(parent, selectedPropKey);
625                PropositionEditor propBo = parent.getChildren().get(index).getData().getProposition();
626
627                // create a new compound proposition
628                PropositionEditor compound = viewHelper.createCompoundPropositionBoStub(propBo, true);
629
630                if (parent.getData() == null) { // SPECIAL CASE: this is the only proposition in the tree
631                    ruleEditor.setProposition(compound);
632                } else {
633                    PropositionEditor parentBo = parent.getData().getProposition();
634                    List<PropositionEditor> siblings = parentBo.getCompoundEditors();
635
636                    int propIndex = -1;
637                    for (int i = 0; i < siblings.size(); i++) {
638                        if (propBo.getKey().equals(siblings.get(i).getKey())) {
639                            propIndex = i;
640                            break;
641                        }
642                    }
643
644                    parentBo.getCompoundEditors().set(propIndex, compound);
645                    compound.getCompoundEditors().get(1).setEditMode(true);
646                }
647
648                viewHelper.refreshInitTrees(ruleEditor);
649                ruleEditor.setSelectedKey(compound.getCompoundEditors().get(1).getKey());
650
651            }
652        }
653
654        return getUIFModelAndView(form);
655    }
656
657    /**
658     * Paste proposition in selected position in tree structure.
659     *
660     * @param form
661     * @param result
662     * @param request
663     * @param response
664     * @return
665     * @throws Exception
666     */
667    @RequestMapping(params = "methodToCall=pasteProposition")
668    public ModelAndView pasteProposition(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
669                                         HttpServletRequest request, HttpServletResponse response)
670            throws Exception {
671
672        boolean cutAction = true;
673        RuleEditor ruleEditor = getRuleEditor(form);
674        RuleViewHelperService viewHelper = this.getViewHelper(form);
675
676        // get selected id
677        String selectedPropKey = ruleEditor.getSelectedKey();
678        if (StringUtils.isBlank(selectedPropKey)) {
679            return getUIFModelAndView(form);
680        }
681
682        // get the id to move
683        String movePropKey = ruleEditor.getCutKey();
684        if (StringUtils.isBlank(movePropKey)) {
685            movePropKey = ruleEditor.getCopyKey();
686            cutAction = false;
687        }
688
689        // check if selected and move is not the same
690        if (StringUtils.isNotBlank(movePropKey)) {
691
692            PropositionEditor newParent = null;
693            PropositionEditor workingProp = null;
694            PropositionEditor root = ruleEditor.getPropositionEditor();
695
696            // Special case when the user copy the the only proposition in tree.
697            if (movePropKey.equals(root.getKey())) {
698                newParent = viewHelper.createCompoundPropositionBoStub(root, false);
699                workingProp = viewHelper.copyProposition(root);
700            } else {
701                Node<RuleEditorTreeNode, String> rootNode = ruleEditor.getEditTree().getRootElement();
702                if (selectedPropKey.equals(root.getKey())) {
703                    newParent = root;
704                } else {
705                    newParent = PropositionTreeUtil.findParentPropositionNode(rootNode, selectedPropKey).getData().getProposition();
706                }
707                PropositionEditor oldParent = PropositionTreeUtil.findParentPropositionNode(rootNode, movePropKey).getData().getProposition();
708
709                // cut or copy from old
710                if (oldParent != null) {
711                    List<PropositionEditor> children = oldParent.getCompoundEditors();
712                    for (int index = 0; index < children.size(); index++) {
713                        if (movePropKey.equalsIgnoreCase(children.get(index).getKey())) {
714                            if (cutAction) {
715                                workingProp = oldParent.getCompoundEditors().remove(index);
716                            } else {
717                                workingProp = viewHelper.copyProposition(oldParent.getCompoundEditors().get(index));
718                            }
719                            break;
720                        }
721                    }
722                }
723            }
724
725            // add to new
726            addProposition(selectedPropKey, newParent, workingProp);
727            if (movePropKey.equals(root.getKey())) {
728                ruleEditor.setProposition(newParent);
729            }
730
731            //Refresh the tree.
732            PropositionTreeUtil.removeCompoundProp(ruleEditor);
733            ruleEditor.setSelectedKey(StringUtils.EMPTY);
734            viewHelper.refreshInitTrees(ruleEditor);
735        }
736
737        //Compare rule with parent rule.
738        compareRulePropositions((MaintenanceDocumentForm) form, ruleEditor);
739
740        // call the super method to avoid the agenda tree being reloaded from the db
741        return getUIFModelAndView(form);
742    }
743
744    /**
745     * Adds proposition at selected position.
746     *
747     * @param selectedpropKey
748     * @param newParent
749     * @param workingProp
750     */
751    private void addProposition(String selectedpropKey, PropositionEditor newParent, PropositionEditor workingProp) {
752        // add to new
753        if (newParent != null && workingProp != null) {
754            //Selected is parent, add to list.
755            if(selectedpropKey.equalsIgnoreCase(newParent.getKey())){
756                newParent.getCompoundEditors().add(workingProp);
757                return;
758            }
759
760            //Add after selected prop.
761            List<PropositionEditor> children = newParent.getCompoundEditors();
762            for (int index = 0; index < children.size(); index++) {
763                if (selectedpropKey.equalsIgnoreCase(children.get(index).getKey())) {
764                    children.add(index + 1, workingProp);
765                    return;
766                }
767            }
768        }
769    }
770
771    /**
772     * Removes proposition.
773     *
774     * @param form
775     * @param result
776     * @param request
777     * @param response
778     * @return
779     * @throws Exception
780     */
781    @RequestMapping(params = "methodToCall=deleteProposition")
782    public ModelAndView deleteProposition(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
783                                          HttpServletRequest request, HttpServletResponse response)
784            throws Exception {
785        RuleEditor ruleEditor = getRuleEditor(form);
786        String selectedpropKey = ruleEditor.getSelectedKey();
787        Node<RuleEditorTreeNode, String> root = ruleEditor.getEditTree().getRootElement();
788
789        Node<RuleEditorTreeNode, String> parentNode = PropositionTreeUtil.findParentPropositionNode(root, selectedpropKey);
790
791        // what if it is the root?
792        if (parentNode != null && parentNode.getData() != null) { // it is not the root as there is a parent w/ a prop
793            PropositionEditor parent = parentNode.getData().getProposition();
794            if (parent != null) {
795                List<PropositionEditor> children = parent.getCompoundEditors();
796                for (int index = 0; index < children.size(); index++) {
797                    if (selectedpropKey.equalsIgnoreCase(children.get(index).getKey())) {
798                        parent.getCompoundComponents().remove(index);
799                        break;
800                    }
801                }
802            }
803            PropositionTreeUtil.removeCompoundProp(ruleEditor);
804            ruleEditor.setSelectedKey(StringUtils.EMPTY);
805        } else { // no parent, it is the root
806            ruleEditor.reset();
807        }
808
809        //Compare rule with parent rule.
810        compareRulePropositions((MaintenanceDocumentForm) form, ruleEditor);
811
812        this.getViewHelper(form).refreshInitTrees(ruleEditor);
813        return getUIFModelAndView(form);
814    }
815
816    /**
817     * Updates compound operator in tree structure.
818     *
819     * @param form
820     * @param result
821     * @param request
822     * @param response
823     * @return
824     * @throws Exception
825     */
826    @RequestMapping(params = "methodToCall=updateCompoundOperator")
827    public ModelAndView updateCompoundOperator(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
828                                               HttpServletRequest request, HttpServletResponse response)
829            throws Exception {
830
831        RuleEditor ruleEditor = getRuleEditor(form);
832        String selectedpropKey = ruleEditor.getSelectedKey();
833        Node<RuleEditorTreeNode, String> parentNode = PropositionTreeUtil.findParentPropositionNode(ruleEditor.getEditTree().getRootElement(), selectedpropKey);
834        PropositionEditor parent = parentNode.getData().getProposition();
835
836        PropositionEditor proposition = PropositionTreeUtil.findProposition(parentNode, selectedpropKey);
837
838        RuleViewHelperService viewHelper = this.getViewHelper(form);
839        viewHelper.setTypeForCompoundOpCode(parent, proposition.getCompoundOpCode());
840        viewHelper.resetDescription(parent);
841        viewHelper.refreshInitTrees(ruleEditor);
842
843        //Compare rule with parent rule.
844        compareRulePropositions((MaintenanceDocumentForm) form, ruleEditor);
845
846        return getUIFModelAndView(form);
847    }
848
849    /**
850     * Updates rule with new or changed propositions.
851     *
852     * @param form
853     * @param result
854     * @param request
855     * @param response
856     * @return
857     * @throws Exception
858     */
859    @RequestMapping(params = "methodToCall=updateProposition")
860    public ModelAndView updateProposition(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
861                                          HttpServletRequest request, HttpServletResponse response)
862            throws Exception {
863
864
865        //Reset the description on current selected proposition
866        RuleEditor ruleEditor = getRuleEditor(form);
867        PropositionEditor proposition = PropositionTreeUtil.getProposition(ruleEditor);
868        if (proposition != null) {
869
870            //Validate the proposition and return if has errors.
871            this.getViewHelper(form).validateProposition(proposition);
872            if (!GlobalVariables.getMessageMap().getErrorMessages().isEmpty()) {
873                return getUIFModelAndView(form);
874            }
875
876            if (!GlobalVariables.getMessageMap().getWarningMessages().isEmpty()) {
877                if (!hasDialogBeenAnswered(KRMSConstants.KSKRMS_DIALOG_YESNO_WARNING, form)) {
878                    return showDialog(KRMSConstants.KSKRMS_DIALOG_YESNO_WARNING, form, request, response);
879                }
880
881                String dialogResponse = getStringDialogResponse(KRMSConstants.KSKRMS_DIALOG_YESNO_WARNING, form, request, response);
882                if ("N".equals(dialogResponse)) {
883                    form.getDialogManager().resetDialogStatus(KRMSConstants.KSKRMS_DIALOG_YESNO_WARNING);
884                    return getUIFModelAndView(form);
885                }
886            }
887
888            //Reset the description and natural language for the proposition.
889            this.getViewHelper(form).resetDescription(proposition);
890            if (!GlobalVariables.getMessageMap().getErrorMessages().isEmpty()) {
891                return getUIFModelAndView(form);
892            }
893
894            //Check if the proposition that was edited is the root proposition and replace.
895            if (ruleEditor.getPropositionEditor().getKey().equals(ruleEditor.getSelectedKey())) {
896                ruleEditor.setProposition(proposition);
897            } else {
898                //Replace old proposition if not the root proposition.
899                this.setUpdatedProposition(ruleEditor.getPropositionEditor(), proposition);
900            }
901
902        }
903
904        if (ruleEditor.getProposition() != null) {
905            PropositionTreeUtil.resetNewProp(ruleEditor.getPropositionEditor());
906        }
907
908        // clear dialog history so user can press the button again
909        form.getDialogManager().resetDialogStatus(KRMSConstants.KSKRMS_DIALOG_YESNO_WARNING);
910
911        //Compare rule with parent rule.
912        compareRulePropositions((MaintenanceDocumentForm) form, ruleEditor);
913
914        //Remove the edit mode
915        PropositionTreeUtil.resetEditModeOnPropositionTree(ruleEditor.getPropositionEditor());
916        this.getViewHelper(form).refreshInitTrees(ruleEditor);
917
918        return getUIFModelAndView(form);
919    }
920
921    /**
922     * Replace old proposition with the updated proposition once the user clicked "Update Preview". We keep the
923     * old proposition for when the user want to cancel the editing of this proposition.
924     * <p/>
925     * Recursively walk through the proposition tree and search for the proposition with the same key, if found
926     * replace it at the same index.
927     *
928     * @param proposition
929     * @param updatedProposition
930     */
931    private void setUpdatedProposition(PropositionEditor proposition, PropositionEditor updatedProposition) {
932
933        if (proposition.getCompoundEditors() != null) {
934            for (int i = 0; i < proposition.getCompoundEditors().size(); i++) {
935                PropositionEditor childProp = proposition.getCompoundEditors().get(i);
936                if (childProp.getKey().equals(updatedProposition.getKey())) {
937                    proposition.getCompoundEditors().set(i, updatedProposition);
938                } else {
939                    setUpdatedProposition(childProp, updatedProposition);
940                }
941            }
942        }
943    }
944
945    protected void compareRulePropositions(MaintenanceDocumentForm form, RuleEditor ruleEditor) throws Exception {
946
947        RuleManagementWrapper ruleWrapper = (RuleManagementWrapper) form.getDocument().getNewMaintainableObject().getDataObject();
948
949        //Compare CO to CLU and display info message
950        if (ruleEditor.getProposition() != null) {
951            if (!this.getViewHelper(form).compareRules(ruleWrapper.getRuleEditor())) {
952                GlobalVariables.getMessageMap().putInfoForSectionId(KRMSConstants.KRMS_RULE_TREE_GROUP_ID, "info.krms.tree.rule.changed");
953            } else if (GlobalVariables.getMessageMap().containsMessageKey(KRMSConstants.KRMS_RULE_TREE_GROUP_ID)) {
954                GlobalVariables.getMessageMap().removeAllInfoMessagesForProperty(KRMSConstants.KRMS_RULE_TREE_GROUP_ID);
955            }
956        }
957    }
958
959    /**
960     * Updates rule and redirects to agenda maintenance page.
961     *
962     * @param form
963     * @param result
964     * @param request
965     * @param response
966     * @return
967     * @throws Exception
968     */
969    @RequestMapping(params = "methodToCall=updateRule")
970    public ModelAndView updateRule(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
971                                   HttpServletRequest request, HttpServletResponse response)
972            throws Exception {
973
974        RuleEditor ruleEditor = getRuleEditor(form);
975
976        //Return with error message if user is currently editing a proposition.
977        PropositionEditor proposition = PropositionTreeUtil.getProposition(ruleEditor);
978        if ((proposition!=null) && (proposition.isEditMode())) {
979            GlobalVariables.getMessageMap().putErrorForSectionId(KRMSConstants.KRMS_PROPOSITION_DETAILSECTION_ID, KRMSConstants.KRMS_MSG_ERROR_RULE_PREVIEW);
980            return getUIFModelAndView(form);
981        }
982
983        if (!(ruleEditor.getProposition() == null && ruleEditor.getPropId() == null)) {
984            PropositionTreeUtil.resetEditModeOnPropositionTree(ruleEditor.getPropositionEditor());
985            ruleEditor.setDummy(false);
986            PropositionTreeUtil.resetNewProp(ruleEditor.getPropositionEditor());
987        }
988        this.getViewHelper(form).refreshViewTree(ruleEditor);
989
990        //Replace edited rule with existing rule.
991        RuleManagementWrapper ruleWrapper = AgendaUtilities.getRuleWrapper((MaintenanceDocumentForm) form);
992        AgendaEditor agendaEditor = AgendaUtilities.getSelectedAgendaEditor(ruleWrapper, ruleEditor.getKey());
993        agendaEditor.getRuleEditors().put(ruleEditor.getKey(), ruleEditor);
994
995        if (!form.getActionParameters().containsKey(UifParameters.NAVIGATE_TO_PAGE_ID)) {
996            form.getActionParameters().put(UifParameters.NAVIGATE_TO_PAGE_ID, KRMSConstants.KRMS_AGENDA_MAINTENANCE_PAGE_ID);
997        }
998        return super.navigate(form, result, request, response);
999    }
1000
1001    /**
1002     * Updates view with changed logic expressions.
1003     * Also does validation and displays necessary messages on view.
1004     *
1005     * @param form
1006     * @param result
1007     * @param request
1008     * @param response
1009     * @return
1010     * @throws Exception
1011     */
1012    @RequestMapping(params = "methodToCall=updatePreview")
1013    public ModelAndView updatePreview(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
1014                                      HttpServletRequest request, HttpServletResponse response)
1015            throws Exception {
1016        RuleEditor ruleEditor = getRuleEditor(form);
1017        parseRuleExpression(ruleEditor, this.getViewHelper(form));
1018
1019        //Clear new collection lines to remove new collection add line only for edit tree
1020        if (form.getNewCollectionLines().size() != 1) {
1021            List<String> keys = new ArrayList<String>(form.getNewCollectionLines().keySet());
1022            for (String key : keys) {
1023                if (key.contains(PropositionTreeUtil.EDIT_TREE_NEW_COLLECTION_LINE)) {
1024                    form.getNewCollectionLines().remove(key);
1025                }
1026            }
1027        }
1028
1029        this.getViewHelper(form).refreshInitTrees(ruleEditor);
1030        return getUIFModelAndView(form);
1031    }
1032
1033    /**
1034     * Validation for logic expression.
1035     *
1036     * @param ruleEditor
1037     */
1038    private void parseRuleExpression(RuleEditor ruleEditor, RuleViewHelperService viewHelper) {
1039        RuleLogicExpressionParser ruleLogicExpressionParser = new RuleLogicExpressionParser();
1040        ruleLogicExpressionParser.setExpression(ruleEditor.getLogicArea());
1041        List<String> propsAlpha = this.getPropositionKeys(new ArrayList<String>(), ruleEditor.getPropositionEditor());
1042
1043        //validate the expression
1044        List<String> errorMessages = new ArrayList<String>();
1045        boolean validExpression = ruleLogicExpressionParser.validateExpression(errorMessages, propsAlpha);
1046
1047        //show errors and don't change anything else
1048        if (!validExpression) {
1049            for (int i = 0; i < errorMessages.size(); i++) {
1050                GlobalVariables.getMessageMap().putError("document.newMaintainableObject.dataObject.logicArea", errorMessages.get(i));
1051            }
1052            // reload page1
1053            return;
1054        }
1055
1056        ruleEditor.setProposition(ruleLogicExpressionParser.parseExpressionIntoRule(ruleEditor, viewHelper));
1057    }
1058
1059    /**
1060     * Returns list of proposition keys.
1061     *
1062     * @param propositionKeys
1063     * @param propositionEditor
1064     * @return
1065     */
1066    private List<String> getPropositionKeys(List<String> propositionKeys, PropositionEditor propositionEditor) {
1067        propositionKeys.add(propositionEditor.getKey());
1068        if (propositionEditor.getCompoundComponents() != null) {
1069            for (PropositionEditor child : propositionEditor.getCompoundEditors()) {
1070                this.getPropositionKeys(propositionKeys, child);
1071            }
1072        }
1073        return propositionKeys;
1074    }
1075
1076    /**
1077     * Reverts rule to previous state and refreshes view.
1078     *
1079     * @param form
1080     * @param result
1081     * @param request
1082     * @param response
1083     * @return
1084     * @throws Exception
1085     */
1086    @RequestMapping(params = "methodToCall=cancelEditProposition")
1087    public ModelAndView cancelEditProposition(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
1088                                              HttpServletRequest request, HttpServletResponse response)
1089            throws Exception {
1090
1091        RuleEditor ruleEditor = getRuleEditor(form);
1092        PropositionEditor root = ruleEditor.getPropositionEditor();
1093
1094        //If first root and not yet updated, clear rule root
1095        if (root.isNewProp() && root.isEditMode()) {
1096            ruleEditor.reset();
1097        } else {
1098            PropositionTreeUtil.cancelNewProp(root);
1099            PropositionTreeUtil.removeCompoundProp(ruleEditor);
1100
1101            ruleEditor.setSelectedKey(StringUtils.EMPTY);
1102            PropositionTreeUtil.resetEditModeOnPropositionTree(ruleEditor.getPropositionEditor());
1103        }
1104
1105        //Clear new collection lines to remove new collection add line only for edit tree
1106        if (form.getNewCollectionLines().size() != 1) {
1107            List<String> keys = new ArrayList<String>(form.getNewCollectionLines().keySet());
1108            for (String key : keys) {
1109                if (key.contains(PropositionTreeUtil.EDIT_TREE_NEW_COLLECTION_LINE)) {
1110                    form.getNewCollectionLines().remove(key);
1111                }
1112            }
1113        }
1114
1115        this.getViewHelper(form).refreshInitTrees(ruleEditor);
1116
1117        //Compare rule with parent rule.
1118        compareRulePropositions((MaintenanceDocumentForm) form, ruleEditor);
1119
1120        return getUIFModelAndView(form);
1121    }
1122
1123    /**
1124     * Reverts rule to previous state and navigates to agenda maintenance page.
1125     *
1126     * @param form
1127     * @param result
1128     * @param request
1129     * @param response
1130     * @return
1131     * @throws Exception
1132     */
1133    @RequestMapping(params = "methodToCall=cancelEditRule")
1134    public ModelAndView cancelEditRule(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
1135                                       HttpServletRequest request, HttpServletResponse response)
1136            throws Exception {
1137
1138        RuleEditor ruleEditor = getRuleEditor(form);
1139        PropositionEditor proposition = ruleEditor.getPropositionEditor();
1140
1141        //Reset the editing tree.
1142        if (proposition != null) {
1143            PropositionTreeUtil.cancelNewProp(proposition);
1144        }
1145        PropositionTreeUtil.resetEditModeOnPropositionTree(ruleEditor.getPropositionEditor());
1146
1147        if (!form.getActionParameters().containsKey(UifParameters.NAVIGATE_TO_PAGE_ID)) {
1148            form.getActionParameters().put(UifParameters.NAVIGATE_TO_PAGE_ID, KRMSConstants.KRMS_AGENDA_MAINTENANCE_PAGE_ID);
1149        }
1150        return super.navigate(form, result, request, response);
1151    }
1152
1153    /**
1154     * Updates proposition type and reloads view.
1155     *
1156     * @param form
1157     * @param result
1158     * @param request
1159     * @param response
1160     * @return
1161     * @throws Exception
1162     */
1163    @RequestMapping(params = "methodToCall=updatePropositionType")
1164    public ModelAndView updatePropositionType(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
1165                                              HttpServletRequest request, HttpServletResponse response)
1166            throws Exception {
1167
1168        PropositionEditor proposition = PropositionTreeUtil.getProposition(this.getRuleEditor(form));
1169        proposition.clear();
1170        this.getViewHelper(form).configurePropositionForType(proposition);
1171
1172        return getUIFModelAndView(form);
1173    }
1174
1175    /**
1176     * Test method for a controller that invokes a dialog lightbox.
1177     *
1178     * @param form     - test form
1179     * @param result   - Spring form binding result
1180     * @param request  - http request
1181     * @param response - http response
1182     * @return
1183     * @throws Exception
1184     */
1185    @RequestMapping(params = "methodToCall=compareRules")
1186    public ModelAndView compareRules(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
1187                                     HttpServletRequest request, HttpServletResponse response) throws Exception {
1188
1189        doCompareRules(form);
1190
1191        // redirect back to client to display lightbox
1192        return showDialog(KRMSConstants.KSKRMS_DIALOG_COMPARE, form, request, response);
1193    }
1194
1195    protected void doCompareRules(UifFormBase form) throws Exception {
1196        MaintenanceDocumentForm document = (MaintenanceDocumentForm) form;
1197        Object dataObject = document.getDocument().getNewMaintainableObject().getDataObject();
1198        if (dataObject instanceof RuleManagementWrapper) {
1199            RuleManagementWrapper ruleWrapper = (RuleManagementWrapper) dataObject;
1200            String ruleId = document.getActionParamaterValue(KRMSConstants.KRMS_PARM_RULE_KEY);
1201            RuleEditor ruleEditor = null;
1202            if ((ruleId != null) && (StringUtils.isNotBlank(ruleId))) {
1203                //Get a specific ruleEditor based on the ruleId.
1204                ruleEditor = AgendaUtilities.getSelectedRuleEditor(ruleWrapper, ruleId);
1205            } else {
1206                //Get the current editing ruleEditor.
1207                ruleEditor = ruleWrapper.getRuleEditor();
1208            }
1209
1210            //Build the compare rule tree
1211            ruleWrapper.setCompareTree(this.getViewHelper(form).buildCompareTree(ruleEditor, ruleEditor.getParent()));
1212            ruleWrapper.setCompareLightBoxHeader(ruleEditor.getRuleTypeInfo().getDescription());
1213        }
1214    }
1215
1216    /**
1217     * Returns form's view helper serivce.
1218     *
1219     * @param form
1220     * @return
1221     */
1222    protected RuleViewHelperService getViewHelper(UifFormBase form) {
1223        return (RuleViewHelperService) KSControllerHelper.getViewHelperService(form);
1224    }
1225
1226    /**
1227     * Retrieves selected proposition key and initializes edit on propostion.
1228     *
1229     * @param form
1230     * @param result
1231     * @param request
1232     * @param response
1233     * @return
1234     * @throws Exception
1235     */
1236    @RequestMapping(params = "methodToCall=getSelectedKey")
1237    public ModelAndView getSelectedKey(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
1238                                       HttpServletRequest request, HttpServletResponse response) throws Exception {
1239
1240        //Clear the current states of the tabs to open the first tab again with the edit tree.
1241        Map<String, String> states = (Map<String, String>) form.getClientStateForSyncing().get(KRMSConstants.KRMS_RULE_TABS_ID);
1242        states.put(KRMSConstants.KRMS_PARM_ACTIVE_TAB, KRMSConstants.KRMS_RULE_EDITWITHOBJECT_ID);
1243
1244        //Set the selected rule statement key.
1245        String selectedKey = request.getParameter(KRMSConstants.KRMS_PARM_SELECTED_KEY);
1246        getRuleEditor(form).setSelectedKey(selectedKey);
1247
1248        return this.goToEditProposition(form, result, request, response);
1249    }
1250
1251}