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