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