001    /**
002     * Copyright 2005-2012 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     */
016    package org.kuali.rice.krms.controller;
017    
018    import org.apache.commons.lang.StringUtils;
019    import org.kuali.rice.core.api.util.tree.Node;
020    import org.kuali.rice.krad.uif.UifParameters;
021    import org.kuali.rice.krad.uif.component.Component;
022    import org.kuali.rice.krad.uif.container.Group;
023    import org.kuali.rice.krad.uif.container.LinkGroup;
024    import org.kuali.rice.krad.uif.element.Action;
025    import org.kuali.rice.krad.uif.field.MessageField;
026    import org.kuali.rice.krad.uif.util.ComponentFactory;
027    import org.kuali.rice.krad.uif.util.ComponentUtils;
028    import org.kuali.rice.krad.util.GlobalVariables;
029    import org.kuali.rice.krad.web.controller.MaintenanceDocumentController;
030    import org.kuali.rice.krad.web.form.MaintenanceDocumentForm;
031    import org.kuali.rice.krad.web.form.UifFormBase;
032    import org.kuali.rice.krms.api.repository.LogicalOperator;
033    import org.kuali.rice.krms.api.repository.proposition.PropositionType;
034    import org.kuali.rice.krms.api.repository.type.KrmsTypeDefinition;
035    import org.kuali.rice.krms.dto.AgendaEditor;
036    import org.kuali.rice.krms.dto.PropositionEditor;
037    import org.kuali.rice.krms.dto.RuleEditor;
038    import org.kuali.rice.krms.dto.RuleManagementWrapper;
039    import org.kuali.rice.krms.dto.RuleTypeInfo;
040    import org.kuali.rice.krms.dto.TemplateInfo;
041    import org.kuali.rice.krms.impl.repository.KrmsRepositoryServiceLocator;
042    import org.kuali.rice.krms.impl.util.KRMSPropertyConstants;
043    import org.kuali.rice.krms.service.RuleViewHelperService;
044    import org.kuali.rice.krms.tree.RuleViewTreeBuilder;
045    import org.kuali.rice.krms.util.AgendaUtilities;
046    import org.kuali.student.enrollment.class1.krms.dto.EnrolPropositionEditor;
047    import org.kuali.student.enrollment.class1.krms.tree.node.KSSimplePropositionEditNode;
048    import org.kuali.student.enrollment.class1.krms.tree.node.KSSimplePropositionNode;
049    import org.kuali.rice.krms.tree.node.RuleEditorTreeNode;
050    import org.kuali.rice.krms.util.PropositionTreeUtil;
051    import org.kuali.rice.krms.util.RuleLogicExpressionParser;
052    import org.kuali.student.enrollment.uif.util.KSControllerHelper;
053    import org.kuali.student.krms.KRMSConstants;
054    import org.springframework.validation.BindingResult;
055    import org.springframework.web.bind.annotation.ModelAttribute;
056    import org.springframework.web.bind.annotation.RequestMapping;
057    import org.springframework.web.servlet.ModelAndView;
058    
059    import javax.servlet.http.HttpServletRequest;
060    import javax.servlet.http.HttpServletResponse;
061    import java.util.ArrayList;
062    import java.util.List;
063    
064    /**
065     * Controller for the Test UI Page
066     *
067     * @author Kuali Rice Team (rice.collab@kuali.org)
068     */
069    public class RuleEditorController extends MaintenanceDocumentController {
070    
071        /*
072        * Method used to invoke the CO inquiry view from Manage Course Offering screen while search input is Course Offering
073        * Code (04a screen)
074        */
075        @RequestMapping(params = "methodToCall=goToRuleView")
076        public ModelAndView goToRuleView(@ModelAttribute("KualiForm") UifFormBase form, @SuppressWarnings("unused") BindingResult result,
077                                         @SuppressWarnings("unused") HttpServletRequest request, @SuppressWarnings("unused") HttpServletResponse response) throws Exception {
078    
079            RuleEditor ruleEditor = AgendaUtilities.retrieveSelectedRuleEditor(form);
080    
081            this.getViewHelper(form).refreshInitTrees(ruleEditor);
082    
083            form.getActionParameters().put(UifParameters.NAVIGATE_TO_PAGE_ID, "KRMS-RuleMaintenance-Page");
084            return super.navigate(form, result, request, response);
085        }
086    
087        @RequestMapping(params = "methodToCall=deleteRule")
088        public ModelAndView deleteRule(@ModelAttribute("KualiForm") UifFormBase form, @SuppressWarnings("unused") BindingResult result,
089                                       @SuppressWarnings("unused") HttpServletRequest request, @SuppressWarnings("unused") HttpServletResponse response) throws Exception {
090            MaintenanceDocumentForm document = (MaintenanceDocumentForm) form;
091            RuleManagementWrapper ruleWrapper = (RuleManagementWrapper) document.getDocument().getNewMaintainableObject().getDataObject();
092            String ruleKey = document.getActionParamaterValue("ruleKey");
093    
094            RuleEditor ruleEditor = AgendaUtilities.getSelectedRuleEditor(ruleWrapper, ruleKey);
095    
096            List<AgendaEditor> agendas = ruleWrapper.getAgendas();
097            for (AgendaEditor agenda : agendas) {
098                if (agenda.getRuleEditors().contains(ruleEditor)) {
099                    ruleWrapper.getDeletedRuleIds().add(ruleEditor.getId());
100                    agenda.getRuleEditors().remove(ruleEditor);
101                }
102            }
103    
104            return getUIFModelAndView(document);
105        }
106    
107        @RequestMapping(params = "methodToCall=addRule")
108        public ModelAndView addRule(@ModelAttribute("KualiForm") UifFormBase form, @SuppressWarnings("unused") BindingResult result,
109                                    @SuppressWarnings("unused") HttpServletRequest request, @SuppressWarnings("unused") HttpServletResponse response) throws Exception {
110            RuleEditor ruleEditor = AgendaUtilities.retrieveSelectedRuleEditor(form);
111            ruleEditor.setDummy(false);
112    
113            this.getViewHelper(form).refreshInitTrees(ruleEditor);
114    
115            form.getActionParameters().put(UifParameters.NAVIGATE_TO_PAGE_ID, "KRMS-RuleMaintenance-Page");
116            return super.navigate(form, result, request, response);
117        }
118    
119        @RequestMapping(params = "methodToCall=ajaxRefresh")
120        public ModelAndView ajaxRefresh(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
121                                        HttpServletRequest request, HttpServletResponse response)
122                throws Exception {
123            // call the super method to avoid the agenda tree being reloaded from the db
124            return getUIFModelAndView(form);
125        }
126    
127        /**
128         * @param form
129         * @return the {@link org.kuali.rice.krms.impl.ui.AgendaEditor} from the form
130         */
131        protected RuleEditor getRuleEditor(UifFormBase form) {
132            if (form instanceof MaintenanceDocumentForm) {
133                MaintenanceDocumentForm maintenanceDocumentForm = (MaintenanceDocumentForm) form;
134                Object dataObject = maintenanceDocumentForm.getDocument().getNewMaintainableObject().getDataObject();
135    
136                if (dataObject instanceof RuleEditor) {
137                    return (RuleEditor) dataObject;
138                } else if (dataObject instanceof RuleManagementWrapper) {
139                    RuleManagementWrapper wrapper = (RuleManagementWrapper) dataObject;
140                    return wrapper.getRuleEditor();
141                }
142            }
143    
144            return null;
145        }
146    
147        //
148        // Rule Editor Controller methods
149        //
150        @RequestMapping(params = "methodToCall=copyRule")
151        public ModelAndView copyRule(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
152                                     HttpServletRequest request, HttpServletResponse response) throws Exception {
153    
154            //TODO: Copy rule to a different Co or AO
155    
156            return super.refresh(form, result, request, response);
157        }
158    
159        /**
160         * This method starts an edit proposition.
161         */
162        @RequestMapping(params = "methodToCall=goToEditProposition")
163        public ModelAndView goToEditProposition(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
164                                                HttpServletRequest request, HttpServletResponse response) throws Exception {
165    
166            RuleViewHelperService viewHelper = this.getViewHelper(form);
167    
168            // open the selected node for editing
169            RuleEditor ruleEditor = getRuleEditor(form);
170            String selectedpropKey = ruleEditor.getSelectedKey();
171    
172            Node<RuleEditorTreeNode, String> root = ruleEditor.getEditTree().getRootElement();
173            PropositionEditor propositionToToggleEdit = null;
174            boolean newEditMode = true;
175    
176            // find parent
177            Node<RuleEditorTreeNode, String> parent = PropositionTreeUtil.findParentPropositionNode(root, selectedpropKey);
178            if (parent != null) {
179                List<Node<RuleEditorTreeNode, String>> children = parent.getChildren();
180                for (int index = 0; index < children.size(); index++) {
181                    Node<RuleEditorTreeNode, String> child = children.get(index);
182                    if (propKeyMatches(child, selectedpropKey)) {
183                        PropositionEditor prop = child.getData().getProposition();
184                        propositionToToggleEdit = prop;
185                        newEditMode = !prop.isEditMode();
186                        break;
187                    } else {
188                        child.getData().getProposition().setEditMode(false);
189                    }
190                }
191            }
192    
193            PropositionTreeUtil.resetEditModeOnPropositionTree(ruleEditor);
194            if (propositionToToggleEdit != null) {
195                propositionToToggleEdit.setEditMode(newEditMode);
196                //refresh the tree
197                viewHelper.refreshInitTrees(ruleEditor);
198            }
199    
200            PropositionEditor proposition = PropositionTreeUtil.getProposition(ruleEditor);
201            if (!PropositionType.COMPOUND.getCode().equalsIgnoreCase(proposition.getPropositionTypeCode())) {
202    
203                String propositionTypeId = proposition.getTypeId();
204                if (propositionTypeId == null) {
205                    proposition.setType(null);
206                } else {
207    
208                    KrmsTypeDefinition type = KrmsRepositoryServiceLocator.getKrmsTypeRepositoryService().getTypeById(propositionTypeId);
209                    if (type != null) {
210                        proposition.setType(type.getName());
211                    }
212                }
213    
214            }
215    
216            return getUIFModelAndView(form);
217        }
218    
219        @RequestMapping(params = "methodToCall=addProposition")
220        public ModelAndView addProposition(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
221                                           HttpServletRequest request, HttpServletResponse response) throws Exception {
222    
223            RuleEditor ruleEditor = getRuleEditor(form);
224            String selectedPropKey = ruleEditor.getSelectedKey();
225    
226            // find parent
227            Node<RuleEditorTreeNode, String> root = ruleEditor.getEditTree().getRootElement();
228            Node<RuleEditorTreeNode, String> parent = PropositionTreeUtil.findParentPropositionNode(root, selectedPropKey);
229    
230            PropositionTreeUtil.resetEditModeOnPropositionTree(ruleEditor);
231            RuleViewHelperService viewHelper = this.getViewHelper(form);
232    
233            // add new child at appropriate spot
234            if (parent != null) {
235                List<Node<RuleEditorTreeNode, String>> children = parent.getChildren();
236                for (int index = 0; index < children.size(); index++) {
237                    Node<RuleEditorTreeNode, String> child = children.get(index);
238    
239                    // if our selected node is a simple proposition, add a new one after
240                    if (propKeyMatches(child, selectedPropKey)) {
241                        // handle special case of adding to a lone simple proposition.
242                        // in this case, we need to change the root level proposition to a compound proposition
243                        // move the existing simple proposition as the first compound component,
244                        // then add a new blank simple prop as the second compound component.
245                        PropositionEditor blank = null;
246                        if (parent.equals(root) &&
247                                (isSimpleNode(child.getNodeType()))) {
248    
249                            // create a new compound proposition
250                            blank = viewHelper.createCompoundPropositionBoStub(child.getData().getProposition(), true);
251                            blank.setDescription(KRMSConstants.PROP_COMP_DEFAULT_DESCR);
252                            // don't set compound.setEditMode(true) as the Simple Prop in the compound prop is the only prop in edit mode
253                            ruleEditor.setProposition(blank);
254                        }
255                        // handle regular case of adding a simple prop to an existing compound prop
256                        else if (!parent.equals(root)){
257    
258                            // build new Blank Proposition
259                            blank = viewHelper.createSimplePropositionBoStub(child.getData().getProposition());
260                            //add it to the parent
261                            PropositionEditor parentProp = parent.getData().getProposition();
262                            parentProp.getCompoundEditors().add(((index / 2) + 1), blank);
263                        } else {
264                            return getUIFModelAndView(form);
265                        }
266                        this.getViewHelper(form).refreshInitTrees(ruleEditor);
267                        if(blank!=null){
268                            ruleEditor.setSelectedKey(blank.getKey());
269                        }else{
270                            ruleEditor.setSelectedKey(null);
271                        }
272                        break;
273                    }
274                }
275            } else {
276                // special case, if root has no children, add a new simple proposition
277                // todo: how to add compound proposition. - just add another to the firs simple
278                if (root.getChildren().isEmpty()) {
279                    PropositionEditor blank = viewHelper.createSimplePropositionBoStub(null);
280                    blank.setRuleId(ruleEditor.getId());
281                    ruleEditor.setPropId(blank.getId());
282                    ruleEditor.setProposition(blank);
283                    this.getViewHelper(form).refreshInitTrees(ruleEditor);
284                }
285            }
286            return getUIFModelAndView(form);
287        }
288    
289        private boolean propKeyMatches(Node<RuleEditorTreeNode, String> node, String propKey) {
290            if (propKey != null && node != null && node.getData() != null && propKey.equalsIgnoreCase(node.getData().getProposition().getKey())) {
291                return true;
292            }
293            return false;
294        }
295    
296        /**
297         * This method return the index of the position of the child that matches the id
298         *
299         * @param parent
300         * @param propKey
301         * @return index if found, -1 if not found
302         */
303        private int findChildIndex(Node<RuleEditorTreeNode, String> parent, String propKey) {
304            int index;
305            List<Node<RuleEditorTreeNode, String>> children = parent.getChildren();
306            for (index = 0; index < children.size(); index++) {
307                Node<RuleEditorTreeNode, String> child = children.get(index);
308                // if our selected node is a simple proposition, add a new one after
309                if (propKeyMatches(child, propKey)) {
310                    return index;
311                }
312            }
313            return -1;
314        }
315    
316        @RequestMapping(params = "methodToCall=movePropositionUp")
317        public ModelAndView movePropositionUp(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
318                                              HttpServletRequest request, HttpServletResponse response)
319                throws Exception {
320            moveSelectedProposition(form, true);
321    
322            return getUIFModelAndView(form);
323        }
324    
325        @RequestMapping(params = "methodToCall=movePropositionDown")
326        public ModelAndView movePropositionDown(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
327                                                HttpServletRequest request, HttpServletResponse response)
328                throws Exception {
329            moveSelectedProposition(form, false);
330    
331            return getUIFModelAndView(form);
332        }
333    
334        private void moveSelectedProposition(UifFormBase form, boolean up) {
335    
336            /* Rough algorithm for moving a node up.
337             *
338             * find the following:
339             *   node := the selected node
340             *   parent := the selected node's parent, its containing node (via when true or when false relationship)
341             *   parentsOlderCousin := the parent's level-order predecessor (sibling or cousin)
342             *
343             */
344            RuleEditor ruleEditor = getRuleEditor(form);
345            String selectedPropKey = ruleEditor.getSelectedKey();
346    
347            // find parent
348            Node<RuleEditorTreeNode, String> parent = PropositionTreeUtil.findParentPropositionNode(ruleEditor.getEditTree().getRootElement(), selectedPropKey);
349    
350            // add new child at appropriate spot
351            if (parent != null) {
352                List<Node<RuleEditorTreeNode, String>> children = parent.getChildren();
353                for (int index = 0; index < children.size(); index++) {
354                    Node<RuleEditorTreeNode, String> child = children.get(index);
355                    // if our selected node is a simple proposition, add a new one after
356                    if (propKeyMatches(child, selectedPropKey) &&
357                            (isSimpleNode(child.getNodeType()) || (RuleEditorTreeNode.COMPOUND_NODE_TYPE.equalsIgnoreCase(child.getNodeType())))) {
358    
359                        //remove it from its current spot
360                        PropositionEditor parentProp = parent.getData().getProposition();
361                        PropositionEditor workingProp = parentProp.getCompoundEditors().remove(index / 2);
362                        if ((index > 0) && up) {
363                            parentProp.getCompoundEditors().add((index / 2) - 1, workingProp);
364                        } else if ((index < (children.size() - 1) && !up)) {
365                            parentProp.getCompoundEditors().add((index / 2) + 1, workingProp);
366                        }
367                        // redisplay the tree (editMode = true)
368                        this.getViewHelper(form).refreshInitTrees(ruleEditor);
369                        break;
370                    }
371                }
372            }
373        }
374    
375        public boolean isSimpleNode(String nodeType) {
376            if (KSSimplePropositionNode.NODE_TYPE.equalsIgnoreCase(nodeType) ||
377                    KSSimplePropositionEditNode.NODE_TYPE.equalsIgnoreCase(nodeType)) {
378                return true;
379            }
380            return false;
381        }
382    
383        @RequestMapping(params = "methodToCall=movePropositionLeft")
384        public ModelAndView movePropositionLeft(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
385                                                HttpServletRequest request, HttpServletResponse response)
386                throws Exception {
387    
388            /* Rough algorithm for moving a node up.
389             *
390             * find the following:
391             *   node := the selected node
392             *   parent := the selected node's parent, its containing node (via when true or when false relationship)
393             *   parentsOlderCousin := the parent's level-order predecessor (sibling or cousin)
394             *
395             */
396            RuleEditor ruleEditor = getRuleEditor(form);
397            String selectedpropKey = ruleEditor.getSelectedKey();
398    
399            // find agendaEditor.getAgendaItemLine().getRule().getPropositionTree().getRootElement()parent
400            Node<RuleEditorTreeNode, String> root = ruleEditor.getEditTree().getRootElement();
401            Node<RuleEditorTreeNode, String> parent = PropositionTreeUtil.findParentPropositionNode(root, selectedpropKey);
402            if ((parent != null) && (RuleEditorTreeNode.COMPOUND_NODE_TYPE.equalsIgnoreCase(parent.getNodeType()))) {
403                Node<RuleEditorTreeNode, String> granny = PropositionTreeUtil.findParentPropositionNode(root, parent.getData().getProposition().getKey());
404                if (!granny.equals(root)) {
405                    int oldIndex = findChildIndex(parent, selectedpropKey);
406                    int newIndex = findChildIndex(granny, parent.getData().getProposition().getKey());
407                    if (oldIndex >= 0 && newIndex >= 0) {
408                        PropositionEditor prop = parent.getData().getProposition().getCompoundEditors().remove(oldIndex / 2);
409                        granny.getData().getProposition().getCompoundEditors().add((newIndex / 2) + 1, prop);
410                        this.getViewHelper(form).refreshInitTrees(ruleEditor);
411                    }
412                }
413                // TODO: do we allow moving up to the root?
414                // we could add a new top level compound node, with current root as 1st child,
415                // and move the node to the second child.
416    
417            }
418            return getUIFModelAndView(form);
419        }
420    
421        @RequestMapping(params = "methodToCall=movePropositionRight")
422        public ModelAndView movePropositionRight(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
423                                                 HttpServletRequest request, HttpServletResponse response)
424                throws Exception {
425            /* Rough algorithm for moving a node Right
426             * if the selected node is above a compound proposition, move it into the compound proposition as the first child
427             * if the node is above a simple proposition, do nothing.
428             * find the following:
429             *   node := the selected node
430             *   parent := the selected node's parent, its containing node
431             *   nextSibling := the node after the selected node
432             *
433             */
434            RuleEditor ruleEditor = getRuleEditor(form);
435            String selectedpropKey = ruleEditor.getSelectedKey();
436    
437            // find parent
438            Node<RuleEditorTreeNode, String> parent = PropositionTreeUtil.findParentPropositionNode(
439                    ruleEditor.getEditTree().getRootElement(), selectedpropKey);
440            if (parent != null) {
441                int index = findChildIndex(parent, selectedpropKey);
442                // if we are the last child, do nothing, otherwise
443                if (index >= 0 && index + 1 < parent.getChildren().size()) {
444                    Node<RuleEditorTreeNode, String> nextSibling = parent.getChildren().get(index + 2);
445                    // if selected node above a compound node, move it into it as first child
446                    if (RuleEditorTreeNode.COMPOUND_NODE_TYPE.equalsIgnoreCase(nextSibling.getNodeType())) {
447                        // remove selected node from it's current spot
448                        PropositionEditor prop = parent.getData().getProposition().getCompoundEditors().remove(index / 2);
449                        // add it to it's siblings children
450                        nextSibling.getData().getProposition().getCompoundEditors().add(0, prop);
451                        this.getViewHelper(form).refreshInitTrees(ruleEditor);
452                    }
453                }
454            }
455            return getUIFModelAndView(form);
456        }
457    
458        /**
459         * introduces a new compound proposition between the selected proposition and its parent.
460         * Additionally, it puts a new blank simple proposition underneath the compound proposition
461         * as a sibling to the selected proposition.
462         */
463        @RequestMapping(params = "methodToCall=togglePropositionSimpleCompound")
464        public ModelAndView togglePropositionSimpleCompound(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
465                                                            HttpServletRequest request, HttpServletResponse response)
466                throws Exception {
467    
468            RuleEditor ruleEditor = getRuleEditor(form);
469            String selectedPropKey = ruleEditor.getSelectedKey();
470    
471            PropositionTreeUtil.resetEditModeOnPropositionTree(ruleEditor);
472            RuleViewHelperService viewHelper = this.getViewHelper(form);
473    
474            if (!StringUtils.isBlank(selectedPropKey)) {
475                // find parent
476                Node<RuleEditorTreeNode, String> parent = PropositionTreeUtil.findParentPropositionNode(
477                        ruleEditor.getEditTree().getRootElement(), selectedPropKey);
478                if (parent != null) {
479    
480                    int index = findChildIndex(parent, selectedPropKey);
481    
482                    PropositionEditor propBo = parent.getChildren().get(index).getData().getProposition();
483    
484                    // create a new compound proposition
485                    PropositionEditor compound = viewHelper.createCompoundPropositionBoStub(propBo, true);
486                    compound.setDescription(KRMSConstants.PROP_COMP_DEFAULT_DESCR);
487                    compound.setEditMode(false);
488    
489                    if (parent.getData() == null) { // SPECIAL CASE: this is the only proposition in the tree
490                        ruleEditor.setProposition(compound);
491                    } else {
492                        PropositionEditor parentBo = parent.getData().getProposition();
493                        List<PropositionEditor> siblings = parentBo.getCompoundEditors();
494    
495                        int propIndex = -1;
496                        for (int i = 0; i < siblings.size(); i++) {
497                            if (propBo.getKey().equals(siblings.get(i).getKey())) {
498                                propIndex = i;
499                                break;
500                            }
501                        }
502    
503                        parentBo.getCompoundEditors().set(propIndex, compound);
504                        compound.getCompoundEditors().get(1).setEditMode(true);
505                        ruleEditor.setSelectedKey(compound.getCompoundComponents().get(1).getId());
506                    }
507                }
508            }
509    
510            viewHelper.refreshInitTrees(ruleEditor);
511            return getUIFModelAndView(form);
512        }
513    
514        @RequestMapping(params = "methodToCall=pasteProposition")
515        public ModelAndView pasteProposition(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
516                                             HttpServletRequest request, HttpServletResponse response)
517                throws Exception {
518    
519            boolean cutAction = true;
520            RuleEditor ruleEditor = getRuleEditor(form);
521            RuleViewHelperService viewHelper = this.getViewHelper(form);
522    
523            // get selected id
524            String selectedPropKey = ruleEditor.getSelectedKey();
525            if (StringUtils.isBlank(selectedPropKey)) {
526                return getUIFModelAndView(form);
527            }
528    
529            // get the id to move
530            String movePropKey = ruleEditor.getCutKey();
531            if (StringUtils.isBlank(movePropKey)) {
532                movePropKey = ruleEditor.getCopyKey();
533                cutAction = false;
534            }
535    
536            // check if selected and move is not the same
537            if (StringUtils.isNotBlank(movePropKey) && !selectedPropKey.equals(movePropKey)) {
538    
539                Node<RuleEditorTreeNode, String> root = ruleEditor.getEditTree().getRootElement();
540                PropositionEditor newParent = getNewParent(viewHelper, ruleEditor, selectedPropKey, root);
541                PropositionEditor oldParent = PropositionTreeUtil.findParentPropositionNode(root, movePropKey).getData().getProposition();
542                PropositionEditor workingProp = null;
543    
544                // cut or copy from old
545                if (oldParent != null) {
546                    List<PropositionEditor> children = oldParent.getCompoundEditors();
547                    for (int index = 0; index < children.size(); index++) {
548                        if (movePropKey.equalsIgnoreCase(children.get(index).getKey())) {
549                            if (cutAction) {
550                                workingProp = oldParent.getCompoundEditors().remove(index);
551                            } else {
552                                workingProp = viewHelper.copyProposition(oldParent.getCompoundEditors().get(index));
553                            }
554                            break;
555                        }
556                    }
557                }
558    
559                // add to new and refresh the tree
560                addProposition(selectedPropKey, newParent, workingProp);
561                viewHelper.refreshInitTrees(ruleEditor);
562            }
563    
564            // call the super method to avoid the agenda tree being reloaded from the db
565            return getUIFModelAndView(form);
566        }
567    
568        private PropositionEditor getNewParent(RuleViewHelperService viewHelper, RuleEditor ruleEditor, String selectedpropKey, Node<RuleEditorTreeNode, String> root) {
569            Node<RuleEditorTreeNode, String> parentNode = PropositionTreeUtil.findParentPropositionNode(root, selectedpropKey);
570            PropositionEditor newParent;
571            if (parentNode.equals(root)) {
572                // special case
573                // build new top level compound proposition,
574                // add existing as first child
575                // then paste cut node as 2nd child
576                newParent = viewHelper.createCompoundPropositionBoStub(
577                        root.getChildren().get(0).getData().getProposition(), false);
578                newParent.setEditMode(true);
579                ruleEditor.setProposition(newParent);
580            } else {
581                newParent = parentNode.getData().getProposition();
582            }
583            return newParent;
584        }
585    
586        private void addProposition(String selectedpropKey, PropositionEditor newParent, PropositionEditor workingProp) {
587            // add to new
588            if (newParent != null && workingProp != null) {
589                List<PropositionEditor> children = newParent.getCompoundEditors();
590                for (int index = 0; index < children.size(); index++) {
591                    if (selectedpropKey.equalsIgnoreCase(children.get(index).getKey())) {
592                        children.add(index + 1, workingProp);
593                        break;
594                    }
595                }
596            }
597        }
598    
599        @RequestMapping(params = "methodToCall=deleteProposition")
600        public ModelAndView deleteProposition(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
601                                              HttpServletRequest request, HttpServletResponse response)
602                throws Exception {
603            RuleEditor ruleEditor = getRuleEditor(form);
604            String selectedpropKey = ruleEditor.getSelectedKey();
605            Node<RuleEditorTreeNode, String> root = ruleEditor.getEditTree().getRootElement();
606    
607            Node<RuleEditorTreeNode, String> parentNode = PropositionTreeUtil.findParentPropositionNode(root, selectedpropKey);
608    
609            // what if it is the root?
610            if (parentNode != null && parentNode.getData() != null) { // it is not the root as there is a parent w/ a prop
611                PropositionEditor parent = parentNode.getData().getProposition();
612                if (parent != null) {
613                    List<PropositionEditor> children = (List<PropositionEditor>) parent.getCompoundComponents();
614                    for (int index = 0; index < children.size(); index++) {
615                        if (selectedpropKey.equalsIgnoreCase(children.get(index).getKey())) {
616                            parent.getCompoundComponents().remove(index);
617                            break;
618                        }
619                    }
620                }
621            } else { // no parent, it is the root
622                parentNode.getChildren().clear();
623                ruleEditor.getEditTree().setRootElement(null);
624                ruleEditor.setPropId(null);
625                ruleEditor.setProposition(null);
626            }
627    
628            this.getViewHelper(form).refreshInitTrees(ruleEditor);
629            return getUIFModelAndView(form);
630        }
631    
632        @RequestMapping(params = "methodToCall=updateCompoundOperator")
633        public ModelAndView updateCompoundOperator(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
634                                                   HttpServletRequest request, HttpServletResponse response)
635                throws Exception {
636    
637            RuleViewHelperService viewHelper = this.getViewHelper(form);
638            RuleEditor ruleEditor = getRuleEditor(form);
639            String selectedpropKey = ruleEditor.getSelectedKey();
640            Node<RuleEditorTreeNode, String> parentNode = PropositionTreeUtil.findParentPropositionNode(ruleEditor.getEditTree().getRootElement(), selectedpropKey);
641            PropositionEditor parent = parentNode.getData().getProposition();
642    
643            PropositionEditor proposition = PropositionTreeUtil.findProposition(parentNode, selectedpropKey);
644            PropositionTreeUtil.setTypeForCompoundOpCode(parent, proposition.getCompoundOpCode());
645            parent.setDescription(viewHelper.resetDescription(parent));
646    
647            viewHelper.refreshInitTrees(ruleEditor);
648    
649            return getUIFModelAndView(form);
650        }
651    
652        @RequestMapping(params = "methodToCall=updateProposition")
653        public ModelAndView updateProposition(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
654                                              HttpServletRequest request, HttpServletResponse response)
655                throws Exception {
656            RuleEditor ruleEditor = getRuleEditor(form);
657            PropositionTreeUtil.resetNewProp((PropositionEditor) ruleEditor.getProposition());
658    
659            EnrolPropositionEditor proposition = (EnrolPropositionEditor) PropositionTreeUtil.getProposition(ruleEditor);
660    
661            //Resolve term if single course
662            //Reset the description
663            this.getViewHelper(form).resetDescription(proposition);
664    
665            //Remove the edit mode
666            PropositionTreeUtil.resetEditModeOnPropositionTree(ruleEditor);
667            this.getViewHelper(form).refreshInitTrees(ruleEditor);
668    
669            return getUIFModelAndView(form);
670        }
671    
672        @RequestMapping(params = "methodToCall=updateRule")
673        public ModelAndView updateRule(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
674                                       HttpServletRequest request, HttpServletResponse response)
675                throws Exception {
676    
677            MaintenanceDocumentForm document = (MaintenanceDocumentForm) form;
678            RuleManagementWrapper ruleWrapper = (RuleManagementWrapper) document.getDocument().getNewMaintainableObject().getDataObject();
679    
680            RuleEditor ruleEditor = getRuleEditor(form);
681    
682            this.getViewHelper(form).refreshViewTree(ruleEditor);
683            PropositionTreeUtil.resetNewProp((PropositionEditor) ruleEditor.getProposition());
684    
685            PropositionTreeUtil.resetEditModeOnPropositionTree(ruleEditor);
686            PropositionEditor proposition = PropositionTreeUtil.getProposition(ruleEditor);
687            this.getViewHelper(form).resetDescription(proposition);
688    
689    
690            //Replace edited rule with existing rule.
691            for (AgendaEditor agendaEditor : ruleWrapper.getAgendas()) {
692    
693                List<RuleEditor> ruleEditors = agendaEditor.getRuleEditors();
694                RuleEditor existingRule = AgendaUtilities.getSelectedRuleEditorByType(ruleEditors, ruleEditor.getTypeId());
695                if (existingRule != null) {
696                    ruleEditors.remove(existingRule);
697                }
698                ruleEditors.add(ruleEditor);
699            }
700    
701            form.getActionParameters().put(UifParameters.NAVIGATE_TO_PAGE_ID, "KRMS-AgendaMaintenance-Page");
702            return super.navigate(form, result, request, response);
703        }
704    
705        @RequestMapping(params = "methodToCall=updatePreview")
706        public ModelAndView updatePreview(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
707                                          HttpServletRequest request, HttpServletResponse response)
708                throws Exception {
709            RuleEditor ruleEditor = getRuleEditor(form);
710            ruleEditor.setSelectedTab("1");
711    
712            parseRuleExpression(ruleEditor);
713    
714            this.getViewHelper(form).refreshInitTrees(ruleEditor);
715            return getUIFModelAndView(form);
716        }
717    
718        @RequestMapping(params = "methodToCall=onTabSelect")
719        public ModelAndView onEditTabSelect(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
720                                          HttpServletRequest request, HttpServletResponse response)
721                throws Exception {
722    
723            RuleEditor ruleEditor = getRuleEditor(form);
724            parseRuleExpression(ruleEditor);
725    
726            this.getViewHelper(form).refreshInitTrees(ruleEditor);
727            return getUIFModelAndView(form);
728        }
729    
730        private void parseRuleExpression(RuleEditor ruleEditor) {
731            RuleLogicExpressionParser ruleLogicExpressionParser = new RuleLogicExpressionParser();
732            ruleLogicExpressionParser.setExpression(ruleEditor.getLogicArea());
733            List<String> propsAlpha = this.getPropositionKeys(new ArrayList<String>(), (PropositionEditor) ruleEditor.getProposition());
734    
735            //validate the expression
736            List<String> errorMessages = new ArrayList<String>();
737            boolean validExpression = ruleLogicExpressionParser.validateExpression(errorMessages, propsAlpha);
738    
739            //show errors and don't change anything else
740            if (!validExpression) {
741                for (int i = 0; i < errorMessages.size(); i++) {
742                    GlobalVariables.getMessageMap().putError("document.newMaintainableObject.dataObject.logicArea", errorMessages.get(i));
743                }
744                // reload page1
745                return;
746            }
747    
748            ruleEditor.setProposition(ruleLogicExpressionParser.parseExpressionIntoRule(ruleEditor));
749        }
750    
751        private List<String> getPropositionKeys(List<String> propositionKeys, PropositionEditor propositionEditor) {
752            propositionKeys.add(propositionEditor.getKey());
753            if (propositionEditor.getCompoundComponents() != null) {
754                for (PropositionEditor child : propositionEditor.getCompoundEditors()) {
755                    this.getPropositionKeys(propositionKeys, child);
756                }
757            }
758            return propositionKeys;
759        }
760    
761        @RequestMapping(params = "methodToCall=cancelEditProposition")
762        public ModelAndView cancelEditProposition(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
763                                                  HttpServletRequest request, HttpServletResponse response)
764                throws Exception {
765    
766            RuleEditor ruleEditor = getRuleEditor(form);
767            PropositionEditor proposition = (PropositionEditor) ruleEditor.getProposition();
768    
769            //Reset the editing tree.
770            PropositionTreeUtil.cancelNewProp(proposition);
771            PropositionTreeUtil.resetEditModeOnPropositionTree(ruleEditor);
772            this.getViewHelper(form).refreshInitTrees(ruleEditor);
773    
774            return getUIFModelAndView(form);
775        }
776    
777        @RequestMapping(params = "methodToCall=cancelEditRule")
778        public ModelAndView cancelEditRule(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
779                                           HttpServletRequest request, HttpServletResponse response)
780                throws Exception {
781    
782            RuleEditor ruleEditor = getRuleEditor(form);
783            PropositionEditor proposition = (PropositionEditor) ruleEditor.getProposition();
784    
785            //Reset the editing tree.
786            if(proposition!=null){
787                PropositionTreeUtil.cancelNewProp(proposition);
788            }
789            PropositionTreeUtil.resetEditModeOnPropositionTree(ruleEditor);
790    
791            form.getActionParameters().put(UifParameters.NAVIGATE_TO_PAGE_ID, "KRMS-AgendaMaintenance-Page");
792            return super.navigate(form, result, request, response);
793        }
794    
795        @RequestMapping(params = "methodToCall=updatePropositionType")
796        public ModelAndView updatePropositionType(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
797                                                  HttpServletRequest request, HttpServletResponse response)
798                throws Exception {
799    
800            PropositionEditor proposition = PropositionTreeUtil.getProposition(this.getRuleEditor(form));
801            configureProposition(form, proposition);
802    
803            return getUIFModelAndView(form);
804        }
805    
806        private void configureProposition(UifFormBase form, PropositionEditor proposition) {
807    
808            if (proposition != null) {
809    
810                if (PropositionType.COMPOUND.getCode().equalsIgnoreCase(proposition.getPropositionTypeCode())) {
811                    return;
812                }
813    
814                String propositionTypeId = proposition.getTypeId();
815                if (propositionTypeId == null) {
816                    proposition.setType(null);
817                    return;
818                }
819    
820                KrmsTypeDefinition type = KrmsRepositoryServiceLocator.getKrmsTypeRepositoryService().getTypeById(propositionTypeId);
821                if (type != null) {
822                    proposition.setType(type.getName());
823                }
824            }
825        }
826    
827        /**
828         * Test method for a controller that invokes a dialog lightbox.
829         *
830         * @param form     - test form
831         * @param result   - Spring form binding result
832         * @param request  - http request
833         * @param response - http response
834         * @return
835         * @throws Exception
836         */
837        @RequestMapping(params = "methodToCall=compareRules")
838        public ModelAndView compareRules(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
839                                         HttpServletRequest request, HttpServletResponse response) throws Exception {
840    
841            MaintenanceDocumentForm document = (MaintenanceDocumentForm) form;
842            Object dataObject = document.getDocument().getNewMaintainableObject().getDataObject();
843            if (dataObject instanceof RuleManagementWrapper) {
844                RuleManagementWrapper ruleWrapper = (RuleManagementWrapper) dataObject;
845                String ruleId = document.getActionParamaterValue("ruleKey");
846                RuleEditor ruleEditor = null;
847                if ((ruleId != null) && (StringUtils.isNotBlank(ruleId))) {
848                    //Get a specific ruleEditor based on the ruleId.
849                    ruleEditor = AgendaUtilities.getSelectedRuleEditor(ruleWrapper, ruleId);
850                } else {
851                    //Get the current editing ruleEditor.
852                    ruleEditor = ruleWrapper.getRuleEditor();
853                }
854    
855                //Build the compare rule tree
856                ruleWrapper.setCompareTree(this.getViewHelper(form).buildCompareTree(ruleEditor, ruleWrapper.getRefObjectId()));
857    
858            }
859    
860            // redirect back to client to display lightbox
861            return showDialog("compareRuleLightBox", form, request, response);
862        }
863    
864        protected RuleViewHelperService getViewHelper(UifFormBase form) {
865            return (RuleViewHelperService) KSControllerHelper.getViewHelperService(form);
866        }
867    //
868        @RequestMapping(params = "methodToCall=getSelectedKey")
869        public ModelAndView getSelectedKey(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
870                                           HttpServletRequest request, HttpServletResponse response) throws Exception {
871    
872            RuleViewHelperService viewHelper = this.getViewHelper(form);
873            String selectedKey = request.getParameter("selectedKey");
874    
875            RuleEditor ruleEditor = getRuleEditor(form);
876            String selectedpropKey = selectedKey;
877            ruleEditor.setSelectedKey(selectedpropKey);
878            //this.goToEditProposition()
879            return this.goToEditProposition(form,result, request, response);
880        }
881    
882    }