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 */
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.uif.component.Component;
022import org.kuali.rice.krad.uif.container.Group;
023import org.kuali.rice.krad.uif.container.LinkGroup;
024import org.kuali.rice.krad.uif.element.Action;
025import org.kuali.rice.krad.uif.field.MessageField;
026import org.kuali.rice.krad.uif.util.ComponentFactory;
027import org.kuali.rice.krad.uif.util.ComponentUtils;
028import org.kuali.rice.krad.util.GlobalVariables;
029import org.kuali.rice.krad.web.controller.MaintenanceDocumentController;
030import org.kuali.rice.krad.web.form.MaintenanceDocumentForm;
031import org.kuali.rice.krad.web.form.UifFormBase;
032import org.kuali.rice.krms.api.repository.LogicalOperator;
033import org.kuali.rice.krms.api.repository.proposition.PropositionType;
034import org.kuali.rice.krms.api.repository.type.KrmsTypeDefinition;
035import org.kuali.rice.krms.dto.AgendaEditor;
036import org.kuali.rice.krms.dto.PropositionEditor;
037import org.kuali.rice.krms.dto.RuleEditor;
038import org.kuali.rice.krms.dto.RuleManagementWrapper;
039import org.kuali.rice.krms.dto.RuleTypeInfo;
040import org.kuali.rice.krms.dto.TemplateInfo;
041import org.kuali.rice.krms.impl.repository.KrmsRepositoryServiceLocator;
042import org.kuali.rice.krms.impl.util.KRMSPropertyConstants;
043import org.kuali.rice.krms.service.RuleViewHelperService;
044import org.kuali.rice.krms.tree.RuleViewTreeBuilder;
045import org.kuali.rice.krms.util.AgendaUtilities;
046import org.kuali.student.enrollment.class1.krms.dto.EnrolPropositionEditor;
047import org.kuali.student.enrollment.class1.krms.tree.node.KSSimplePropositionEditNode;
048import org.kuali.student.enrollment.class1.krms.tree.node.KSSimplePropositionNode;
049import org.kuali.rice.krms.tree.node.RuleEditorTreeNode;
050import org.kuali.rice.krms.util.PropositionTreeUtil;
051import org.kuali.rice.krms.util.RuleLogicExpressionParser;
052import org.kuali.student.enrollment.uif.util.KSControllerHelper;
053import org.kuali.student.krms.KRMSConstants;
054import org.springframework.validation.BindingResult;
055import org.springframework.web.bind.annotation.ModelAttribute;
056import org.springframework.web.bind.annotation.RequestMapping;
057import org.springframework.web.servlet.ModelAndView;
058
059import javax.servlet.http.HttpServletRequest;
060import javax.servlet.http.HttpServletResponse;
061import java.util.ArrayList;
062import java.util.List;
063
064/**
065 * Controller for the Test UI Page
066 *
067 * @author Kuali Rice Team (rice.collab@kuali.org)
068 */
069public 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}