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.controller.MethodAccessible;
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.dto.RuleManager;
033import org.kuali.rice.krms.impl.repository.KrmsRepositoryServiceLocator;
034import org.kuali.rice.krms.service.RuleViewHelperService;
035import org.kuali.rice.krms.tree.node.RuleEditorTreeNode;
036import org.kuali.rice.krms.util.AgendaUtilities;
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     * Method used to invoke the CO inquiry view from Manage Course Offering screen while search input is Course Offering
060     * Code (04a screen)
061     *
062     * @param form
063     * @param result
064     * @param request
065     * @param response
066     * @return
067     */
068    @RequestMapping(params = "methodToCall=goToRuleView")
069    public ModelAndView goToRuleView(@ModelAttribute("KualiForm") UifFormBase form, @SuppressWarnings("unused") BindingResult result,
070                                     @SuppressWarnings("unused") HttpServletRequest request, @SuppressWarnings("unused") HttpServletResponse response) {
071
072        //Clear the client state on new edit rule.
073        form.getClientStateForSyncing().clear();
074
075        RuleEditor ruleEditor = this.retrieveSelectedRuleEditor(this.getMaintenanceDocumentForm(form));
076        this.getViewHelper(form).refreshInitTrees(ruleEditor);
077
078        if (!form.getActionParameters().containsKey(UifParameters.NAVIGATE_TO_PAGE_ID)) {
079            form.getActionParameters().put(UifParameters.NAVIGATE_TO_PAGE_ID, KRMSConstants.KRMS_RULE_MAINTENANCE_PAGE_ID);
080        }
081
082        //Compare rule with parent rule.
083        compareRulePropositions(this.getMaintenanceDocumentForm(form), ruleEditor);
084
085        return super.navigate(form, result, request, response);
086    }
087
088    /**
089     * Deletes selected rule from agenda on Manage Course Requistes page
090     *
091     * @param form
092     * @param result
093     * @param request
094     * @param response
095     * @return
096     */
097    @MethodAccessible
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 = this.getMaintenanceDocumentForm(form);
103        RuleManager 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 = this.retrieveSelectedRuleEditor(this.getMaintenanceDocumentForm(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 RuleManager) {
179                RuleManager wrapper = (RuleManager) 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    @MethodAccessible
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     */
217    @MethodAccessible
218    @RequestMapping(params = "methodToCall=goToEditProposition")
219    public ModelAndView goToEditProposition(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
220                                            HttpServletRequest request, HttpServletResponse response) {
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     */
259    @MethodAccessible
260    @RequestMapping(params = "methodToCall=addProposition")
261    public ModelAndView addProposition(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
262                                       HttpServletRequest request, HttpServletResponse response) {
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 == null || 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(KRMSConstants.COMPOUND_NODE_TYPE)) {
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(KRMSConstants.ROOT_TYPE) &&
288                    !parent.getChildren().get(parent.getChildren().size() - 1).getNodeType().contains(KRMSConstants.SIMPLE_NODE_TYPE)) {
289                parent = root.getChildren().get(root.getChildren().size() - 1);
290                selectedPropKey = parent.getChildren().get(parent.getChildren().size() - 1).getData().getProposition().getKey();
291            }
292        }
293
294        // add new child at appropriate spot
295        if (parent != null) {
296            List<Node<RuleEditorTreeNode, String>> children = parent.getChildren();
297            for (int index = 0; index < children.size(); index++) {
298                Node<RuleEditorTreeNode, String> child = children.get(index);
299
300                // if our selected node is a simple proposition, add a new one after
301                if (propKeyMatches(child, selectedPropKey)) {
302                    // handle special case of adding to a lone simple proposition.
303                    // in this case, we need to change the root level proposition to a compound proposition
304                    // move the existing simple proposition as the first compound component,
305                    // then add a new blank simple prop as the second compound component.
306                    PropositionEditor blank = null;
307                    if (parent.equals(root) && (isSimpleNode(child.getNodeType()))) {
308
309                        // create a new compound proposition
310                        blank = viewHelper.createCompoundPropositionBoStub(child.getData().getProposition(), true);
311                        // don't set compound.setEditMode(true) as the Simple Prop in the compound prop is the only prop in edit mode
312                        ruleEditor.setProposition(blank);
313                    }
314                    // handle regular case of adding a simple prop to an existing compound prop
315                    else if (!parent.equals(root)) {
316
317                        // build new Blank Proposition
318                        blank = viewHelper.createSimplePropositionBoStub(child.getData().getProposition());
319                        //add it to the parent
320                        PropositionEditor parentProp = parent.getData().getProposition();
321                        parentProp.getCompoundEditors().add(((index / 2) + 1), blank);
322                    } else {
323                        return getUIFModelAndView(form);
324                    }
325                    this.getViewHelper(form).refreshInitTrees(ruleEditor);
326                    if (blank != null) {
327                        ruleEditor.setSelectedKey(blank.getKey());
328                    } else {
329                        ruleEditor.setSelectedKey(null);
330                    }
331                    break;
332                }
333            }
334        } else {
335            // special case, if root has no children, add a new simple proposition
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     */
390    @MethodAccessible
391    @RequestMapping(params = "methodToCall=movePropositionUp")
392    public ModelAndView movePropositionUp(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
393                                          HttpServletRequest request, HttpServletResponse response) {
394        moveSelectedProposition(form, true);
395
396        return getUIFModelAndView(form);
397    }
398
399    /**
400     * Moves proposition down in tree structure.
401     *
402     * @param form
403     * @param result
404     * @param request
405     * @param response
406     * @return
407     */
408    @MethodAccessible
409    @RequestMapping(params = "methodToCall=movePropositionDown")
410    public ModelAndView movePropositionDown(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
411                                            HttpServletRequest request, HttpServletResponse response) {
412        moveSelectedProposition(form, false);
413
414        return getUIFModelAndView(form);
415    }
416
417    /**
418     * Moves proposition up or down.
419     * <p/>
420     * Rough algorithm for moving a node up.
421     * <p/>
422     * find the following:
423     * node := the selected node
424     * parent := the selected node's parent, its containing node (via when true or when false relationship)
425     * parentsOlderCousin := the parent's level-order predecessor (sibling or cousin)
426     *
427     * @param form
428     * @param up   whether the desired move is in an up direction
429     * @throws Exception
430     */
431    private void moveSelectedProposition(UifFormBase form, boolean up) {
432
433        RuleEditor ruleEditor = getRuleEditor(form);
434        String selectedPropKey = ruleEditor.getSelectedKey();
435
436        // find parent
437        Node<RuleEditorTreeNode, String> parent = PropositionTreeUtil.findParentPropositionNode(ruleEditor.getEditTree().getRootElement(), selectedPropKey);
438
439        // add new child at appropriate spot
440        if (parent != null) {
441            List<Node<RuleEditorTreeNode, String>> children = parent.getChildren();
442            for (int index = 0; index < children.size(); index++) {
443                Node<RuleEditorTreeNode, String> child = children.get(index);
444                // if our selected node is a simple proposition, add a new one after
445                if (propKeyMatches(child, selectedPropKey) &&
446                        (isSimpleNode(child.getNodeType()) ||
447                                (child.getNodeType().contains(KRMSConstants.COMPOUND_NODE_TYPE)) ||
448                                (child.getNodeType().contains(KRMSConstants.FIRST_IN_GROUP)) ||
449                                (child.getNodeType().contains(KRMSConstants.LAST_IN_GROUP)))) {
450
451                    //remove it from its current spot
452                    PropositionEditor parentProp = parent.getData().getProposition();
453                    PropositionEditor workingProp = null;
454                    if (index != 0 && up) {
455                        workingProp = parentProp.getCompoundEditors().remove(index / 2);
456                    } else if (!up && index != (children.size() - 1)) {
457                        workingProp = parentProp.getCompoundEditors().remove(index / 2);
458                    }
459                    if ((index > 0) && up) {
460                        parentProp.getCompoundEditors().add((index / 2) - 1, workingProp);
461                    } else if ((index < (children.size() - 1) && !up)) {
462                        parentProp.getCompoundEditors().add((index / 2) + 1, workingProp);
463                    }
464                    // redisplay the tree (editMode = true)
465                    this.getViewHelper(form).refreshInitTrees(ruleEditor);
466                    break;
467                }
468            }
469        }
470        //Compare rule with parent rule.
471        compareRulePropositions((MaintenanceDocumentForm) form, ruleEditor);
472
473    }
474
475    /**
476     * Returns <code>true</code> if node is of type simple
477     *
478     * @param nodeType
479     * @return if node is of type simple; <code>false</code> otherwise
480     */
481    public boolean isSimpleNode(String nodeType) {
482        if (nodeType.contains(KRMSConstants.SIMPLE_NODE_TYPE) ||
483                KRMSConstants.EDIT_NODE_TYPE.equalsIgnoreCase(nodeType)) {
484            return true;
485        }
486        return false;
487    }
488
489    /**
490     * Moves proposition left in tree structure.
491     * <p/>
492     * Rough algorithm for moving a node up.
493     * <p/>
494     * find the following:
495     * node := the selected node
496     * parent := the selected node's parent, its containing node (via when true or when false relationship)
497     * parentsOlderCousin := the parent's level-order predecessor (sibling or cousin)
498     *
499     * @param form
500     * @param result
501     * @param request
502     * @param response
503     * @return
504     */
505    @MethodAccessible
506    @RequestMapping(params = "methodToCall=movePropositionLeft")
507    public ModelAndView movePropositionLeft(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
508                                            HttpServletRequest request, HttpServletResponse response) {
509
510        RuleEditor ruleEditor = getRuleEditor(form);
511        String selectedpropKey = ruleEditor.getSelectedKey();
512
513        // find agendaEditor.getAgendaItemLine().getRule().getPropositionTree().getRootElement()parent
514        Node<RuleEditorTreeNode, String> root = ruleEditor.getEditTree().getRootElement();
515        Node<RuleEditorTreeNode, String> parent = PropositionTreeUtil.findParentPropositionNode(root, selectedpropKey);
516        if ((parent != null) && (!parent.getNodeType().contains(KRMSConstants.ROOT_TYPE))) {
517            Node<RuleEditorTreeNode, String> granny = PropositionTreeUtil.findParentPropositionNode(root, parent.getData().getProposition().getKey());
518            if (!granny.equals(root)) {
519                int oldIndex = findChildIndex(parent, selectedpropKey);
520                int newIndex = findChildIndex(granny, parent.getData().getProposition().getKey());
521                if (oldIndex >= 0 && newIndex >= 0) {
522                    PropositionEditor prop = parent.getData().getProposition().getCompoundEditors().remove(oldIndex / 2);
523                    if ((parent.getChildren().size() == 1) || (parent.getChildren().size() == 3)) {
524                        PropositionTreeUtil.removeCompoundProp(ruleEditor.getPropositionEditor());
525                    }
526                    if (granny.getData().getProposition().getCompoundEditors().isEmpty()) {
527                        granny.getData().getProposition().getCompoundEditors().add(newIndex, prop);
528                    } else {
529                        granny.getData().getProposition().getCompoundEditors().add((newIndex / 2) + 1, prop);
530                    }
531                    this.getViewHelper(form).refreshInitTrees(ruleEditor);
532                }
533            }
534
535        }
536        //Compare rule with parent rule.
537        compareRulePropositions(this.getMaintenanceDocumentForm(form), ruleEditor);
538        return getUIFModelAndView(form);
539    }
540
541    /**
542     * Move proposition right in tree structure.
543     * <p/>
544     * Rough algorithm for moving a node Right
545     * if the selected node is above a compound proposition, move it into the compound proposition as the first child
546     * if the node is above a simple proposition, do nothing.
547     * find the following:
548     * node := the selected node
549     * parent := the selected node's parent, its containing node
550     * nextSibling := the node after the selected node
551     *
552     * @param form
553     * @param result
554     * @param request
555     * @param response
556     * @return
557     */
558    @MethodAccessible
559    @RequestMapping(params = "methodToCall=movePropositionRight")
560    public ModelAndView movePropositionRight(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
561                                             HttpServletRequest request, HttpServletResponse response) {
562
563        RuleEditor ruleEditor = getRuleEditor(form);
564        String selectedpropKey = ruleEditor.getSelectedKey();
565
566        // find parent
567        Node<RuleEditorTreeNode, String> parent = PropositionTreeUtil.findParentPropositionNode(
568                ruleEditor.getEditTree().getRootElement(), selectedpropKey);
569        if (parent != null) {
570            int index = findChildIndex(parent, selectedpropKey);
571            // if we are the last child, do nothing, otherwise
572            if (index >= 0 && index + 1 < parent.getChildren().size()) {
573                Node<RuleEditorTreeNode, String> nextSibling = parent.getChildren().get(index + 2);
574                // if selected node above a compound node, move it into it as first child
575                if (nextSibling.getNodeType().contains(KRMSConstants.COMPOUND_NODE_TYPE)) {
576                    // remove selected node from it's current spot
577                    PropositionEditor prop = parent.getData().getProposition().getCompoundEditors().remove(index / 2);
578                    // add it to it's siblings children
579                    nextSibling.getData().getProposition().getCompoundEditors().add(0, prop);
580                }
581                //Remove single parents and refresh the tree.
582                PropositionTreeUtil.removeCompoundProp(parent.getData().getProposition());
583                this.getViewHelper(form).refreshInitTrees(ruleEditor);
584            }
585        }
586        //Compare rule with parent rule.
587        compareRulePropositions(this.getMaintenanceDocumentForm(form), ruleEditor);
588        return getUIFModelAndView(form);
589    }
590
591    /**
592     * Introduces a new compound proposition between the selected proposition and its parent.
593     * Additionally, it puts a new blank simple proposition underneath the compound proposition
594     * as a sibling to the selected proposition.
595     *
596     * @param form
597     * @param result
598     * @param request
599     * @param response
600     * @return
601     * @throws Exception
602     */
603    @MethodAccessible
604    @RequestMapping(params = "methodToCall=togglePropositionSimpleCompound")
605    public ModelAndView togglePropositionSimpleCompound(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
606                                                        HttpServletRequest request, HttpServletResponse response) {
607
608        RuleEditor ruleEditor = getRuleEditor(form);
609        String selectedPropKey = ruleEditor.getSelectedKey();
610
611        PropositionTreeUtil.resetEditModeOnPropositionTree(ruleEditor.getPropositionEditor());
612        RuleViewHelperService viewHelper = this.getViewHelper(form);
613
614        if (!StringUtils.isBlank(selectedPropKey)) {
615            // find parent
616            Node<RuleEditorTreeNode, String> parent = PropositionTreeUtil.findParentPropositionNode(
617                    ruleEditor.getEditTree().getRootElement(), selectedPropKey);
618            if (parent != null) {
619
620                int index = findChildIndex(parent, selectedPropKey);
621                PropositionEditor propBo = parent.getChildren().get(index).getData().getProposition();
622
623                // create a new compound proposition
624                PropositionEditor compound = viewHelper.createCompoundPropositionBoStub(propBo, true);
625
626                if (parent.getData() == null) { // SPECIAL CASE: this is the only proposition in the tree
627                    ruleEditor.setProposition(compound);
628                } else {
629                    PropositionEditor parentBo = parent.getData().getProposition();
630                    List<PropositionEditor> siblings = parentBo.getCompoundEditors();
631
632                    int propIndex = -1;
633                    for (int i = 0; i < siblings.size(); i++) {
634                        if (propBo.getKey().equals(siblings.get(i).getKey())) {
635                            propIndex = i;
636                            break;
637                        }
638                    }
639
640                    parentBo.getCompoundEditors().set(propIndex, compound);
641                    compound.getCompoundEditors().get(1).setEditMode(true);
642                }
643
644                viewHelper.refreshInitTrees(ruleEditor);
645                ruleEditor.setSelectedKey(compound.getCompoundEditors().get(1).getKey());
646
647            }
648        }
649
650        return getUIFModelAndView(form);
651    }
652
653    /**
654     * Paste proposition in selected position in tree structure.
655     *
656     * @param form
657     * @param result
658     * @param request
659     * @param response
660     * @return
661     * @throws Exception
662     */
663    @MethodAccessible
664    @RequestMapping(params = "methodToCall=pasteProposition")
665    public ModelAndView pasteProposition(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
666                                         HttpServletRequest request, HttpServletResponse response) {
667
668        boolean cutAction = true;
669        RuleEditor ruleEditor = getRuleEditor(form);
670        RuleViewHelperService viewHelper = this.getViewHelper(form);
671
672        // get selected id
673        String selectedPropKey = ruleEditor.getSelectedKey();
674        if (StringUtils.isBlank(selectedPropKey)) {
675            return getUIFModelAndView(form);
676        }
677
678        // get the id to move
679        String movePropKey = ruleEditor.getCutKey();
680        if (StringUtils.isBlank(movePropKey)) {
681            movePropKey = ruleEditor.getCopyKey();
682            cutAction = false;
683        }
684
685        // check if selected and move is not the same
686        if (StringUtils.isNotBlank(movePropKey)) {
687
688            PropositionEditor newParent = null;
689            PropositionEditor workingProp = null;
690            PropositionEditor root = ruleEditor.getPropositionEditor();
691
692            // Special case when the user copy the the only proposition in tree.
693            if (movePropKey.equals(root.getKey())) {
694                newParent = viewHelper.createCompoundPropositionBoStub(root, false);
695                workingProp = viewHelper.copyProposition(root);
696            } else {
697                Node<RuleEditorTreeNode, String> rootNode = ruleEditor.getEditTree().getRootElement();
698                if (selectedPropKey.equals(root.getKey())) {
699                    newParent = root;
700                } else {
701                    newParent = PropositionTreeUtil.findParentPropositionNode(rootNode, selectedPropKey).getData().getProposition();
702                }
703                PropositionEditor oldParent = PropositionTreeUtil.findParentPropositionNode(rootNode, movePropKey).getData().getProposition();
704
705                // cut or copy from old
706                if (oldParent != null) {
707                    List<PropositionEditor> children = oldParent.getCompoundEditors();
708                    for (int index = 0; index < children.size(); index++) {
709                        if (movePropKey.equalsIgnoreCase(children.get(index).getKey())) {
710                            if (cutAction) {
711                                workingProp = oldParent.getCompoundEditors().remove(index);
712                            } else {
713                                workingProp = viewHelper.copyProposition(oldParent.getCompoundEditors().get(index));
714                            }
715                            break;
716                        }
717                    }
718                }
719            }
720
721            // add to new
722            addProposition(selectedPropKey, newParent, workingProp);
723            if (movePropKey.equals(root.getKey())) {
724                ruleEditor.setProposition(newParent);
725            }
726
727            //Refresh the tree.
728            PropositionTreeUtil.removeCompoundProp(ruleEditor);
729            ruleEditor.setSelectedKey(StringUtils.EMPTY);
730            viewHelper.refreshInitTrees(ruleEditor);
731        }
732
733        //Compare rule with parent rule.
734        compareRulePropositions(this.getMaintenanceDocumentForm(form), ruleEditor);
735
736        // call the super method to avoid the agenda tree being reloaded from the db
737        return getUIFModelAndView(form);
738    }
739
740    /**
741     * Adds proposition at selected position.
742     *
743     * @param selectedpropKey
744     * @param newParent
745     * @param workingProp
746     */
747    private void addProposition(String selectedpropKey, PropositionEditor newParent, PropositionEditor workingProp) {
748        // add to new
749        if (newParent != null && workingProp != null) {
750            //Selected is parent, add to list.
751            if(selectedpropKey.equalsIgnoreCase(newParent.getKey())){
752                newParent.getCompoundEditors().add(workingProp);
753                return;
754            }
755
756            //Add after selected prop.
757            List<PropositionEditor> children = newParent.getCompoundEditors();
758            for (int index = 0; index < children.size(); index++) {
759                if (selectedpropKey.equalsIgnoreCase(children.get(index).getKey())) {
760                    children.add(index + 1, workingProp);
761                    return;
762                }
763            }
764        }
765    }
766
767    /**
768     * Removes proposition.
769     *
770     * @param form
771     * @param result
772     * @param request
773     * @param response
774     * @return
775     */
776    @MethodAccessible
777    @RequestMapping(params = "methodToCall=deleteProposition")
778    public ModelAndView deleteProposition(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
779                                          HttpServletRequest request, HttpServletResponse response) {
780        RuleEditor ruleEditor = getRuleEditor(form);
781        String selectedpropKey = ruleEditor.getSelectedKey();
782        Node<RuleEditorTreeNode, String> root = ruleEditor.getEditTree().getRootElement();
783
784        Node<RuleEditorTreeNode, String> parentNode = PropositionTreeUtil.findParentPropositionNode(root, selectedpropKey);
785
786        // what if it is the root?
787        if (parentNode != null && parentNode.getData() != null) { // it is not the root as there is a parent w/ a prop
788            PropositionEditor parent = parentNode.getData().getProposition();
789            if (parent != null) {
790                List<PropositionEditor> children = parent.getCompoundEditors();
791                for (int index = 0; index < children.size(); index++) {
792                    if (selectedpropKey.equalsIgnoreCase(children.get(index).getKey())) {
793                        parent.getCompoundComponents().remove(index);
794                        break;
795                    }
796                }
797            }
798            PropositionTreeUtil.removeCompoundProp(ruleEditor);
799            ruleEditor.setSelectedKey(StringUtils.EMPTY);
800        } else { // no parent, it is the root
801            ruleEditor.reset();
802        }
803
804        //Compare rule with parent rule.
805        compareRulePropositions(this.getMaintenanceDocumentForm(form), ruleEditor);
806
807        this.getViewHelper(form).refreshInitTrees(ruleEditor);
808        return getUIFModelAndView(form);
809    }
810
811    /**
812     * Updates compound operator in tree structure.
813     *
814     * @param form
815     * @param result
816     * @param request
817     * @param response
818     * @return
819     */
820    @MethodAccessible
821    @RequestMapping(params = "methodToCall=updateCompoundOperator")
822    public ModelAndView updateCompoundOperator(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
823                                               HttpServletRequest request, HttpServletResponse response) {
824
825        RuleEditor ruleEditor = getRuleEditor(form);
826        String selectedpropKey = ruleEditor.getSelectedKey();
827        Node<RuleEditorTreeNode, String> parentNode = PropositionTreeUtil.findParentPropositionNode(ruleEditor.getEditTree().getRootElement(), selectedpropKey);
828        PropositionEditor parent = parentNode.getData().getProposition();
829
830        PropositionEditor proposition = PropositionTreeUtil.findProposition(parentNode, selectedpropKey);
831
832        RuleViewHelperService viewHelper = this.getViewHelper(form);
833        viewHelper.setTypeForCompoundOpCode(parent, proposition.getCompoundOpCode());
834        viewHelper.resetDescription(parent);
835        viewHelper.refreshInitTrees(ruleEditor);
836
837        //Compare rule with parent rule.
838        compareRulePropositions(this.getMaintenanceDocumentForm(form), ruleEditor);
839
840        return getUIFModelAndView(form);
841    }
842
843    /**
844     * Updates rule with new or changed propositions.
845     *
846     * @param form
847     * @param result
848     * @param request
849     * @param response
850     * @return
851     * @throws Exception
852     */
853    @MethodAccessible
854    @RequestMapping(params = "methodToCall=updateProposition")
855    public ModelAndView updateProposition(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
856                                          HttpServletRequest request, HttpServletResponse response) {
857
858        //Reset the description on current selected proposition
859        RuleEditor ruleEditor = getRuleEditor(form);
860        PropositionEditor proposition = PropositionTreeUtil.getProposition(ruleEditor);
861        if (proposition != null) {
862
863            //Validate the proposition and return if has errors.
864            this.getViewHelper(form).validateProposition(proposition);
865            if (!GlobalVariables.getMessageMap().getErrorMessages().isEmpty()) {
866                return getUIFModelAndView(form);
867            }
868
869            if (!GlobalVariables.getMessageMap().getWarningMessages().isEmpty()) {
870                if (!hasDialogBeenAnswered(KRMSConstants.KSKRMS_DIALOG_YESNO_WARNING, form)) {
871                    return showDialog(KRMSConstants.KSKRMS_DIALOG_YESNO_WARNING, form, request, response);
872                }
873
874                String dialogResponse = getStringDialogResponse(KRMSConstants.KSKRMS_DIALOG_YESNO_WARNING, form, request, response);
875                if ("N".equals(dialogResponse)) {
876                    form.getDialogManager().resetDialogStatus(KRMSConstants.KSKRMS_DIALOG_YESNO_WARNING);
877                    return getUIFModelAndView(form);
878                }
879            }
880
881            //Reset the description and natural language for the proposition.
882            this.getViewHelper(form).resetDescription(proposition);
883            if (!GlobalVariables.getMessageMap().getErrorMessages().isEmpty()) {
884                return getUIFModelAndView(form);
885            }
886
887            //Check if the proposition that was edited is the root proposition and replace.
888            if (ruleEditor.getPropositionEditor().getKey().equals(ruleEditor.getSelectedKey())) {
889                ruleEditor.setProposition(proposition);
890            } else {
891                //Replace old proposition if not the root proposition.
892                this.setUpdatedProposition(ruleEditor.getPropositionEditor(), proposition);
893            }
894
895        }
896
897        if (ruleEditor.getProposition() != null) {
898            PropositionTreeUtil.resetNewProp(ruleEditor.getPropositionEditor());
899        }
900
901        // clear dialog history so user can press the button again
902        form.getDialogManager().resetDialogStatus(KRMSConstants.KSKRMS_DIALOG_YESNO_WARNING);
903
904        //Compare rule with parent rule.
905        compareRulePropositions(this.getMaintenanceDocumentForm(form), ruleEditor);
906
907        //Remove the edit mode
908        PropositionTreeUtil.resetEditModeOnPropositionTree(ruleEditor.getPropositionEditor());
909        this.getViewHelper(form).refreshInitTrees(ruleEditor);
910
911        return getUIFModelAndView(form);
912    }
913
914    /**
915     * Replace old proposition with the updated proposition once the user clicked "Update Preview". We keep the
916     * old proposition for when the user want to cancel the editing of this proposition.
917     * <p/>
918     * Recursively walk through the proposition tree and search for the proposition with the same key, if found
919     * replace it at the same index.
920     *
921     * @param proposition
922     * @param updatedProposition
923     */
924    private void setUpdatedProposition(PropositionEditor proposition, PropositionEditor updatedProposition) {
925
926        if (proposition.getCompoundEditors() != null) {
927            for (int i = 0; i < proposition.getCompoundEditors().size(); i++) {
928                PropositionEditor childProp = proposition.getCompoundEditors().get(i);
929                if (childProp.getKey().equals(updatedProposition.getKey())) {
930                    proposition.getCompoundEditors().set(i, updatedProposition);
931                } else {
932                    setUpdatedProposition(childProp, updatedProposition);
933                }
934            }
935        }
936    }
937
938    protected void compareRulePropositions(MaintenanceDocumentForm form, RuleEditor ruleEditor) {
939
940        RuleManager ruleWrapper = (RuleManager) form.getDocument().getNewMaintainableObject().getDataObject();
941
942        //Compare rule to parent and display info message
943        if (ruleEditor.getProposition() != null) {
944            if (!this.getViewHelper(form).compareRules(ruleWrapper.getRuleEditor())) {
945                GlobalVariables.getMessageMap().putInfoForSectionId(KRMSConstants.KRMS_RULE_TREE_GROUP_ID, "info.krms.tree.rule.changed");
946            } else if (GlobalVariables.getMessageMap().containsMessageKey(KRMSConstants.KRMS_RULE_TREE_GROUP_ID)) {
947                GlobalVariables.getMessageMap().removeAllInfoMessagesForProperty(KRMSConstants.KRMS_RULE_TREE_GROUP_ID);
948            }
949        }
950    }
951
952    /**
953     * Updates rule and redirects to agenda maintenance page.
954     *
955     * @param form
956     * @param result
957     * @param request
958     * @param response
959     * @return
960     * @throws Exception
961     */
962    @RequestMapping(params = "methodToCall=updateRule")
963    public ModelAndView updateRule(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
964                                   HttpServletRequest request, HttpServletResponse response) {
965
966        RuleEditor ruleEditor = getRuleEditor(form);
967
968        //Return with error message if user is currently editing a proposition.
969        PropositionEditor proposition = PropositionTreeUtil.getProposition(ruleEditor);
970        if ((proposition!=null) && (proposition.isEditMode())) {
971            GlobalVariables.getMessageMap().putErrorForSectionId(KRMSConstants.KRMS_PROPOSITION_DETAILSECTION_ID+proposition.getIdSuffix(),
972                    KRMSConstants.KRMS_MSG_ERROR_RULE_PREVIEW);
973            return getUIFModelAndView(form);
974        }
975
976        if (!(ruleEditor.getProposition() == null && ruleEditor.getPropId() == null)) {
977            PropositionTreeUtil.resetEditModeOnPropositionTree(ruleEditor.getPropositionEditor());
978            ruleEditor.setDummy(false);
979            PropositionTreeUtil.resetNewProp(ruleEditor.getPropositionEditor());
980        }
981
982        if(ruleEditor.getPropositionEditor()!=null){
983            // handle saving new parameterized terms
984            this.getViewHelper(form).finPropositionEditor(ruleEditor.getPropositionEditor());
985        }
986
987        this.getViewHelper(form).refreshViewTree(ruleEditor);
988
989        //Replace edited rule with existing rule.
990        RuleManager ruleWrapper = AgendaUtilities.getRuleWrapper(this.getMaintenanceDocumentForm(form));
991        AgendaEditor agendaEditor = AgendaUtilities.getSelectedAgendaEditor(ruleWrapper, ruleEditor.getKey());
992        agendaEditor.getRuleEditors().put(ruleEditor.getKey(), ruleEditor);
993
994        if (!form.getActionParameters().containsKey(UifParameters.NAVIGATE_TO_PAGE_ID)) {
995            form.getActionParameters().put(UifParameters.NAVIGATE_TO_PAGE_ID, KRMSConstants.KRMS_AGENDA_MAINTENANCE_PAGE_ID);
996        }
997        return super.navigate(form, result, request, response);
998    }
999
1000    /**
1001     * Updates view with changed logic expressions.
1002     * Also does validation and displays necessary messages on view.
1003     *
1004     * @param form
1005     * @param result
1006     * @param request
1007     * @param response
1008     * @return
1009     * @throws Exception
1010     */
1011    @RequestMapping(params = "methodToCall=updatePreview")
1012    public ModelAndView updatePreview(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
1013                                      HttpServletRequest request, HttpServletResponse response) {
1014        RuleEditor ruleEditor = getRuleEditor(form);
1015        parseRuleExpression(ruleEditor, this.getViewHelper(form));
1016
1017        //Clear new collection lines to remove new collection add line only for edit tree
1018        if (form.getNewCollectionLines().size() != 1) {
1019            List<String> keys = new ArrayList<String>(form.getNewCollectionLines().keySet());
1020            for (String key : keys) {
1021                if (key.contains(PropositionTreeUtil.EDIT_TREE_NEW_COLLECTION_LINE)) {
1022                    form.getNewCollectionLines().remove(key);
1023                }
1024            }
1025        }
1026
1027        this.getViewHelper(form).refreshInitTrees(ruleEditor);
1028        return getUIFModelAndView(form);
1029    }
1030
1031    /**
1032     * Validation for logic expression.
1033     *
1034     * @param ruleEditor
1035     */
1036    private void parseRuleExpression(RuleEditor ruleEditor, RuleViewHelperService viewHelper) {
1037        RuleLogicExpressionParser ruleLogicExpressionParser = new RuleLogicExpressionParser();
1038
1039        if (ruleEditor.getLogicArea() == null) {
1040            GlobalVariables.getMessageMap().putError("document.newMaintainableObject.dataObject.logicArea",
1041                    KRMSConstants.KSKRMS_MSG_INFO_LOGIC_NO_STATEMENTS);
1042            return;
1043        }
1044
1045        ruleLogicExpressionParser.setExpression(ruleEditor.getLogicArea());
1046
1047        //validate the expression
1048        List<String> errorMessages = new ArrayList<String>();
1049        List<String> keyList = getPropositionKeys(new ArrayList<String>(), ruleEditor.getPropositionEditor());
1050        boolean validExpression = ruleLogicExpressionParser.validateExpression(errorMessages, keyList);
1051
1052        //show errors and don't change anything else
1053        if (!validExpression) {
1054            for (int i = 0; i < errorMessages.size(); i++) {
1055                GlobalVariables.getMessageMap().putError("document.newMaintainableObject.dataObject.logicArea", errorMessages.get(i));
1056            }
1057            // reload page1
1058            return;
1059        }
1060
1061        ruleEditor.setProposition(ruleLogicExpressionParser.parseExpressionIntoRule(ruleEditor, viewHelper));
1062    }
1063
1064    /**
1065     * Returns list of proposition keys.
1066     *
1067     * @param propositionKeys
1068     * @param propositionEditor
1069     * @return
1070     */
1071    private List<String> getPropositionKeys(List<String> propositionKeys, PropositionEditor propositionEditor) {
1072        propositionKeys.add(propositionEditor.getKey());
1073        if (propositionEditor.getCompoundComponents() != null) {
1074            for (PropositionEditor child : propositionEditor.getCompoundEditors()) {
1075                this.getPropositionKeys(propositionKeys, child);
1076            }
1077        }
1078        return propositionKeys;
1079    }
1080
1081    /**
1082     * Reverts rule to previous state and refreshes view.
1083     *
1084     * @param form
1085     * @param result
1086     * @param request
1087     * @param response
1088     * @return
1089     */
1090    @MethodAccessible
1091    @RequestMapping(params = "methodToCall=cancelEditProposition")
1092    public ModelAndView cancelEditProposition(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
1093                                              HttpServletRequest request, HttpServletResponse response) {
1094
1095        RuleEditor ruleEditor = getRuleEditor(form);
1096        PropositionEditor root = ruleEditor.getPropositionEditor();
1097
1098        //If first root and not yet updated, clear rule root
1099        if (root.isNewProp() && root.isEditMode()) {
1100            ruleEditor.reset();
1101        } else {
1102            PropositionTreeUtil.cancelNewProp(root);
1103            PropositionTreeUtil.removeCompoundProp(ruleEditor);
1104
1105            ruleEditor.setSelectedKey(StringUtils.EMPTY);
1106            PropositionTreeUtil.resetEditModeOnPropositionTree(ruleEditor.getPropositionEditor());
1107        }
1108
1109        //Clear new collection lines to remove new collection add line only for edit tree
1110        if (form.getNewCollectionLines().size() != 1) {
1111            List<String> keys = new ArrayList<String>(form.getNewCollectionLines().keySet());
1112            for (String key : keys) {
1113                if (key.contains(PropositionTreeUtil.EDIT_TREE_NEW_COLLECTION_LINE)) {
1114                    form.getNewCollectionLines().remove(key);
1115                }
1116            }
1117        }
1118
1119        this.getViewHelper(form).refreshInitTrees(ruleEditor);
1120
1121        //Compare rule with parent rule.
1122        compareRulePropositions(this.getMaintenanceDocumentForm(form), ruleEditor);
1123
1124        return getUIFModelAndView(form);
1125    }
1126
1127    /**
1128     * Reverts rule to previous state and navigates to agenda maintenance page.
1129     *
1130     * @param form
1131     * @param result
1132     * @param request
1133     * @param response
1134     * @return
1135     */
1136    @RequestMapping(params = "methodToCall=cancelEditRule")
1137    public ModelAndView cancelEditRule(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
1138                                       HttpServletRequest request, HttpServletResponse response) {
1139
1140        RuleEditor ruleEditor = getRuleEditor(form);
1141        PropositionEditor proposition = ruleEditor.getPropositionEditor();
1142
1143        //Reset the editing tree.
1144        if (proposition != null) {
1145            PropositionTreeUtil.cancelNewProp(proposition);
1146        }
1147        PropositionTreeUtil.resetEditModeOnPropositionTree(ruleEditor.getPropositionEditor());
1148
1149        if (!form.getActionParameters().containsKey(UifParameters.NAVIGATE_TO_PAGE_ID)) {
1150            form.getActionParameters().put(UifParameters.NAVIGATE_TO_PAGE_ID, KRMSConstants.KRMS_AGENDA_MAINTENANCE_PAGE_ID);
1151        }
1152        return super.navigate(form, result, request, response);
1153    }
1154
1155    /**
1156     * Updates proposition type and reloads view.
1157     *
1158     * @param form
1159     * @param result
1160     * @param request
1161     * @param response
1162     * @return
1163     */
1164    @MethodAccessible
1165    @RequestMapping(params = "methodToCall=updatePropositionType")
1166    public ModelAndView updatePropositionType(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
1167                                              HttpServletRequest request, HttpServletResponse response) {
1168
1169        PropositionEditor proposition = PropositionTreeUtil.getProposition(this.getRuleEditor(form));
1170        proposition.clear();
1171        this.getViewHelper(form).configurePropositionForType(proposition);
1172
1173        return getUIFModelAndView(form);
1174    }
1175
1176    /**
1177     * Test method for a controller that invokes a dialog lightbox.
1178     *
1179     * @param form     - test form
1180     * @param result   - Spring form binding result
1181     * @param request  - http request
1182     * @param response - http response
1183     * @return
1184     */
1185    @RequestMapping(params = "methodToCall=compareRules")
1186    public ModelAndView compareRules(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
1187                                     HttpServletRequest request, HttpServletResponse response) {
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) {
1196        MaintenanceDocumentForm document = (MaintenanceDocumentForm) form;
1197        Object dataObject = document.getDocument().getNewMaintainableObject().getDataObject();
1198        if (dataObject instanceof RuleManager) {
1199            RuleManager ruleWrapper = (RuleManager) 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.getParent(), ruleEditor));
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     */
1235    @RequestMapping(params = "methodToCall=getSelectedKey")
1236    public ModelAndView getSelectedKey(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
1237                                       HttpServletRequest request, HttpServletResponse response) {
1238
1239        //Clear the current states of the tabs to open the first tab again with the edit tree.
1240        Map<String, String> states = (Map<String, String>) form.getClientStateForSyncing().get(KRMSConstants.KRMS_RULE_TABS_ID);
1241        states.put(KRMSConstants.KRMS_PARM_ACTIVE_TAB, KRMSConstants.KRMS_RULE_EDITWITHOBJECT_ID);
1242
1243        //Set the selected rule statement key.
1244        String selectedKey = request.getParameter(KRMSConstants.KRMS_PARM_SELECTED_KEY);
1245        getRuleEditor(form).setSelectedKey(selectedKey);
1246
1247        return this.goToEditProposition(form, result, request, response);
1248    }
1249
1250    /**
1251     * Refreshes logic area input field when changing tabs.
1252     *
1253     * @param form
1254     * @param result
1255     * @param request
1256     * @param response
1257     * @return
1258     */
1259    @MethodAccessible
1260    @RequestMapping(params = "methodToCall=refreshLogicArea")
1261    public ModelAndView refreshLogicArea(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
1262                                       HttpServletRequest request, HttpServletResponse response) {
1263
1264        RuleEditor rule = this.getRuleEditor(form);
1265
1266        //Reset the logic expression.
1267        if (rule.getProposition() != null) {
1268            rule.setLogicArea(PropositionTreeUtil.configureLogicExpression(rule.getPropositionEditor()));
1269        } else {
1270            rule.setLogicArea(StringUtils.EMPTY);
1271        }
1272
1273        return super.getUIFModelAndView(form);
1274    }
1275
1276    protected RuleEditor retrieveSelectedRuleEditor(MaintenanceDocumentForm document){
1277        return AgendaUtilities.retrieveSelectedRuleEditor(document);
1278    }
1279
1280    //Method for checking if the form is an instance of maintenanceDocumentForm, then returning the casted form
1281    protected MaintenanceDocumentForm getMaintenanceDocumentForm(UifFormBase form) {
1282        if (form instanceof MaintenanceDocumentForm) {
1283            return (MaintenanceDocumentForm) form;
1284        }
1285        throw new RuntimeException("Error retrieving Maintenance document form from UifFormBase");
1286    }
1287
1288}