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