1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.kuali.student.lum.program.client.requirements;
16
17 import java.util.*;
18
19 import org.kuali.student.r1.common.assembly.data.Data;
20 import org.kuali.student.r2.common.util.ContextUtils;
21 import org.kuali.student.r1.core.statement.dto.StatementTreeViewInfo;
22 import org.kuali.student.r1.core.statement.dto.StatementTypeInfo;
23 import org.kuali.student.common.ui.client.application.KSAsyncCallback;
24 import org.kuali.student.common.ui.client.mvc.*;
25 import org.kuali.student.core.statement.ui.client.widgets.rules.RulesUtil;
26 import org.kuali.student.lum.program.client.ProgramConstants;
27 import org.kuali.student.lum.program.client.events.StoreRequirementIDsEvent;
28 import org.kuali.student.lum.program.client.events.StoreSpecRequirementIDsEvent;
29 import org.kuali.student.lum.program.client.rpc.MajorDisciplineRpcService;
30 import org.kuali.student.lum.program.client.rpc.MajorDisciplineRpcServiceAsync;
31 import org.kuali.student.lum.program.client.rpc.StatementRpcService;
32 import org.kuali.student.lum.program.client.rpc.StatementRpcServiceAsync;
33 import org.kuali.student.r2.lum.program.dto.ProgramRequirementInfo;
34
35 import com.google.gwt.core.client.GWT;
36 import com.google.gwt.event.shared.HandlerManager;
37 import com.google.gwt.user.client.Window;
38
39 public class ProgramRequirementsDataModel {
40
41 private final MajorDisciplineRpcServiceAsync programRemoteService = GWT.create(MajorDisciplineRpcService.class);
42 private StatementRpcServiceAsync statementRpcServiceAsync = GWT.create(StatementRpcService.class);
43 private Model model = null;
44 private HandlerManager eventBus;
45
46
47 public enum requirementState {STORED, ADDED, EDITED, DELETED;}
48 private Map<Integer, ProgramRequirementInfo> progReqInfos = new LinkedHashMap<Integer, ProgramRequirementInfo>();
49 private Map<Integer, ProgramRequirementInfo> origProgReqInfos = new LinkedHashMap<Integer, ProgramRequirementInfo>();
50 private Map<Integer, requirementState> progReqState = new HashMap<Integer, requirementState>();
51 private Map<Integer, requirementState> origProgReqState = new HashMap<Integer, requirementState>();
52 private List<StatementTypeInfo> stmtTypes = new ArrayList<StatementTypeInfo>();
53 private boolean isInitialized = false;
54 private static Integer progReqIDs = 111111;
55
56 public ProgramRequirementsDataModel(HandlerManager eventBus) {
57 this.eventBus = eventBus;
58 }
59
60
61 public void setupRules(Controller parentController, String modelId, final Callback<Boolean> onReadyCallback) {
62 parentController.requestModel(modelId, new ModelRequestCallback() {
63
64 @Override
65 public void onRequestFail(Throwable cause) {
66 GWT.log("Unable to retrieve program model for program summary view", cause);
67 onReadyCallback.exec(false);
68 }
69
70 @Override
71 public void onModelReady(Model modelIn) {
72
73
74
75
76 resetRules();
77
78 model = modelIn;
79 onReadyCallback.exec(true);
80 }
81 });
82 }
83
84 private void resetRules() {
85 progReqInfos = new LinkedHashMap<Integer, ProgramRequirementInfo>();
86 origProgReqInfos = new LinkedHashMap<Integer, ProgramRequirementInfo>();
87 progReqState = new HashMap<Integer, requirementState>();
88 origProgReqState = new HashMap<Integer, requirementState>();
89 stmtTypes = new ArrayList<StatementTypeInfo>();
90 model = null;
91 isInitialized = false;
92 }
93
94
95 public void retrieveProgramRequirements(Controller parentController, String modelId, final Callback<Boolean> onReadyCallback) {
96
97 setupRules(parentController, modelId, new Callback<Boolean>() {
98 @Override
99 public void exec(Boolean result) {
100 Data program = ((DataModel)model).getRoot().get(ProgramConstants.PROGRAM_REQUIREMENTS);
101
102 Iterator<Data.Property> realPropertyIterator = program.realPropertyIterator();
103 ArrayList<String> programRequirementIds = new ArrayList<String>();
104 while(realPropertyIterator.hasNext()) {
105 programRequirementIds.add((String)realPropertyIterator.next().getValue());
106 }
107 retrieveStatementTypes(programRequirementIds, onReadyCallback);
108 }
109 });
110 }
111
112 private void retrieveStatementTypes(final List<String> programRequirementIds, final Callback<Boolean> onReadyCallback) {
113
114
115 statementRpcServiceAsync.getStatementTypesForStatementType("kuali.statement.type.program", new KSAsyncCallback<List<StatementTypeInfo>>() {
116 @Override
117 public void handleFailure(Throwable caught) {
118 Window.alert(caught.getMessage());
119 GWT.log("getStatementTypes failed", caught);
120 onReadyCallback.exec(false);
121 }
122
123 @Override
124 public void onSuccess(List<StatementTypeInfo> stmtInfoTypes) {
125
126 for (StatementTypeInfo stmtInfoType : stmtInfoTypes) {
127 stmtTypes.add(stmtInfoType);
128 }
129
130
131 retrieveRules(programRequirementIds, onReadyCallback);
132 }
133 });
134 }
135
136 private void retrieveRules(List<String> programRequirementIds, final Callback<Boolean> onReadyCallback) {
137
138
139 if ((programRequirementIds == null) || programRequirementIds.isEmpty()) {
140 isInitialized = true;
141 onReadyCallback.exec(true);
142 return;
143 }
144
145 programRemoteService.getProgramRequirements(programRequirementIds, new KSAsyncCallback<List<ProgramRequirementInfo>>() {
146 @Override
147 public void handleFailure(Throwable caught) {
148 Window.alert(caught.getMessage());
149 GWT.log("getProgramRequirement failed", caught);
150 onReadyCallback.exec(false);
151 }
152
153 @Override
154 public void onSuccess(List<ProgramRequirementInfo> programReqInfos) {
155
156 origProgReqInfos.clear();
157 origProgReqState.clear();
158 progReqInfos.clear();
159 progReqState.clear();
160 for (ProgramRequirementInfo programReqInfo : programReqInfos) {
161
162 if (getStmtTypeInfo(programReqInfo.getStatement().getType()) == null) {
163 Window.alert("Did not find corresponding statement type for program requirement of type: " + programReqInfo.getStatement().getType());
164 GWT.log("Did not find corresponding statement type for program requirement of type: " + programReqInfo.getStatement().getType(), null);
165 }
166
167 setRuleState(programReqInfo);
168 origProgReqInfos.put(progReqIDs, cloneProgReq(programReqInfo));
169 origProgReqState.put(progReqIDs, requirementState.STORED);
170 progReqInfos.put(progReqIDs, programReqInfo);
171 progReqState.put(progReqIDs++, requirementState.STORED);
172 }
173
174 isInitialized = true;
175 onReadyCallback.exec(true);
176 }
177 });
178 }
179
180
181
182 public ProgramRequirementInfo updateRules(StatementTreeViewInfo newSubRule, Integer internalProgReqID, boolean isNewRule) {
183
184 ProgramRequirementInfo affectedRule = progReqInfos.get(internalProgReqID);
185
186 if (affectedRule == null) {
187 Window.alert("Cannot find program requirement with a statement that has id: '" + newSubRule.getId() + "'");
188 GWT.log("Cannot find program requirement with a statement that has id: '" + newSubRule.getId() + "'", null);
189 return null;
190 }
191
192 if (progReqState.get(internalProgReqID) == ProgramRequirementsDataModel.requirementState.STORED) {
193 progReqState.put(internalProgReqID, ProgramRequirementsDataModel.requirementState.EDITED);
194 }
195
196
197 StatementTreeViewInfo affectedTopTree = affectedRule.getStatement();
198 if ((affectedTopTree.getReqComponents() != null) && !affectedTopTree.getReqComponents().isEmpty()) {
199 StatementTreeViewInfo stmtTree = new StatementTreeViewInfo();
200 stmtTree.setId(ProgramRequirementsSummaryView.generateStatementTreeId());
201 stmtTree.setType( affectedRule.getStatement().getType());
202 stmtTree.setReqComponents(affectedTopTree.getReqComponents());
203 List<StatementTreeViewInfo> stmtList = new ArrayList<StatementTreeViewInfo>();
204 stmtList.add(stmtTree);
205 affectedTopTree.setStatements(stmtList);
206 }
207
208 List<StatementTreeViewInfo> affectedSubRules = affectedTopTree.getStatements();
209 if (isNewRule) {
210 affectedSubRules.add(newSubRule);
211 } else {
212
213 if (affectedSubRules == null || affectedSubRules.isEmpty()) {
214 affectedRule.setStatement(newSubRule);
215 } else {
216 for (StatementTreeViewInfo subRule : affectedSubRules) {
217 if (subRule.getId().equals(newSubRule.getId())) {
218 int treeIx = affectedSubRules.indexOf(subRule);
219
220 if (!isEmptyRule(newSubRule)) {
221 affectedSubRules.add(treeIx, newSubRule);
222 }
223 affectedSubRules.remove(subRule);
224 break;
225 }
226 }
227 }
228 }
229
230 return affectedRule;
231 }
232
233 public void updateProgramEntities(final Callback<List<ProgramRequirementInfo>> callback) {
234
235 final List<String> referencedProgReqIds = new ArrayList<String>();
236
237 programRemoteService.storeProgramRequirements(progReqState, progReqInfos, new KSAsyncCallback<Map<Integer, ProgramRequirementInfo>>() {
238 @Override
239 public void handleFailure(Throwable caught) {
240 Window.alert(caught.getMessage());
241 GWT.log("storeProgramRequirements failed", caught);
242 }
243 @Override
244 public void onSuccess(Map<Integer, ProgramRequirementInfo> storedRules) {
245
246 for (Integer internalProgReqID : storedRules.keySet()) {
247 ProgramRequirementInfo storedRule = storedRules.get(internalProgReqID);
248 switch (progReqState.get(internalProgReqID)) {
249 case STORED:
250
251 referencedProgReqIds.add(progReqInfos.get(internalProgReqID).getId());
252 break;
253 case ADDED:
254 referencedProgReqIds.add(storedRule.getId());
255 progReqInfos.put(internalProgReqID, storedRule);
256 origProgReqInfos.put(internalProgReqID, cloneProgReq(storedRule));
257 origProgReqState.put(internalProgReqID, ProgramRequirementsDataModel.requirementState.STORED);
258 progReqState.put(internalProgReqID, ProgramRequirementsDataModel.requirementState.STORED);
259 break;
260 case EDITED:
261 referencedProgReqIds.add(storedRule.getId());
262 progReqInfos.put(internalProgReqID, storedRule);
263 origProgReqInfos.put(internalProgReqID, cloneProgReq(storedRule));
264 origProgReqState.put(internalProgReqID, ProgramRequirementsDataModel.requirementState.STORED);
265 progReqState.put(internalProgReqID, ProgramRequirementsDataModel.requirementState.STORED);
266 break;
267 case DELETED:
268 progReqInfos.remove(internalProgReqID);
269 origProgReqInfos.remove(internalProgReqID);
270 origProgReqState.remove(internalProgReqID);
271 progReqState.remove(internalProgReqID);
272 break;
273 default:
274 break;
275 }
276 }
277
278 saveRequirementIds(referencedProgReqIds, storedRules, callback);
279 }
280 });
281 }
282
283 private void saveRequirementIds(final List<String> referencedProgReqIds, final Map<Integer, ProgramRequirementInfo> storedRules, final Callback<List<ProgramRequirementInfo>> callback) {
284 String programId = ((DataModel)model).getRoot().get("id");
285 String programType = ((DataModel)model).getRoot().get("type");
286
287
288 if (programType == null) {
289 programType = ((DataModel)model).getRoot().get("credentialProgramType");
290 }
291
292
293 if (programType.equals(ProgramConstants.VARIATION_TYPE_KEY)) {
294 eventBus.fireEvent(new StoreSpecRequirementIDsEvent(programId, programType, referencedProgReqIds));
295 } else {
296 eventBus.fireEvent(new StoreRequirementIDsEvent(programId, programType, referencedProgReqIds));
297 }
298
299 callback.exec(new ArrayList(storedRules.values()));
300 }
301
302
303 public List<ProgramRequirementInfo> getProgReqInfo(String stmtTypeId) {
304 List<ProgramRequirementInfo> rules = new ArrayList<ProgramRequirementInfo>();
305 for(ProgramRequirementInfo progReqInfo : progReqInfos.values()) {
306 if (progReqInfo.getStatement().getType().equals(stmtTypeId)) {
307 rules.add(progReqInfo);
308 }
309 }
310 return rules;
311 }
312
313 public Integer getInternalProgReqID(ProgramRequirementInfo progReqInfo) {
314 for(Integer key : progReqInfos.keySet()) {
315 if (progReqInfos.get(key) == progReqInfo) {
316 return key;
317 }
318 }
319
320 Window.alert("Problem retrieving key for program requirement: " + progReqInfo.getId());
321 GWT.log("Problem retrieving key for program requirement: " + progReqInfo.getId(), null);
322
323 return null;
324 }
325
326 public StatementTypeInfo getStmtTypeInfo(String stmtTypeId) {
327 for (StatementTypeInfo stmtInfo : stmtTypes) {
328 if (stmtInfo.getId().equals(stmtTypeId)) {
329 return stmtInfo;
330 }
331 }
332
333 Window.alert("Did not find StatementTypeInfo based on type: " + stmtTypeId);
334 GWT.log("Did not find StatementTypeInfo based on type: " + stmtTypeId);
335
336 return null;
337 }
338
339 public void deleteRule(Integer internalProgReqID) {
340 if (progReqState.get(internalProgReqID) == ProgramRequirementsDataModel.requirementState.ADDED) {
341
342 progReqState.remove(internalProgReqID);
343 progReqInfos.remove(internalProgReqID);
344 } else {
345 markRuleAsDeleted(internalProgReqID);
346 }
347 }
348
349 public void addRule(ProgramRequirementInfo programReqInfo) {
350 setRuleState(programReqInfo);
351 progReqInfos.put(progReqIDs, programReqInfo);
352 progReqState.put(progReqIDs++, requirementState.ADDED);
353 }
354
355 public void updateRule(Integer internalProgReqID, ProgramRequirementInfo programReqInfo) {
356 setRuleState(programReqInfo);
357 progReqInfos.put(internalProgReqID, programReqInfo);
358 markRuleAsEdited(internalProgReqID);
359 }
360
361
362
363
364
365
366 protected void setRuleState(ProgramRequirementInfo programReqInfo) {
367 if (model != null) {
368 String programState = ((DataModel) model).get(ProgramConstants.STATE);
369 programReqInfo.setStateKey(programState);
370 }
371 }
372
373 public void markRuleAsDeleted(Integer internalProgReqID) {
374 if ((progReqState.get(internalProgReqID) == ProgramRequirementsDataModel.requirementState.STORED) ||
375 (progReqState.get(internalProgReqID) == ProgramRequirementsDataModel.requirementState.EDITED)) {
376 progReqState.put(internalProgReqID, ProgramRequirementsDataModel.requirementState.DELETED);
377 }
378 }
379
380 public void markRuleAsEdited(Integer internalProgReqID) {
381 if (progReqState.get(internalProgReqID) == ProgramRequirementsDataModel.requirementState.STORED) {
382 progReqState.put(internalProgReqID, ProgramRequirementsDataModel.requirementState.EDITED);
383 }
384 }
385
386 public String getStmtTypeName(String stmtTypeId) {
387 String name = getStmtTypeInfo(stmtTypeId).getName();
388 return (name == null ? "" : name);
389 }
390
391 public boolean isRuleExists(String stmtTypeId) {
392 boolean showNoRuleText = true;
393 for(ProgramRequirementInfo ruleInfo : progReqInfos.values()) {
394 if ((ruleInfo.getStatement().getType().equals(stmtTypeId)) && (progReqState.get(getInternalProgReqID(ruleInfo)) != ProgramRequirementsDataModel.requirementState.DELETED)) {
395 showNoRuleText = false;
396 }
397 }
398 return showNoRuleText;
399 }
400
401 public boolean isDirty() {
402
403 if (progReqState.size() != origProgReqState.size()) {
404 return true;
405 }
406
407 for(Integer key : progReqState.keySet()) {
408 if (!progReqState.get(key).equals(origProgReqState.get(key))) {
409 return true;
410 }
411 }
412
413
414
415
416
417
418
419 return false;
420 }
421
422 public void revertRuleChanges() {
423 progReqInfos = new HashMap<Integer, ProgramRequirementInfo>();
424 progReqState = new HashMap<Integer, requirementState>();
425 for(Integer key : origProgReqInfos.keySet()) {
426 progReqInfos.put(key, cloneProgReq(origProgReqInfos.get(key)));
427 progReqState.put(key, origProgReqState.get(key));
428 }
429 }
430
431 public ProgramRequirementInfo getProgReqByInternalId(Integer internalProgReqID) {
432 return progReqInfos.get(internalProgReqID);
433 }
434
435 public boolean isEmptyRule(StatementTreeViewInfo tree) {
436 return (tree.getStatements() == null || tree.getStatements().isEmpty() && (tree.getReqComponents() == null || tree.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
451 private ProgramRequirementInfo cloneProgReq(ProgramRequirementInfo inProgReqInfo) {
452 ProgramRequirementInfo clonedProgReqInfo = null;
453 if (inProgReqInfo != null) {
454 clonedProgReqInfo = new ProgramRequirementInfo();
455 clonedProgReqInfo.setId(inProgReqInfo.getId());
456 clonedProgReqInfo.setShortTitle(inProgReqInfo.getShortTitle());
457 clonedProgReqInfo.setLongTitle(inProgReqInfo.getLongTitle());
458 clonedProgReqInfo.setDescr(inProgReqInfo.getDescr());
459 clonedProgReqInfo.setMinCredits(inProgReqInfo.getMinCredits());
460 clonedProgReqInfo.setMaxCredits(inProgReqInfo.getMaxCredits());
461 clonedProgReqInfo.setStateKey(inProgReqInfo.getStateKey());
462 clonedProgReqInfo.setTypeKey(inProgReqInfo.getTypeKey());
463 clonedProgReqInfo.setStatement(RulesUtil.clone(inProgReqInfo.getStatement()));
464
465
466
467 }
468 return clonedProgReqInfo;
469 }
470 }