Coverage Report - org.kuali.student.lum.program.client.requirements.ProgramRequirementsSummaryView
 
Classes in this File Line Coverage Branch Coverage Complexity
ProgramRequirementsSummaryView
0%
0/226
0%
0/76
2.089
ProgramRequirementsSummaryView$1
0%
0/5
0%
0/2
2.089
ProgramRequirementsSummaryView$10
0%
0/15
0%
0/4
2.089
ProgramRequirementsSummaryView$10$1
0%
0/3
N/A
2.089
ProgramRequirementsSummaryView$10$2
0%
0/9
N/A
2.089
ProgramRequirementsSummaryView$11
0%
0/3
N/A
2.089
ProgramRequirementsSummaryView$12
0%
0/5
0%
0/2
2.089
ProgramRequirementsSummaryView$2
0%
0/5
0%
0/2
2.089
ProgramRequirementsSummaryView$3
0%
0/3
N/A
2.089
ProgramRequirementsSummaryView$4
0%
0/3
N/A
2.089
ProgramRequirementsSummaryView$5
0%
0/5
N/A
2.089
ProgramRequirementsSummaryView$5$1
0%
0/6
N/A
2.089
ProgramRequirementsSummaryView$6
0%
0/9
N/A
2.089
ProgramRequirementsSummaryView$6$1
0%
0/4
N/A
2.089
ProgramRequirementsSummaryView$7
0%
0/3
N/A
2.089
ProgramRequirementsSummaryView$7$1
0%
0/4
N/A
2.089
ProgramRequirementsSummaryView$8
0%
0/3
N/A
2.089
ProgramRequirementsSummaryView$9
0%
0/7
0%
0/4
2.089
ProgramRequirementsSummaryView$9$1
0%
0/6
0%
0/2
2.089
ProgramRequirementsSummaryView$ProgramReqDialogView
0%
0/1
N/A
2.089
 
 1  
 package org.kuali.student.lum.program.client.requirements;
 2  
 
 3  
 import java.util.HashMap;
 4  
 import java.util.HashSet;
 5  
 import java.util.LinkedHashMap;
 6  
 import java.util.List;
 7  
 import java.util.Map;
 8  
 import java.util.Set;
 9  
 
 10  
 import org.kuali.student.common.ui.client.application.Application;
 11  
 import org.kuali.student.common.ui.client.application.KSAsyncCallback;
 12  
 import org.kuali.student.common.ui.client.configurable.mvc.FieldDescriptor;
 13  
 import org.kuali.student.common.ui.client.configurable.mvc.SectionTitle;
 14  
 import org.kuali.student.common.ui.client.configurable.mvc.layouts.BasicLayout;
 15  
 import org.kuali.student.common.ui.client.configurable.mvc.sections.GroupSection;
 16  
 import org.kuali.student.common.ui.client.configurable.mvc.views.VerticalSectionView;
 17  
 import org.kuali.student.common.ui.client.mvc.Callback;
 18  
 import org.kuali.student.common.ui.client.mvc.Controller;
 19  
 import org.kuali.student.common.ui.client.mvc.DataModel;
 20  
 import org.kuali.student.common.ui.client.mvc.DataModelDefinition;
 21  
 import org.kuali.student.common.ui.client.mvc.Model;
 22  
 import org.kuali.student.common.ui.client.mvc.ModelProvider;
 23  
 import org.kuali.student.common.ui.client.mvc.ModelRequestCallback;
 24  
 import org.kuali.student.common.ui.client.mvc.View;
 25  
 import org.kuali.student.common.ui.client.service.MetadataRpcService;
 26  
 import org.kuali.student.common.ui.client.service.MetadataRpcServiceAsync;
 27  
 import org.kuali.student.common.ui.client.widgets.KSButton;
 28  
 import org.kuali.student.common.ui.client.widgets.KSButtonAbstract;
 29  
 import org.kuali.student.common.ui.client.widgets.KSLabel;
 30  
 import org.kuali.student.common.ui.client.widgets.KSLightBox;
 31  
 import org.kuali.student.common.ui.client.widgets.buttongroups.ButtonEnumerations;
 32  
 import org.kuali.student.common.ui.client.widgets.dialog.ConfirmationDialog;
 33  
 import org.kuali.student.common.ui.client.widgets.field.layout.button.ActionCancelGroup;
 34  
 import org.kuali.student.common.ui.client.widgets.field.layout.element.MessageKeyInfo;
 35  
 import org.kuali.student.common.ui.client.widgets.field.layout.element.SpanPanel;
 36  
 import org.kuali.student.common.ui.client.widgets.progress.BlockingTask;
 37  
 import org.kuali.student.common.ui.client.widgets.progress.KSBlockingProgressIndicator;
 38  
 import org.kuali.student.common.ui.client.widgets.rules.RulePreviewWidget;
 39  
 import org.kuali.student.common.ui.client.widgets.rules.RulesUtil;
 40  
 import org.kuali.student.core.assembly.data.ConstraintMetadata;
 41  
 import org.kuali.student.core.assembly.data.Data;
 42  
 import org.kuali.student.core.assembly.data.Metadata;
 43  
 import org.kuali.student.core.assembly.data.QueryPath;
 44  
 import org.kuali.student.core.dto.RichTextInfo;
 45  
 import org.kuali.student.core.statement.dto.ReqCompFieldInfo;
 46  
 import org.kuali.student.core.statement.dto.ReqComponentInfo;
 47  
 import org.kuali.student.core.statement.dto.StatementOperatorTypeKey;
 48  
 import org.kuali.student.core.statement.dto.StatementTreeViewInfo;
 49  
 import org.kuali.student.core.statement.dto.StatementTypeInfo;
 50  
 import org.kuali.student.core.validation.dto.ValidationResultInfo;
 51  
 import org.kuali.student.lum.common.client.widgets.CluSetDetailsWidget;
 52  
 import org.kuali.student.lum.common.client.widgets.CluSetRetriever;
 53  
 import org.kuali.student.lum.common.client.widgets.CluSetRetrieverImpl;
 54  
 import org.kuali.student.lum.program.client.ProgramConstants;
 55  
 import org.kuali.student.lum.program.client.ProgramSections;
 56  
 import org.kuali.student.lum.program.client.properties.ProgramProperties;
 57  
 import org.kuali.student.lum.program.client.widgets.EditableHeader;
 58  
 import org.kuali.student.lum.program.dto.ProgramRequirementInfo;
 59  
 
 60  
 import com.google.gwt.core.client.GWT;
 61  
 import com.google.gwt.event.dom.client.ClickEvent;
 62  
 import com.google.gwt.event.dom.client.ClickHandler;
 63  
 import com.google.gwt.event.shared.HandlerManager;
 64  
 import com.google.gwt.user.client.Window;
 65  
 import com.google.gwt.user.client.ui.FlowPanel;
 66  
 import com.google.gwt.user.client.ui.Widget;
 67  
 
 68  0
 public class ProgramRequirementsSummaryView extends VerticalSectionView {
 69  
 
 70  0
     private MetadataRpcServiceAsync metadataServiceAsync = GWT.create(MetadataRpcService.class);
 71  0
     private static CluSetRetriever cluSetRetriever = new CluSetRetrieverImpl();
 72  
 
 73  
     //view's widgets
 74  0
     private FlowPanel layout = new FlowPanel();
 75  0
     private ActionCancelGroup actionCancelButtons = new ActionCancelGroup(ButtonEnumerations.SaveCancelEnum.SAVE, ButtonEnumerations.SaveCancelEnum.CANCEL);
 76  
     private BasicLayout reqCompController;
 77  0
     private FlowPanel holdFieldsPanel = new FlowPanel();
 78  
 
 79  
     //view's data
 80  
     private ProgramRequirementsViewController parentController;
 81  
     private ProgramRequirementsDataModel rules;
 82  
     private boolean isReadOnly;
 83  0
     public static int tempStmtTreeID = 9999;
 84  
     public static final String NEW_PROG_REQ_ID = "NEWPROGREQ";
 85  
     public static final String NEW_STMT_TREE_ID = "NEWSTMTTREE";
 86  
     public static final String NEW_REQ_COMP_ID = "NEWREQCOMP";
 87  
 
 88  
 
 89  
 
 90  0
     private enum ProgramReqDialogView {VIEW}
 91  
     private static final String PROG_REQ_MODEL_ID = "progReqModelId";
 92  
     private DataModel progReqData;
 93  0
     private BlockingTask gettingMetadataTask = new BlockingTask("Loading");
 94  0
     private static Metadata dialogMetadata = null;  //simple caching
 95  
 
 96  0
     private Map<String, SpanPanel> perProgramRequirementTypePanel = new LinkedHashMap<String, SpanPanel>();
 97  0
     private Map<String, KSLabel> perProgramRequirementTypeTotalCredits = new LinkedHashMap<String, KSLabel>();
 98  
 
 99  
     public ProgramRequirementsSummaryView(final ProgramRequirementsViewController parentController, HandlerManager eventBus, Enum<?> viewEnum, String name,
 100  
                                                             String modelId, boolean isReadOnly) {
 101  0
         super(viewEnum, name, modelId);
 102  0
         init(parentController, eventBus, isReadOnly);
 103  0
     }
 104  
 
 105  
     public ProgramRequirementsSummaryView(final ProgramRequirementsViewController parentController, HandlerManager eventBus, Enum<?> viewEnum, String name,
 106  
                                                             String modelId, boolean isReadOnly, EditableHeader header) {
 107  0
         super(viewEnum, name, modelId, header);
 108  0
         init(parentController, eventBus, isReadOnly);
 109  0
     }
 110  
 
 111  
     private void init(ProgramRequirementsViewController parentController, HandlerManager eventBus, boolean isReadOnly) {
 112  0
         this.parentController = parentController;
 113  0
         this.isReadOnly = isReadOnly;
 114  0
         rules = new ProgramRequirementsDataModel(eventBus);
 115  
 
 116  0
         if (!isReadOnly) {
 117  0
             setupSaveCancelButtons();
 118  
         }
 119  0
     }
 120  
 
 121  
     @Override
 122  
     public boolean isDirty() {
 123  0
         return rules.isDirty();
 124  
     }
 125  
 
 126  
     protected ProgramRequirementsDataModel getRules() {
 127  0
         return rules;
 128  
     }
 129  
 
 130  
     @Override
 131  
     public void beforeShow(final Callback<Boolean> onReadyCallback) {
 132  
 
 133  
         //load requirements from database if they haven't been loaded yet
 134  0
         if (!rules.isInitialized() || isReadOnly) {
 135  0
             rules.retrieveProgramRequirements(parentController, new Callback<Boolean>() {
 136  
                 @Override
 137  
                 public void exec(Boolean result) {
 138  0
                     if (result) {
 139  0
                         displayRules();
 140  
                     }
 141  0
                     onReadyCallback.exec(result);
 142  0
                 }
 143  
             });
 144  0
             return;
 145  
         }
 146  0
         onReadyCallback.exec(true);
 147  0
     }
 148  
 
 149  
     public void storeRules(final Callback<Boolean> callback) {
 150  0
         rules.updateProgramEntities(new Callback<List<ProgramRequirementInfo>>() {
 151  
             @Override
 152  
             public void exec(List<ProgramRequirementInfo> programReqInfos) {
 153  0
                 for (ProgramRequirementInfo programReqInfo : programReqInfos) {
 154  0
                     updateRequirementWidgets(programReqInfo);
 155  
                 }
 156  0
                 callback.exec(true);
 157  0
             }
 158  
         });
 159  0
     }
 160  
 
 161  
     public void revertRuleChanges() {
 162  0
         rules.revertRuleChanges();
 163  0
         displayRules();
 164  0
     }
 165  
 
 166  
     protected void updateRequirementWidgets(ProgramRequirementInfo programReqInfo) {
 167  0
         if (programReqInfo != null) {
 168  0
             StatementTypeInfo affectedStatementTypeInfo = rules.getStmtTypeInfo(programReqInfo.getStatement().getType());
 169  0
             SpanPanel reqPanel = perProgramRequirementTypePanel.get(affectedStatementTypeInfo.getId());
 170  
 
 171  
             //this happens if user previously deleted requirement but didn't save when moving to another section
 172  
             //add widget
 173  0
             if (reqPanel.getWidgetCount() == 0) {
 174  0
                 reqPanel.add(addProgramRequirement(reqPanel, programReqInfo));
 175  0
                 return;
 176  
             }
 177  
 
 178  
             //replace widget with a new version
 179  0
             for (int i = 0; i < reqPanel.getWidgetCount(); i++) {
 180  0
                 RulePreviewWidget rulePreviewWidget = (RulePreviewWidget)reqPanel.getWidget(i);
 181  0
                 if (rulePreviewWidget.getInternalProgReqID().equals(rules.getInternalProgReqID(programReqInfo))) {
 182  0
                         RulePreviewWidget newRulePreviewWidget = addProgramRequirement(reqPanel, programReqInfo);
 183  0
                         reqPanel.insert(newRulePreviewWidget, i);
 184  0
                         reqPanel.remove(rulePreviewWidget);
 185  0
                         break;
 186  
                 }
 187  
             }
 188  
         }
 189  0
     }
 190  
 
 191  
     public void displayRules() {
 192  0
         remove(layout);
 193  0
         layout.clear();
 194  
 
 195  
         //display 'Program Requirements' page title (don't add if read only because the section itself will display the title)
 196  0
         if (!isReadOnly) {
 197  0
             SectionTitle pageTitle = SectionTitle.generateH2Title(ProgramProperties.get().programRequirements_summaryViewPageTitle());
 198  
             //pageTitle.setStyleName("KS-Program-Requirements-Section-header");  //make the header orange
 199  0
             pageTitle.addStyleName("ks-layout-header");// change the header to green
 200  
 
 201  0
             layout.add(pageTitle);
 202  
         }
 203  
 
 204  
         //iterate and display rules for each Program Requirement type e.g. Entrance Requirements, Completion Requirements
 205  0
         Boolean firstRequirement = true;
 206  0
         perProgramRequirementTypePanel.clear();
 207  0
         for (StatementTypeInfo stmtTypeInfo : rules.getStmtTypes()) {
 208  
 
 209  
             //create and display one type of program requirement section
 210  0
             SpanPanel requirementsPanel = new SpanPanel();
 211  0
             perProgramRequirementTypePanel.put(stmtTypeInfo.getId(), requirementsPanel);
 212  0
             displayRequirementSectionForGivenType(requirementsPanel, stmtTypeInfo, firstRequirement);
 213  0
             updateTotalCreditPerType(stmtTypeInfo.getId());
 214  0
             firstRequirement = false;
 215  
 
 216  
             //now display each requirement for this Program Requirement type
 217  0
             for (ProgramRequirementInfo ruleInfo : rules.getProgReqInfo(stmtTypeInfo.getId())) {
 218  0
                 RulePreviewWidget rulePreviewWidget = addProgramRequirement(requirementsPanel, ruleInfo);
 219  0
                 requirementsPanel.add(rulePreviewWidget);
 220  0
             }
 221  0
         }
 222  
 
 223  
         //save and cancel buttons
 224  0
         if (!isReadOnly) {
 225  0
             layout.add(actionCancelButtons);
 226  
         }
 227  
 
 228  0
         addWidget(layout);
 229  0
     }
 230  
 
 231  
     private void displayRequirementSectionForGivenType(final SpanPanel requirementsPanel, final StatementTypeInfo stmtTypeInfo, boolean firstRequirement) {
 232  
 
 233  
         //display header for this Program Requirement type e.g. Entrance Requirements; make the header plural
 234  0
         SectionTitle title = SectionTitle.generateH3Title(stmtTypeInfo.getName());
 235  0
         title.setStyleName((firstRequirement ? "KS-Program-Requirements-Preview-Rule-Type-First-Header" : "KS-Program-Requirements-Preview-Rule-Type-Header"));
 236  0
         layout.add(title);
 237  
 
 238  
         //add Total Credits
 239  0
         KSLabel totalCredits = new KSLabel();
 240  0
         totalCredits.addStyleName("KS-Program-Requirements-Preview-Rule-Type-Credits");
 241  0
         perProgramRequirementTypeTotalCredits.put(stmtTypeInfo.getId(), totalCredits);
 242  0
         totalCredits.setVisible(false);
 243  0
         layout.add(totalCredits);
 244  
 
 245  
         //add rule description
 246  0
         if (!isReadOnly) {
 247  0
             KSLabel ruleTypeDesc = new KSLabel(stmtTypeInfo.getDescr());
 248  0
             ruleTypeDesc.addStyleName("KS-Program-Requirements-Preview-Rule-Type-Desc");
 249  0
             layout.add(ruleTypeDesc);
 250  
         }
 251  
 
 252  
         //display "Add Rule" button if user is in 'edit' mode
 253  0
         if (!isReadOnly) {
 254  0
             String addRuleLabel = ProgramProperties.get().programRequirements_summaryViewPageAddRule(stmtTypeInfo.getName());
 255  0
             KSButton addProgramReqBtn = new KSButton(addRuleLabel, KSButtonAbstract.ButtonStyle.FORM_SMALL);
 256  0
             addProgramReqBtn.addClickHandler(new ClickHandler(){
 257  
                 public void onClick(ClickEvent event) {
 258  0
                         showProgramRequirementDialog(requirementsPanel, stmtTypeInfo.getId(), null);
 259  0
                     }
 260  
                 });
 261  0
             layout.add(addProgramReqBtn);
 262  
         }
 263  
 
 264  0
         layout.add(requirementsPanel);
 265  0
     }
 266  
 
 267  
     private RulePreviewWidget addProgramRequirement(final SpanPanel requirementsPanel, final ProgramRequirementInfo progReqInfo) {
 268  
 
 269  0
         Integer internalProgReqID =  rules.getInternalProgReqID(progReqInfo);
 270  0
         String stmtTypeId = progReqInfo.getStatement().getType();
 271  
 
 272  0
         int minCredits = (progReqInfo.getMinCredits() == null ? 0 : progReqInfo.getMinCredits());
 273  0
         int maxCredits = (progReqInfo.getMaxCredits() == null ? 0 : progReqInfo.getMaxCredits());
 274  0
         String plainDesc =  (progReqInfo.getDescr() == null ? "" : progReqInfo.getDescr().getPlain());
 275  0
         final RulePreviewWidget rulePreviewWidget = new RulePreviewWidget(internalProgReqID, progReqInfo.getShortTitle(),
 276  
                                                             getTotalCreditsString(minCredits, maxCredits),
 277  
                                                             plainDesc, progReqInfo.getStatement(),
 278  
                                                             isReadOnly, getCluSetWidgetList(progReqInfo.getStatement()));
 279  0
         addRulePreviewWidgetHandlers(requirementsPanel, rulePreviewWidget, stmtTypeId, internalProgReqID);
 280  0
         return rulePreviewWidget;
 281  
     }
 282  
 
 283  
     private void addRulePreviewWidgetHandlers(final SpanPanel requirementsPanel, final RulePreviewWidget rulePreviewWidget, final String stmtTypeId, final Integer internalProgReqID) {
 284  
 
 285  
         //PROGRAM REQUIREMENT handlers
 286  0
         rulePreviewWidget.addProgReqEditButtonClickHandler(new ClickHandler(){
 287  
             public void onClick(ClickEvent event) {
 288  0
             showProgramRequirementDialog(requirementsPanel, stmtTypeId, internalProgReqID);
 289  0
             }
 290  
         });
 291  
 
 292  0
         rulePreviewWidget.addProgReqDeleteButtonClickHandler(new ClickHandler(){
 293  
             public void onClick(ClickEvent event) {
 294  0
                 final ConfirmationDialog dialog = new ConfirmationDialog(
 295  
                         ProgramProperties.get().programRequirements_summaryViewPageDeleteRuleDialogTitle(),
 296  
                         ProgramProperties.get().programRequirements_summaryViewPageDeleteRuleDialogMsg());
 297  
 
 298  0
                 dialog.getConfirmButton().addClickHandler(new ClickHandler(){
 299  
                     @Override
 300  
                     public void onClick(ClickEvent event) {
 301  0
                         rules.deleteRule(internalProgReqID);
 302  
 
 303  
                         //remove rule from display
 304  0
                         requirementsPanel.remove(rulePreviewWidget);
 305  0
                         updateTotalCreditPerType(stmtTypeId);
 306  0
                         dialog.hide();
 307  0
                     }
 308  
                 });
 309  0
                 dialog.show();
 310  0
             }
 311  
         });
 312  
 
 313  
         //SUBRULE handlers
 314  0
         rulePreviewWidget.addSubRuleAddButtonClickHandler(new ClickHandler(){
 315  
             public void onClick(ClickEvent event) {
 316  0
                     final StatementTreeViewInfo newSubRule = new StatementTreeViewInfo();
 317  0
                     newSubRule.setId(generateStatementTreeId());
 318  0
                     newSubRule.setType(stmtTypeId);
 319  0
                     RichTextInfo text = new RichTextInfo();
 320  0
                     text.setPlain("");
 321  0
                     newSubRule.setDesc(text);
 322  0
                         parentController.getView(ProgramRequirementsViewController.ProgramRequirementsViews.MANAGE, new Callback<View>(){
 323  
 
 324  
                                         @Override
 325  
                                         public void exec(View result) {
 326  0
                                                 ((ProgramRequirementsManageView) result).setRuleTree(newSubRule, true, internalProgReqID);
 327  0
                                                 parentController.showView(ProgramRequirementsViewController.ProgramRequirementsViews.MANAGE);
 328  0
                                         }
 329  
                                 });
 330  0
             }
 331  
         });
 332  
 
 333  0
         rulePreviewWidget.addSubRuleEditButtonClickHandler(new Callback<RulePreviewWidget.SubRuleInfo>(){
 334  
             public void exec(final RulePreviewWidget.SubRuleInfo subRuleInfo) {
 335  0
                     parentController.getView(ProgramRequirementsViewController.ProgramRequirementsViews.MANAGE, new Callback<View>(){
 336  
                     @Override
 337  
                     public void exec(View result) {
 338  0
                         ((ProgramRequirementsManageView) result).setRuleTree(subRuleInfo.getSubrule(), false, subRuleInfo.getInternalProgReqID());
 339  0
                         parentController.showView(ProgramRequirementsViewController.ProgramRequirementsViews.MANAGE);
 340  0
                     }
 341  
                 });
 342  0
                         }
 343  
         });
 344  
 
 345  0
         rulePreviewWidget.addSubRuleDeleteCallback(new Callback<Integer>(){
 346  
             public void exec(final Integer internalProgReqID) {
 347  
                 //deleting subrule does not delete the requirement (rule) itself
 348  0
                 rules.markRuleAsEdited(internalProgReqID);
 349  0
             }
 350  
         });
 351  0
     }
 352  
 
 353  
     protected Map<String, Widget> getCluSetWidgetList(StatementTreeViewInfo rule) {
 354  0
         Map<String, Widget> widgetList = new HashMap<String, Widget>();
 355  0
         Set<String> cluSetIds = new HashSet<String>();
 356  0
         findCluSetIds(rule, cluSetIds);
 357  0
         for (String clusetId : cluSetIds) {
 358  0
             widgetList.put(clusetId, new CluSetDetailsWidget(clusetId, cluSetRetriever));
 359  
         }
 360  
 
 361  0
         return widgetList;
 362  
     }
 363  
 
 364  
     private void findCluSetIds(StatementTreeViewInfo rule, Set<String> list) {
 365  
 
 366  0
         List<StatementTreeViewInfo> statements = rule.getStatements();
 367  0
         List<ReqComponentInfo> reqComponentInfos = rule.getReqComponents();
 368  
 
 369  0
         if ((statements != null) && (statements.size() > 0)) {
 370  
             // retrieve all statements
 371  0
             for (StatementTreeViewInfo statement : statements) {
 372  0
                 findCluSetIds(statement, list); // inside set the children of this statementTreeViewInfo
 373  
             }
 374  0
         } else if ((reqComponentInfos != null) && (reqComponentInfos.size() > 0)) {
 375  
             // retrieve all req. component LEAFS
 376  0
             for (ReqComponentInfo reqComponent : reqComponentInfos) {
 377  0
                 List<ReqCompFieldInfo> fieldInfos = reqComponent.getReqCompFields();
 378  0
                 for (ReqCompFieldInfo fieldInfo : fieldInfos) {
 379  0
                     if (RulesUtil.isCluSetWidget(fieldInfo.getType())) {
 380  0
                         list.add(fieldInfo.getValue());
 381  
                     }
 382  
                 }
 383  0
             }
 384  
         }
 385  0
     }
 386  
 
 387  
     private void showProgramRequirementDialog(final SpanPanel requirementsPanel, final String stmtTypeId, final Integer internalProgReqID) {
 388  
 
 389  0
         boolean isAddProgReq = (internalProgReqID == null);
 390  
 
 391  0
         String addRuleText = (isAddProgReq ? ProgramProperties.get().programRequirements_summaryViewPageAddRule(rules.getStmtTypeName(stmtTypeId)) : "Edit " + rules.getStmtTypeName(stmtTypeId));
 392  0
         final KSLightBox dialog = new KSLightBox(addRuleText);
 393  
 
 394  0
         final ButtonEnumerations.ButtonEnum actionButton = (isAddProgReq ? ButtonEnumerations.AddCancelEnum.ADD : ButtonEnumerations.UpdateCancelEnum.UPDATE);
 395  0
             ActionCancelGroup actionCancelButtons = new ActionCancelGroup(actionButton, ButtonEnumerations.UpdateCancelEnum.CANCEL);
 396  
 
 397  0
         actionCancelButtons.addCallback(new Callback<ButtonEnumerations.ButtonEnum>(){
 398  
              @Override
 399  
             public void exec(ButtonEnumerations.ButtonEnum result) {
 400  0
                 if (result == actionButton) {
 401  
 
 402  0
                     reqCompController.updateModel();
 403  
 
 404  
                     //validate and retrieve fields
 405  0
                     if (progReqData.getRoot().size() > 0) {
 406  0
                         progReqData.validate(new Callback<List<ValidationResultInfo>>() {
 407  
                             @Override
 408  
                             public void exec(List<ValidationResultInfo> validationResults) {
 409  
 
 410  
                                 //do not proceed if the user input is not valid
 411  0
                                 if (!reqCompController.isValid(validationResults, true, true)) {
 412  0
                                     return;
 413  
                                 }
 414  
 
 415  
                                 //retrieve entered values and set the rule info
 416  0
                                 updateProgramInfo(requirementsPanel, stmtTypeId, internalProgReqID);
 417  0
                                 dialog.hide();
 418  0
                             }
 419  
                         });
 420  
                     }
 421  
                 } else {
 422  0
                     dialog.hide();
 423  
                 }
 424  0
             }
 425  
         });
 426  
 
 427  0
         createAddProgramReqDialog(dialog, actionCancelButtons, internalProgReqID);
 428  0
     }
 429  
 
 430  
     private void createAddProgramReqDialog(final KSLightBox dialog, final ActionCancelGroup actionCancelButtons, final Integer internalProgReqID) {
 431  
 
 432  0
         parentController.requestModel(ProgramConstants.PROGRAM_MODEL_ID, new ModelRequestCallback() {
 433  
 
 434  
             @Override
 435  
             public void onRequestFail(Throwable cause) {
 436  0
                 Window.alert(cause.getMessage());
 437  0
                 GWT.log("Unable to retrieve program model for program summary view", cause);
 438  0
             }
 439  
 
 440  
             @Override
 441  
             public void onModelReady(Model model) {
 442  
 
 443  
                 //program has to be in the database before we can save program requirements
 444  0
                 String programId = ((DataModel)model).getRoot().get(ProgramConstants.ID);
 445  0
                 if (programId == null) {
 446  0
                     final ConfirmationDialog dialog = new ConfirmationDialog("Save Program Key Info", "Before saving rules please save program key info");
 447  0
                     dialog.getConfirmButton().addClickHandler(new ClickHandler(){
 448  
                         @Override
 449  
                         public void onClick(ClickEvent event) {
 450  0
                             dialog.hide();
 451  0
                         }
 452  
                     });
 453  0
                     dialog.show();
 454  0
                     return;
 455  
                 }
 456  
 
 457  0
                 if (dialogMetadata == null) {
 458  0
                     KSBlockingProgressIndicator.addTask(gettingMetadataTask);
 459  0
                     metadataServiceAsync.getMetadataList("org.kuali.student.lum.program.dto.ProgramRequirementInfo", "Active", new KSAsyncCallback<Metadata>() {
 460  
                         public void handleFailure(Throwable caught) {
 461  0
                             KSBlockingProgressIndicator.removeTask(gettingMetadataTask);
 462  0
                             Window.alert(caught.getMessage());
 463  0
                             GWT.log("getMetadataList failed for ProgramRequirementInfo", caught);
 464  0
                         }
 465  
 
 466  
                         public void onSuccess(final Metadata metadata) {
 467  0
                             KSBlockingProgressIndicator.removeTask(gettingMetadataTask);
 468  0
                             dialogMetadata = metadata;
 469  0
                             showDialog(dialog, actionCancelButtons, metadata, internalProgReqID);
 470  0
                         }
 471  
                     });
 472  
                 } else {
 473  0
                     showDialog(dialog, actionCancelButtons, dialogMetadata, internalProgReqID);
 474  
                 }
 475  
 
 476  0
             }
 477  
         });
 478  0
     }
 479  
 
 480  
     private static FieldDescriptor createInputField(final String id, final Metadata metadata, final Map<String, Metadata> fieldDefinitionMetadata, final Map<String, FieldDescriptor> fields) {
 481  0
             FieldDescriptor fd = new FieldDescriptor(id, new MessageKeyInfo("program", "program", "draft", id), metadata);
 482  0
         fields.put(id, fd);
 483  
 
 484  
         //add field to the data model metadata
 485  0
         fieldDefinitionMetadata.put(id, metadata);
 486  
 
 487  0
         return fd;
 488  
     }
 489  
     //TODO rework to use Configurer if possible
 490  
     private void showDialog(final KSLightBox dialog, final ActionCancelGroup actionCancelButtons, Metadata metadata, Integer internalProgReqID) {
 491  
 
 492  0
         Map<String, Metadata> fieldDefinitionMetadata = new HashMap<String,Metadata>();
 493  0
         Map<String, FieldDescriptor> fields = new HashMap<String, FieldDescriptor>();
 494  0
         VerticalSectionView dialogPanel = new VerticalSectionView(ProgramReqDialogView.VIEW, "", PROG_REQ_MODEL_ID, false);
 495  0
         holdFieldsPanel.clear();
 496  
 
 497  0
         dialogPanel.addField(createInputField("shortTitle", metadata.getProperties().get("shortTitle"), fieldDefinitionMetadata, fields));
 498  0
         FieldDescriptor minFd = createInputField("minCredits", metadata.getProperties().get("minCredits"), fieldDefinitionMetadata, fields);
 499  0
         FieldDescriptor maxFd = createInputField("maxCredits", metadata.getProperties().get("maxCredits"), fieldDefinitionMetadata, fields);
 500  0
         GroupSection credits = new GroupSection();
 501  0
         credits.addField(minFd);
 502  0
         credits.addField(maxFd);
 503  0
         dialogPanel.addSection(credits);
 504  0
         final Metadata descrMetadata = metadata.getProperties().get("descr").getProperties().get("plain");
 505  0
                 dialogPanel.addField(createInputField("descr", descrMetadata, fieldDefinitionMetadata, fields));
 506  
 
 507  0
         List<ConstraintMetadata> constraints = descrMetadata.getConstraints();
 508  0
         dialogPanel.addWidget(new KSLabel(constraints.get(0).getMaxLength() + getUILabel("descrLimit")));
 509  
 
 510  
         //setup data model
 511  0
         Metadata modelDefinitionMetadata = new Metadata();
 512  0
         modelDefinitionMetadata.setCanView(true);
 513  0
         modelDefinitionMetadata.setDataType(Data.DataType.DATA);
 514  0
         modelDefinitionMetadata.setProperties(fieldDefinitionMetadata);
 515  0
         progReqData = new DataModel();
 516  0
         progReqData.setRoot(new Data());
 517  0
         progReqData.setDefinition(new DataModelDefinition(modelDefinitionMetadata));
 518  
 
 519  
         //initialize fields with values if user is editing an existing rule
 520  0
         if (internalProgReqID != null) {
 521  0
             ProgramRequirementInfo progReq = rules.getProgReqByInternalId(internalProgReqID);
 522  0
             progReqData.set(QueryPath.parse("shortTitle"), progReq.getShortTitle());
 523  0
             progReqData.set(QueryPath.parse("minCredits"), progReq.getMinCredits());
 524  0
             progReqData.set(QueryPath.parse("maxCredits"), progReq.getMaxCredits());
 525  0
             progReqData.set(QueryPath.parse("descr"), (progReq.getDescr() == null ? "" : progReq.getDescr().getPlain()));
 526  
         }
 527  
 
 528  
         //setup controller
 529  0
         reqCompController = new BasicLayout(null);
 530  0
         reqCompController.addView(dialogPanel);
 531  0
         reqCompController.setDefaultModelId(PROG_REQ_MODEL_ID);
 532  0
         reqCompController.registerModel(PROG_REQ_MODEL_ID, new ModelProvider<DataModel>() {
 533  
             @Override
 534  
             public void requestModel(final ModelRequestCallback<DataModel> callback) {
 535  0
                 callback.onModelReady(progReqData);
 536  0
             }
 537  
         });
 538  
 
 539  
         //show fields
 540  0
         holdFieldsPanel.add(reqCompController);
 541  0
         reqCompController.showView(ProgramReqDialogView.VIEW);
 542  
 
 543  
         //layout.addStyleName("KS-Advanced-Search-Window");
 544  0
         holdFieldsPanel.add(actionCancelButtons);
 545  0
         dialog.setSize(550,530);
 546  0
         dialog.setWidget(holdFieldsPanel);
 547  0
         dialog.show();
 548  0
     }
 549  
 
 550  
         private String getUILabel(final String id) {
 551  0
                 return Application.getApplicationContext().getUILabel("program", null, null, id);
 552  
         }
 553  
 
 554  
     private void updateProgramInfo(SpanPanel requirementsPanel, String stmtTypeId, Integer internalProgReqID) {
 555  
 
 556  
         ProgramRequirementInfo progReqInfo;
 557  0
         if (internalProgReqID == null) {
 558  0
             progReqInfo = new ProgramRequirementInfo();
 559  0
             progReqInfo.setId(NEW_PROG_REQ_ID + Integer.toString(tempStmtTreeID++));   //set unique id
 560  0
             progReqInfo.setType("kuali.lu.type.Requirement");
 561  
 
 562  
             //create a top level statement tree
 563  0
             StatementTreeViewInfo stmtTree = new StatementTreeViewInfo();
 564  0
             stmtTree.setId(generateStatementTreeId());
 565  0
             stmtTree.setType(stmtTypeId);
 566  0
             RichTextInfo text2 = new RichTextInfo();
 567  0
             text2.setPlain("");
 568  0
             stmtTree.setDesc(text2);
 569  0
             stmtTree.setOperator(StatementOperatorTypeKey.AND); //AND is top level operator for rules within a Program Requirement
 570  
 
 571  
             //add new statement to the rule because even if user cancel on rule manage screen, we want to have at least one statement present
 572  0
             progReqInfo.setStatement(stmtTree);
 573  0
         } else {
 574  0
             progReqInfo = rules.getProgReqByInternalId(internalProgReqID);
 575  
         }
 576  
 
 577  0
         RichTextInfo text = new RichTextInfo();
 578  0
         text.setPlain((String)(progReqData.getRoot().get("descr")));
 579  0
         progReqInfo.setDescr(text);
 580  0
         progReqInfo.setShortTitle((String)progReqData.getRoot().get("shortTitle"));
 581  0
         progReqInfo.setLongTitle((String)progReqData.getRoot().get("shortTitle"));
 582  0
         progReqInfo.setMinCredits((Integer)progReqData.getRoot().get("minCredits"));
 583  0
         progReqInfo.setMaxCredits((Integer)progReqData.getRoot().get("maxCredits"));
 584  
 
 585  0
         if (internalProgReqID == null) {
 586  0
             rules.addRule(progReqInfo);
 587  0
             RulePreviewWidget rulePreviewWidget = addProgramRequirement(requirementsPanel, progReqInfo);
 588  0
             requirementsPanel.add(rulePreviewWidget);
 589  0
         } else {
 590  0
             rules.updateRule(internalProgReqID, progReqInfo);
 591  0
             for (Object aRequirementsPanel : requirementsPanel) {
 592  0
                 RulePreviewWidget rulePreviewWidget = (RulePreviewWidget) aRequirementsPanel;
 593  0
                 if (rulePreviewWidget.getInternalProgReqID().equals(internalProgReqID)) {
 594  0
                     rulePreviewWidget.updateProgInfoFields(progReqInfo.getShortTitle(),
 595  
                                                             getTotalCreditsString(progReqInfo.getMinCredits(), progReqInfo.getMaxCredits()),
 596  
                                                             progReqInfo.getDescr().getPlain());
 597  
                 }
 598  0
             }
 599  
         }
 600  
 
 601  0
         updateTotalCreditPerType(stmtTypeId);
 602  0
     }
 603  
 
 604  
     private String getTotalCreditsString(int min, int max) {
 605  0
         return "Expected Total Credits:" + min + "-" + max;
 606  
     }
 607  
 
 608  
     private void updateTotalCreditPerType(String stmtTypeId) {
 609  0
         int min = 0;
 610  0
         int max = 0;
 611  0
         for (ProgramRequirementInfo ruleInfo : rules.getProgReqInfo(stmtTypeId)) {
 612  0
             min += ruleInfo.getMinCredits();
 613  0
             max += ruleInfo.getMaxCredits();
 614  
         }
 615  
 
 616  0
         if (min != 0 || max != 0) {
 617  
                 //update total
 618  0
                 perProgramRequirementTypeTotalCredits.get(stmtTypeId).setVisible(true);
 619  0
                 perProgramRequirementTypeTotalCredits.get(stmtTypeId).setText(getTotalCreditsString(min, max));
 620  
         }
 621  0
     }
 622  
 
 623  
     private void setupSaveCancelButtons() {
 624  0
         actionCancelButtons.addStyleName("KS-Program-Requirements-Save-Button");
 625  0
         actionCancelButtons.addCallback(new Callback<ButtonEnumerations.ButtonEnum>(){
 626  
              @Override
 627  
             public void exec(ButtonEnumerations.ButtonEnum result) {
 628  0
                 if (result == ButtonEnumerations.SaveCancelEnum.SAVE) {
 629  0
                     storeRules(Controller.NO_OP_CALLBACK);
 630  
                 } else {
 631  
                     //does not work any more: HistoryManager.navigate(AppLocations.Locations.VIEW_PROGRAM.getLocation(), parentController.getViewContext());
 632  0
                     parentController.getParentController().showView(ProgramSections.SUMMARY);
 633  
                 }
 634  0
             }
 635  
         });
 636  0
     }
 637  
 
 638  
     static public String generateStatementTreeId() {
 639  0
         return (NEW_STMT_TREE_ID + Integer.toString(tempStmtTreeID++));
 640  
     }
 641  
 }