1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.kuali.student.lum.lu.ui.course.client.requirements;
16
17 import java.util.ArrayList;
18 import java.util.HashMap;
19 import java.util.LinkedHashMap;
20 import java.util.List;
21 import java.util.Map;
22
23 import org.kuali.student.common.ui.client.application.Application;
24 import org.kuali.student.common.ui.client.application.KSAsyncCallback;
25 import org.kuali.student.common.ui.client.mvc.Callback;
26 import org.kuali.student.common.ui.client.mvc.Controller;
27 import org.kuali.student.common.ui.client.mvc.DataModel;
28 import org.kuali.student.common.ui.client.mvc.Model;
29 import org.kuali.student.common.ui.client.mvc.ModelRequestCallback;
30 import org.kuali.student.common.ui.client.widgets.dialog.ConfirmationDialog;
31 import org.kuali.student.common.ui.client.widgets.notification.KSNotification;
32 import org.kuali.student.common.ui.client.widgets.notification.KSNotifier;
33 import org.kuali.student.core.statement.ui.client.widgets.rules.RulesUtil;
34 import org.kuali.student.lum.common.client.lu.LUUIConstants;
35 import org.kuali.student.lum.lu.ui.course.client.service.CourseRpcService;
36 import org.kuali.student.lum.lu.ui.course.client.service.CourseRpcServiceAsync;
37 import org.kuali.student.lum.program.client.rpc.StatementRpcService;
38 import org.kuali.student.lum.program.client.rpc.StatementRpcServiceAsync;
39 import org.kuali.student.r1.core.statement.dto.ReqCompFieldInfo;
40 import org.kuali.student.r1.core.statement.dto.ReqComponentInfo;
41 import org.kuali.student.r1.core.statement.dto.StatementTreeViewInfo;
42 import org.kuali.student.r1.core.statement.dto.StatementTypeInfo;
43
44 import com.google.gwt.core.client.GWT;
45 import com.google.gwt.event.dom.client.ClickEvent;
46 import com.google.gwt.event.dom.client.ClickHandler;
47 import com.google.gwt.user.client.Window;
48
49 public class CourseRequirementsDataModel {
50
51 private final CourseRpcServiceAsync courseRemoteService = GWT.create(CourseRpcService.class);
52 private final StatementRpcServiceAsync statementRpcServiceAsync = GWT.create(StatementRpcService.class);
53 private Controller parentController;
54
55
56 public enum requirementState {STORED, ADDED, EDITED, DELETED;}
57 private Map<Integer, StatementTreeViewInfo> courseReqInfos = new LinkedHashMap<Integer, StatementTreeViewInfo>();
58 private Map<Integer, StatementTreeViewInfo> origCourseReqInfos = new LinkedHashMap<Integer, StatementTreeViewInfo>();
59 private Map<Integer, requirementState> courseReqState = new HashMap<Integer, requirementState>();
60 private Map<Integer, requirementState> origCourseReqState = new HashMap<Integer, requirementState>();
61 private List<StatementTypeInfo> stmtTypes = new ArrayList<StatementTypeInfo>();
62 private boolean isInitialized = false;
63 private static Integer courseReqIDs = 111111;
64
65 public CourseRequirementsDataModel(Controller parentController) {
66 this.parentController = parentController;
67 }
68
69
70 public void retrieveCourseRequirements(String modelId, final Callback<Boolean> onReadyCallback) {
71
72 courseReqInfos = new LinkedHashMap<Integer, StatementTreeViewInfo>();
73 origCourseReqInfos = new LinkedHashMap<Integer, StatementTreeViewInfo>();
74 courseReqState = new HashMap<Integer, requirementState>();
75 origCourseReqState = new HashMap<Integer, requirementState>();
76 stmtTypes = new ArrayList<StatementTypeInfo>();
77 isInitialized = false;
78
79 parentController.requestModel(modelId, new ModelRequestCallback() {
80
81 @Override
82 public void onRequestFail(Throwable cause) {
83 Window.alert(cause.getMessage());
84 GWT.log("Unable to retrieve model for course requirements view", cause);
85 onReadyCallback.exec(false);
86 }
87
88 @Override
89 public void onModelReady(Model model) {
90 String courseId = ((DataModel)model).getRoot().get("id");
91 retrieveStatementTypes(courseId, onReadyCallback);
92 }
93 });
94 }
95
96 public void retrieveStatementTypes(final String courseId, final Callback<Boolean> onReadyCallback) {
97
98
99 statementRpcServiceAsync.getStatementTypesForStatementTypeForCourse("kuali.statement.type.course", new KSAsyncCallback<List<StatementTypeInfo>>() {
100 @Override
101 public void handleFailure(Throwable caught) {
102 Window.alert(caught.getMessage());
103 GWT.log("getStatementTypes failed", caught);
104 onReadyCallback.exec(false);
105 }
106
107 @Override
108 public void onSuccess(List<StatementTypeInfo> stmtInfoTypes) {
109
110 stmtTypes.clear();
111 for (StatementTypeInfo stmtInfoType : stmtInfoTypes) {
112 stmtTypes.add(stmtInfoType);
113 }
114
115
116 retrieveRules(courseId, onReadyCallback);
117 }
118 });
119 }
120
121 private void retrieveRules(String courseId, final Callback<Boolean> onReadyCallback) {
122
123
124 if ((courseId == null) || courseId.isEmpty()) {
125 isInitialized = true;
126 onReadyCallback.exec(true);
127 return;
128 }
129
130 courseRemoteService.getCourseStatements(courseId, CourseRequirementsManageView.RULEEDIT_TEMLATE,
131 CourseRequirementsManageView.TEMLATE_LANGUAGE, new KSAsyncCallback<List<StatementTreeViewInfo>>() {
132 @Override
133 public void handleFailure(Throwable caught) {
134 Window.alert(caught.getMessage());
135 GWT.log("getCourseStatements failed", caught);
136 onReadyCallback.exec(false);
137 }
138
139 @Override
140 public void onSuccess(List<StatementTreeViewInfo> foundRules) {
141
142 origCourseReqInfos.clear();
143 origCourseReqState.clear();
144 courseReqInfos.clear();
145 courseReqState.clear();
146 if (foundRules != null) {
147 for (StatementTreeViewInfo foundRule : foundRules) {
148
149 if (getStmtTypeInfo(foundRule.getType()) == null) {
150
151 GWT.log("Did not find corresponding statement type for course requirement of type: " + foundRule.getType(), null);
152 }
153
154 origCourseReqInfos.put(courseReqIDs, RulesUtil.clone(foundRule));
155 origCourseReqState.put(courseReqIDs, requirementState.STORED);
156 courseReqInfos.put(courseReqIDs, foundRule);
157 courseReqState.put(courseReqIDs++, requirementState.STORED);
158 }
159 }
160
161 isInitialized = true;
162 onReadyCallback.exec(true);
163 }
164 });
165 }
166
167 public StatementTreeViewInfo updateRules(StatementTreeViewInfo newSubRule, Integer internalCourseReqID, boolean isNewRule) {
168
169 StatementTreeViewInfo affectedRule = courseReqInfos.get(internalCourseReqID);
170
171 if (affectedRule == null) {
172 Window.alert("Cannot find course requisite with a statement that has id: '" + newSubRule.getId() + "'");
173 GWT.log("Cannot find course requisite with a statement that has id: '" + newSubRule.getId() + "'", null);
174 return null;
175 }
176
177 if (courseReqState.get(internalCourseReqID) == CourseRequirementsDataModel.requirementState.STORED) {
178 courseReqState.put(internalCourseReqID, CourseRequirementsDataModel.requirementState.EDITED);
179 }
180
181 courseReqInfos.put(internalCourseReqID, newSubRule);
182
183 return newSubRule;
184 }
185
186 public void updateCourseRequisites(final String courseId, final String courseState, final Callback<List<StatementTreeViewInfo>> callback) {
187
188 if (courseId == null) {
189 final ConfirmationDialog dialog = new ConfirmationDialog(Application.getApplicationContext().getUILabel(
190 LUUIConstants.COURSE_GROUP_NAME, "submitCourseRequisitesDialogTitle"), Application
191 .getApplicationContext().getUILabel(LUUIConstants.COURSE_GROUP_NAME,
192 "submitCourseRequisitesDialogMsg"));
193 dialog.getConfirmButton().addClickHandler(new ClickHandler(){
194 @Override
195 public void onClick(ClickEvent event) {
196 dialog.hide();
197 }
198 });
199 dialog.show();
200 return;
201 }
202
203 final List<String> referencedProgReqIds = new ArrayList<String>();
204
205 courseRemoteService.storeCourseStatements(courseId.toString(), courseState, courseReqState, courseReqInfos, new KSAsyncCallback<Map<Integer, StatementTreeViewInfo>>() {
206 @Override
207 public void handleFailure(Throwable caught) {
208 Window.alert(caught.getMessage());
209 GWT.log("storeProgramRequirements failed", caught);
210 }
211 @Override
212 public void onSuccess(Map<Integer, StatementTreeViewInfo> storedRules) {
213
214 for (Integer internalProgReqID : storedRules.keySet()) {
215 StatementTreeViewInfo storedRule = storedRules.get(internalProgReqID);
216 switch (courseReqState.get(internalProgReqID)) {
217 case STORED:
218
219 referencedProgReqIds.add(internalProgReqID.toString());
220 break;
221 case ADDED:
222 referencedProgReqIds.add(storedRule.getId());
223 courseReqInfos.put(internalProgReqID, storedRule);
224 origCourseReqInfos.put(internalProgReqID, RulesUtil.clone(storedRule));
225 origCourseReqState.put(internalProgReqID, requirementState.STORED);
226 courseReqState.put(internalProgReqID, requirementState.STORED);
227 break;
228 case EDITED:
229 referencedProgReqIds.add(storedRule.getId());
230 courseReqInfos.put(internalProgReqID, storedRule);
231 origCourseReqInfos.put(internalProgReqID, RulesUtil.clone(storedRule));
232 origCourseReqState.put(internalProgReqID, requirementState.STORED);
233 courseReqState.put(internalProgReqID, requirementState.STORED);
234 break;
235 case DELETED:
236 courseReqInfos.remove(internalProgReqID);
237 origCourseReqInfos.remove(internalProgReqID);
238 origCourseReqState.remove(internalProgReqID);
239 courseReqState.remove(internalProgReqID);
240 break;
241 default:
242 break;
243 }
244 }
245
246 KSNotifier.add(new KSNotification("Requirements Save Successful", false, 4000));
247
248 callback.exec(new ArrayList(storedRules.values()));
249 }
250 });
251 }
252
253 public static void stripStatementIds(StatementTreeViewInfo tree) {
254 List<StatementTreeViewInfo> statements = tree.getStatements();
255 List<ReqComponentInfo> reqComponentInfos = tree.getReqComponents();
256
257 if ((tree.getId() != null) && (tree.getId().indexOf(CourseRequirementsSummaryView.NEW_STMT_TREE_ID)) >= 0) {
258 tree.setId(null);
259 }
260
261 if ((statements != null) && (statements.size() > 0)) {
262
263 for (StatementTreeViewInfo statement : statements) {
264 stripStatementIds(statement);
265 }
266 } else if ((reqComponentInfos != null) && (reqComponentInfos.size() > 0)) {
267
268 for (ReqComponentInfo reqComponent : reqComponentInfos) {
269 if ((reqComponent.getId() != null) && (reqComponent.getId().indexOf(CourseRequirementsSummaryView.NEW_REQ_COMP_ID) >= 0)) {
270 reqComponent.setId(null);
271 }
272
273 for (ReqCompFieldInfo field : reqComponent.getReqCompFields()) {
274 field.setId(null);
275 }
276 }
277 }
278 }
279
280 public List<StatementTreeViewInfo> getCourseReqInfo(String stmtTypeId) {
281 List<StatementTreeViewInfo> rules = new ArrayList<StatementTreeViewInfo>();
282 for(StatementTreeViewInfo rule : courseReqInfos.values()) {
283 if (rule.getType().equals(stmtTypeId)) {
284 rules.add(rule);
285 }
286 }
287 return rules;
288 }
289
290 public Integer getInternalCourseReqID(StatementTreeViewInfo rule) {
291 for(Integer key : courseReqInfos.keySet()) {
292 if (courseReqInfos.get(key) == rule) {
293 return key;
294 }
295 }
296
297 Window.alert("Problem retrieving key for course requisite: " + rule.getId());
298 GWT.log("Problem retrieving key for course requisite: " + rule.getId(), null);
299
300 return null;
301 }
302
303 public StatementTypeInfo getStmtTypeInfo(String stmtTypeId) {
304 for (StatementTypeInfo stmtInfo : stmtTypes) {
305 if (stmtInfo.getId().equals(stmtTypeId)) {
306 return stmtInfo;
307 }
308 }
309
310 try {
311
312 Window.alert("Did not find StatementTypeInfo based on typeA: " + stmtTypeId + new Throwable().getStackTrace().toString());
313 GWT.log("Did not find StatementTypeInfo based on type: " + stmtTypeId + new Throwable().getStackTrace());
314
315
316 throw new Exception();
317
318 } catch (Exception e) {
319 Window.alert("Exception" + e.getStackTrace().toString());
320 }
321 return null;
322 }
323
324 public void deleteRule(Integer internalProgReqID) {
325 if (courseReqState.get(internalProgReqID) == requirementState.ADDED) {
326
327 courseReqState.remove(internalProgReqID);
328 courseReqInfos.remove(internalProgReqID);
329 } else {
330 markRuleAsDeleted(internalProgReqID);
331 }
332 }
333
334 public void addRule(StatementTreeViewInfo rule) {
335 courseReqInfos.put(courseReqIDs, rule);
336 courseReqState.put(courseReqIDs++, requirementState.ADDED);
337 }
338
339 public void updateRule(Integer internalProgReqID, StatementTreeViewInfo rule) {
340 courseReqInfos.put(internalProgReqID, rule);
341 markRuleAsEdited(internalProgReqID);
342 }
343
344 public void markRuleAsDeleted(Integer internalCourseReqID) {
345 if ((courseReqState.get(internalCourseReqID) == requirementState.STORED) ||
346 (courseReqState.get(internalCourseReqID) == requirementState.EDITED)) {
347 courseReqState.put(internalCourseReqID, requirementState.DELETED);
348 }
349 }
350
351 public void markRuleAsEdited(Integer internalCourseReqID) {
352 if (courseReqState.get(internalCourseReqID) == requirementState.STORED) {
353 courseReqState.put(internalCourseReqID, requirementState.EDITED);
354 }
355 }
356
357 public String getStmtTypeName(String stmtTypeId) {
358 String name = getStmtTypeInfo(stmtTypeId).getName();
359 return (name == null ? "" : name);
360 }
361
362 public boolean isRuleExists(String stmtTypeId) {
363 boolean showNoRuleText = true;
364 for(StatementTreeViewInfo ruleInfo : courseReqInfos.values()) {
365 if ((ruleInfo.getType().equals(stmtTypeId)) && (courseReqState.get(getInternalCourseReqID(ruleInfo)) != requirementState.DELETED)) {
366 showNoRuleText = false;
367 }
368 }
369 return showNoRuleText;
370 }
371
372 public void removeEmptyRules() {
373 for(StatementTreeViewInfo rule : courseReqInfos.values()) {
374 if (isEmpty(rule)) {
375 Integer ruleId = getInternalCourseReqID(rule);
376 courseReqInfos.remove(ruleId);
377 courseReqState.remove(ruleId);
378 }
379 }
380 }
381
382 public boolean isDirty() {
383
384 if (courseReqState.size() != origCourseReqState.size()) {
385 return true;
386 }
387
388 for(Integer key : courseReqState.keySet()) {
389 if (!courseReqState.get(key).equals(origCourseReqState.get(key))) {
390 return true;
391 }
392 }
393
394 return false;
395 }
396
397 public void revertRuleChanges() {
398 courseReqInfos = new HashMap<Integer, StatementTreeViewInfo>();
399 courseReqState = new HashMap<Integer, requirementState>();
400 for(Integer key : origCourseReqInfos.keySet()) {
401 courseReqInfos.put(key, RulesUtil.clone(origCourseReqInfos.get(key)));
402 courseReqState.put(key, origCourseReqState.get(key));
403 }
404 }
405
406 public StatementTreeViewInfo getRule(Integer internalCourseReqID) {
407 return courseReqInfos.get(internalCourseReqID);
408 }
409
410 public static void getStatementTypes(final Callback<List<StatementTypeInfo>> onReadyCallback) {
411
412 StatementRpcServiceAsync statementRpcServiceAsync = GWT.create(StatementRpcService.class);
413
414
415 statementRpcServiceAsync.getStatementTypesForStatementTypeForCourse("kuali.statement.type.course", new KSAsyncCallback<List<StatementTypeInfo>>() {
416 @Override
417 public void handleFailure(Throwable caught) {
418 Window.alert(caught.getMessage());
419 GWT.log("getStatementTypes failed", caught);
420 onReadyCallback.exec(new ArrayList<StatementTypeInfo>());
421 }
422
423 @Override
424 public void onSuccess(List<StatementTypeInfo> stmtInfoTypes) {
425
426 List<StatementTypeInfo> stmtTypes = new ArrayList<StatementTypeInfo>();
427 for (StatementTypeInfo stmtInfoType : stmtInfoTypes) {
428 stmtTypes.add(stmtInfoType);
429 }
430 onReadyCallback.exec(stmtTypes);
431 }
432 });
433 }
434
435 public static boolean isEmpty(StatementTreeViewInfo rule) {
436 return (((rule.getStatements() == null) || rule.getStatements().isEmpty()) && ((rule.getReqComponents() == null) || rule.getReqComponents().isEmpty()));
437 }
438
439 public boolean isInitialized() {
440 return isInitialized;
441 }
442
443 public void setInitialized(boolean initialized) {
444 isInitialized = initialized;
445 }
446
447 public List<StatementTypeInfo> getStmtTypes() {
448 return stmtTypes;
449 }
450 }