View Javadoc

1   package org.kuali.student.lum.lu.ui.dependency.client.views;
2   
3   
4   import java.util.ArrayList;
5   import java.util.Arrays;
6   import java.util.HashMap;
7   import java.util.HashSet;
8   import java.util.List;
9   import java.util.Map;
10  import java.util.Set;
11  
12  import org.kuali.student.common.ui.client.application.KSAsyncCallback;
13  import org.kuali.student.common.ui.client.mvc.Callback;
14  import org.kuali.student.common.ui.client.mvc.Controller;
15  import org.kuali.student.common.ui.client.mvc.DataModelDefinition;
16  import org.kuali.student.common.ui.client.mvc.ViewComposite;
17  import org.kuali.student.common.ui.client.service.MetadataRpcService;
18  import org.kuali.student.common.ui.client.service.MetadataRpcServiceAsync;
19  import org.kuali.student.common.ui.client.service.SearchRpcService;
20  import org.kuali.student.common.ui.client.service.SearchRpcServiceAsync;
21  import org.kuali.student.common.ui.client.util.UtilConstants;
22  import org.kuali.student.common.ui.client.widgets.HasWatermark;
23  import org.kuali.student.common.ui.client.widgets.KSButton;
24  import org.kuali.student.common.ui.client.widgets.KSButtonAbstract.ButtonStyle;
25  import org.kuali.student.common.ui.client.widgets.KSLabel;
26  import org.kuali.student.common.ui.client.widgets.field.layout.element.SpanPanel;
27  import org.kuali.student.common.ui.client.widgets.field.layout.layouts.VerticalFieldLayout;
28  import org.kuali.student.common.ui.client.widgets.filter.FilterEvent;
29  import org.kuali.student.common.ui.client.widgets.filter.FilterEventHandler;
30  import org.kuali.student.common.ui.client.widgets.filter.FilterResetEventHandler;
31  import org.kuali.student.common.ui.client.widgets.filter.KSFilterOptions;
32  import org.kuali.student.common.ui.client.widgets.headers.KSDocumentHeader;
33  import org.kuali.student.common.ui.client.widgets.layout.HorizontalBlockFlowPanel;
34  import org.kuali.student.common.ui.client.widgets.layout.VerticalFlowPanel;
35  import org.kuali.student.common.ui.client.widgets.progress.BlockingTask;
36  import org.kuali.student.common.ui.client.widgets.progress.KSBlockingProgressIndicator;
37  import org.kuali.student.common.ui.client.widgets.search.CollapsablePanel;
38  import org.kuali.student.common.ui.client.widgets.search.KSPicker;
39  import org.kuali.student.common.ui.client.widgets.suggestbox.IdableSuggestOracle.IdableSuggestion;
40  import org.kuali.student.common.ui.client.widgets.suggestbox.KSSuggestBox;
41  import org.kuali.student.core.statement.ui.client.widgets.rules.RulePreviewWidget;
42  import org.kuali.student.core.statement.ui.client.widgets.rules.RulesUtil;
43  import org.kuali.student.lum.common.client.lu.LUUIConstants;
44  import org.kuali.student.lum.common.client.widgets.AppLocations;
45  import org.kuali.student.lum.common.client.widgets.CluSetDetailsWidget;
46  import org.kuali.student.lum.common.client.widgets.CluSetRetriever;
47  import org.kuali.student.lum.common.client.widgets.CluSetRetrieverImpl;
48  import org.kuali.student.lum.lu.ui.dependency.client.controllers.DependencyAnalysisController;
49  import org.kuali.student.lum.lu.ui.dependency.client.controllers.DependencyAnalysisController.DependencyViews;
50  import org.kuali.student.lum.lu.ui.dependency.client.service.DependencyAnalysisRpcService;
51  import org.kuali.student.lum.lu.ui.dependency.client.service.DependencyAnalysisRpcServiceAsync;
52  import org.kuali.student.lum.lu.ui.dependency.client.widgets.DependencyResultPanel;
53  import org.kuali.student.lum.lu.ui.dependency.client.widgets.DependencyResultPanel.DependencyTypeSection;
54  import org.kuali.student.lum.lu.ui.tools.client.configuration.ClusetView.Picker;
55  import org.kuali.student.r1.common.assembly.data.LookupMetadata;
56  import org.kuali.student.r1.common.assembly.data.Metadata;
57  import org.kuali.student.r1.common.assembly.data.ModelDefinition;
58  import org.kuali.student.r2.core.search.dto.*;
59  import org.kuali.student.r2.core.search.dto.SearchParamInfo;
60  import org.kuali.student.r1.core.statement.dto.ReqCompFieldInfo;
61  import org.kuali.student.r1.core.statement.dto.ReqComponentInfo;
62  import org.kuali.student.r1.core.statement.dto.StatementTreeViewInfo;
63  import org.kuali.student.r2.lum.program.dto.ProgramRequirementInfo;
64  
65  import com.google.gwt.core.client.GWT;
66  import com.google.gwt.event.dom.client.ClickEvent;
67  import com.google.gwt.event.dom.client.ClickHandler;
68  import com.google.gwt.http.client.URL;
69  import com.google.gwt.user.client.Window;
70  import com.google.gwt.user.client.ui.Anchor;
71  import com.google.gwt.user.client.ui.FlowPanel;
72  import com.google.gwt.user.client.ui.HTMLPanel;
73  import com.google.gwt.user.client.ui.HorizontalPanel;
74  import com.google.gwt.user.client.ui.Widget;
75  
76  public class DependencyAnalysisView extends ViewComposite{
77         
78  	private static CluSetRetriever cluSetRetriever = new CluSetRetrieverImpl();
79  	
80      protected final BlockingTask initializingTask = new BlockingTask("Loading");
81      
82      protected DependencyAnalysisRpcServiceAsync depRpcServiceAsync = GWT.create(DependencyAnalysisRpcService.class);
83      protected MetadataRpcServiceAsync metadataServiceAsync = GWT.create(MetadataRpcService.class);
84      protected SearchRpcServiceAsync searchServiceAsync = GWT.create(SearchRpcService.class);
85  
86  	private ModelDefinition searchDefinition;
87  	private VerticalFieldLayout container = new VerticalFieldLayout();
88  	protected boolean initialized = false;
89  	
90  	protected String selectedCourseId;
91  	protected String selectedCourseCd;
92  	protected String selectedCourseName;
93  	
94  	protected DependencyResultPanel depResultPanel;
95  	protected KSFilterOptions dependencyFilter;
96  	protected HorizontalBlockFlowPanel resultContainer = new HorizontalBlockFlowPanel();
97  	
98  	private final BlockingTask loadDataTask = new BlockingTask("Retrieving Data");
99  	
100 	private KSDocumentHeader header;
101 		
102 	public DependencyAnalysisView(Controller controller) {
103 		super(controller, "Dependency Analysis", DependencyViews.MAIN);
104         this.initWidget(container);
105         this.addStyleName("blockLayout");
106         this.addStyleName("ks-dependency-container");
107 	}
108 	
109 	@Override
110 	public void beforeShow(final Callback<Boolean> onReadyCallback) {
111         if (!initialized) {
112     		KSBlockingProgressIndicator.addTask(initializingTask);
113 
114     		//This loads search definitions for the dependency analysis search 
115             metadataServiceAsync.getMetadata("dependency", null, null, new KSAsyncCallback<Metadata>(){
116 
117                 @Override
118                 public void handleFailure(Throwable caught) {
119                     KSBlockingProgressIndicator.removeTask(initializingTask);
120                     throw new RuntimeException("Failed to load search definitions.", caught);                        
121                 }
122 
123                 @Override
124                 public void onSuccess(Metadata result) {
125                 	searchDefinition = new DataModelDefinition(result);
126                 	init();
127                 	onReadyCallback.exec(true);                	
128                     initialized = true;
129                     KSBlockingProgressIndicator.removeTask(initializingTask);
130                 }                
131             });	        
132         } else {
133         	onReadyCallback.exec(true);
134         }
135 	}
136 
137 	protected void init(){		
138 		this.header = new KSDocumentHeader();
139 		
140         header.setTitle("Dependency Analysis");        
141 
142         //Get search definition for dependency analysis trigger search and create trigger picker          
143 		Metadata metaData = searchDefinition.getMetadata("courseId");
144 		final KSPicker triggerPicker = new Picker(metaData.getInitialLookup(), metaData.getAdditionalLookups());
145         ((HasWatermark)triggerPicker.getInputWidget()).setWatermarkText("Enter course code");	
146         triggerPicker.getInputWidget().ensureDebugId("Dependency-Analysis-Course-Code");
147 
148         //Setup the "go" button for trigger picker
149         KSButton goButton = new KSButton("Go", ButtonStyle.PRIMARY_SMALL);
150 		goButton.addClickHandler(new ClickHandler(){
151 
152 			@Override
153 			public void onClick(ClickEvent event) {				
154                 selectedCourseId = triggerPicker.getValue().toString();
155                 KSSuggestBox suggestBox = (KSSuggestBox)triggerPicker.getInputWidget();
156                 IdableSuggestion selectedSuggestion = suggestBox.getCurrentSuggestion();
157                 
158                 // We need to make sure we only search for courses that have been selected from the suggest box
159                 if(selectedSuggestion != null && selectedSuggestion.getReplacementString().equalsIgnoreCase(suggestBox.getText())){
160 	                selectedCourseName = selectedSuggestion.getAttrMap().get("lu.resultColumn.luOptionalLongName");
161 	                if (!selectedCourseId.equals(UtilConstants.IMPOSSIBLE_CHARACTERS)){
162 	    				KSBlockingProgressIndicator.addTask(loadDataTask);
163 	                	selectedCourseCd = triggerPicker.getDisplayValue();                
164 		                if (depResultPanel != null){
165 		                	resultContainer.remove(depResultPanel);
166 		                }
167 		                depResultPanel = new DependencyResultPanel();
168 		                depResultPanel.setHeaderTitle(selectedCourseCd + " - " + selectedCourseName);		
169 		                resultContainer.add(depResultPanel);
170 		                resultContainer.setVisible(true);
171 		                updateDependencyResults();
172 		                
173 		                ((DependencyAnalysisController) DependencyAnalysisView.this.getController()).showExport(isExportButtonActive());
174 		                header.showPrint(true);
175 		                header.setPrintContent(depResultPanel); // we only want to print the results panel
176 	                }
177 	                
178                 }
179 			}
180 			
181 		});
182 
183 		
184         //Create search section with the trigger picker and go button
185 		HorizontalPanel pickerPanel = new HorizontalPanel();
186 		pickerPanel.add(triggerPicker);
187 		pickerPanel.add(goButton);
188         
189 		FlowPanel searchPanel = new FlowPanel();
190 		searchPanel.addStyleName("ks-dependency-search");
191 		searchPanel.add(new KSLabel("Search for item to view its dependencies"));
192 		searchPanel.add(pickerPanel);		
193 		
194 		//Add widgets to view
195 		container.setTitleWidget(header);
196 		container.addStyleName("blockLayout");
197         container.addWidget(searchPanel);
198         
199         List<LookupMetadata> lookups = new ArrayList<LookupMetadata>();
200         metaData = searchDefinition.getMetadata("filter");
201         lookups.add(metaData.getInitialLookup());
202         
203         dependencyFilter = new KSFilterOptions(metaData.getAdditionalLookups());
204         dependencyFilter.addFilterEventHandler(new FilterEventHandler(){
205 
206 			@Override
207 			public void onDeselect(FilterEvent e) {
208 				depResultPanel.hide(e.getFilterKey(), e.getFilterValue());
209 			}
210 
211 			@Override
212 			public void onSelect(FilterEvent e) {
213 				if (e.isInitialSelect()){
214 					depResultPanel.hideAll();
215 				}
216 				depResultPanel.show(e.getFilterKey(), e.getFilterValue());			
217 			}
218         	
219         });
220         
221         dependencyFilter.addFilterResetEventHandler(new FilterResetEventHandler(){
222 
223 			@Override
224 			public void onReset() {
225 				depResultPanel.showAll();				
226 			}        	
227         });
228         
229         resultContainer.add(dependencyFilter);
230         resultContainer.setVisible(false);
231         
232         container.addWidget(resultContainer);
233 	}
234 
235 	/*
236 	 * This method calls the dependency analysis search with the selected trigger from the picker,
237 	 * and updates the DependencyResultPanel with the results from the search. 
238 	 */
239 	protected void updateDependencyResults(){
240 		//Setup up sections for DependencyResultPanel		
241 		depResultPanel.addSection(LUUIConstants.DEP_SECTION_COURSE,"Course Dependencies");		
242 		depResultPanel.addSection(LUUIConstants.DEP_SECTION_PROGRAM,"Program Dependencies");
243 		depResultPanel.addSection(LUUIConstants.DEP_SECTION_COURSE_SET, "Course Set Inclusions");		
244 			
245 		dependencyFilter.reset();
246 		
247 		//Setup and invoke the dependency analysis search and process the results
248 		SearchRequestInfo searchRequest = new SearchRequestInfo();
249 		searchRequest.setSearchKey("lu.search.dependencyAnalysis");
250 		
251 		SearchParamInfo searchParam = new SearchParamInfo();
252 		searchParam.setKey("lu.queryParam.luOptionalCluId");
253 		searchParam.getValues().add(selectedCourseId);
254 		searchRequest.getParams().add(searchParam);
255 				
256 		searchServiceAsync.search(searchRequest, new KSAsyncCallback<SearchResultInfo>(){
257 
258 			@Override
259 			public void onSuccess(SearchResultInfo searchResults) {
260 				for (SearchResultRowInfo searchResultRow : searchResults.getRows ()) {
261 					
262 					//TODO: This should not use hard-coded result columns 
263 					String cluCode = "";
264 					String cluName = "";
265 					String cluType = "";
266 					String dependencyType = "";
267 					String dependencyTypeName = "";
268 					String reqComponentIds = "";
269 					String reqRootId = "";
270 					String cluId = "";
271 					String curriculumOversightNames = "";
272 					String dependencySectionKey = "";
273 					Boolean diffAdminOrg = false;
274 					String parentCluId = "";
275 					
276 					for (SearchResultCellInfo searchResultCell : searchResultRow.getCells ()){
277 						if (searchResultCell.getKey().equals ("lu.resultColumn.luOptionalCode")) {
278 							cluCode = searchResultCell.getValue();	
279 						} if (searchResultCell.getKey().equals ("lu.resultColumn.cluId")) {
280 							cluId = searchResultCell.getValue();
281 						} else if (searchResultCell.getKey().equals("lu.resultColumn.luOptionalLongName")){
282 							cluName = searchResultCell.getValue();
283 						} else if (searchResultCell.getKey().equals("lu.resultColumn.cluType")){
284 							cluType = searchResultCell.getValue();
285 							if (cluType.equals(LUUIConstants.CLU_TYPE_CREDIT_COURSE)){
286 								dependencySectionKey = LUUIConstants.DEP_SECTION_COURSE;
287 							} else if (cluType != null){
288 								dependencySectionKey = LUUIConstants.DEP_SECTION_PROGRAM;
289 							}
290 						} else if (searchResultCell.getKey().equals("lu.resultColumn.luOptionalDependencyType")){
291 							dependencyType = searchResultCell.getValue();
292 							if (dependencyType.equals("cluSet")){
293 								dependencySectionKey = LUUIConstants.DEP_SECTION_COURSE_SET;
294 							} else if (LUUIConstants.DEP_TYPE_JOINT.equals(dependencyType) || 
295 										LUUIConstants.DEP_TYPE_CROSS_LISTED.equals(dependencyType)){
296 								dependencySectionKey = LUUIConstants.DEP_SECTION_COURSE;;
297 							}
298 						} else if (searchResultCell.getKey().equals("lu.resultColumn.luOptionalDependencyTypeName")){
299 							dependencyTypeName = searchResultCell.getValue();
300 						} else if (searchResultCell.getKey().equals("lu.resultColumn.luOptionalDependencyRequirementComponentIds")){
301 							reqComponentIds = searchResultCell.getValue();
302 						} else if (searchResultCell.getKey().equals("lu.resultColumn.luOptionalDependencyRootId")){
303 							reqRootId = searchResultCell.getValue();
304 						} else if (searchResultCell.getKey().equals("lu.resultColumn.luOptionalOversightCommitteeNames")){
305 							curriculumOversightNames = searchResultCell.getValue();
306 						} else if (searchResultCell.getKey().equals("lu.resultColumn.luOptionalDependencyRequirementDifferentAdminOrg")){
307 							diffAdminOrg = ("true").equals(searchResultCell.getValue());
308 						} else if (searchResultCell.getKey().equals("lu.resultColumn.parentCluId")){
309 							parentCluId = searchResultCell.getValue();
310 						}
311 						
312 							
313 					}
314 					
315 					//Get the dependency type section to add the dependency to, create new one if this is the first dependency for the t
316 					DependencyTypeSection typeSection = depResultPanel.getDependencyTypeSection(dependencySectionKey, dependencyType);
317 					if (typeSection == null){						
318 						typeSection = depResultPanel.addDependencyTypeSection(dependencySectionKey, dependencyType, getDependencyTypeLabel(dependencySectionKey, dependencyType, dependencyTypeName));
319 					}
320 					
321 					//If dependency has details, create the details widget
322 					VerticalFieldLayout depDetails = null;
323 					if (hasDependencyDetails(dependencyType)){
324 						depDetails = getDependencyDetails(dependencySectionKey, dependencyType, cluCode, reqRootId, reqComponentIds);
325 						KSLabel curricOversightLabel = new KSLabel("Curriculum Oversight: " + curriculumOversightNames);
326 						curricOversightLabel.addStyleName("ks-dependency-oversight");
327 						depDetails.addWidget(curricOversightLabel);
328 					}
329 
330 					//Add the dependency to the dependency section
331 					typeSection.addDependencyItem(getDependencyLabel(dependencySectionKey, dependencyType, cluId, cluCode, cluName, cluType, diffAdminOrg, parentCluId), depDetails);
332 				}
333 				
334 				depResultPanel.finishLoad();
335 				KSBlockingProgressIndicator.removeTask(loadDataTask);
336 			}
337 			
338 		});
339 	}
340 	
341 
342 	private VerticalFieldLayout getDependencyDetails(String dependencySectionKey, String dependencyType, final String cluCode, final String rootId, String reqComponentIds){
343 		VerticalFieldLayout depDetails = new VerticalFieldLayout();
344 		depDetails.addStyleName("KS-Dependency-Details");
345 		if (reqComponentIds != null && !reqComponentIds.isEmpty()){
346 			List<String> reqComponentIdList = Arrays.asList(reqComponentIds.split(","));
347 
348 			final VerticalFlowPanel simpleRequirement = new VerticalFlowPanel();			
349 			simpleRequirement.addStyleName("KS-Dependency-Simple-Rule");
350 			
351 			//For programs, add ability to display both the simple requirement and complex requirement for the details
352 			if (LUUIConstants.DEP_SECTION_PROGRAM.equals(dependencySectionKey)){
353 				final KSButton complexReqLabel = new KSButton("Display complex requirement", ButtonStyle.DEFAULT_ANCHOR);
354 				final KSButton simpleReqLabel = new KSButton("Display simple requirement", ButtonStyle.DEFAULT_ANCHOR);
355 				
356 				//Initialize the complex requirement panel, set it so it is not initially open (ie. not visible)
357 				final FlowPanel complexContent = new FlowPanel();
358 				final CollapsablePanel complexRequirement = GWT.create(CollapsablePanel.class);
359 				complexRequirement.initialise("", complexContent, false, false);
360                 
361 				complexContent.addStyleName("KS-Dependency-Complex-Rule");
362 				depDetails.addWidget(simpleRequirement);
363 				depDetails.addWidget(complexRequirement);
364 				depDetails.addWidget(complexReqLabel);
365 				depDetails.addWidget(simpleReqLabel);
366 				
367 				simpleReqLabel.setVisible(false);
368 				
369 				//Click handler to display the complex requirement, which will go and fetch the requirement components
370 				//if displaying for first time.
371 				complexReqLabel.addClickHandler(new ClickHandler(){
372 					public void onClick(ClickEvent event) {
373 						simpleReqLabel.setVisible(true);
374 						simpleRequirement.setVisible(false);
375 						complexReqLabel.setVisible(false);
376 
377 						if (complexContent.getWidgetCount() <= 0){
378 							KSBlockingProgressIndicator.addTask(loadDataTask);
379 							//TODO: This code copied from program screens, need common reusable code
380 							depRpcServiceAsync.getProgramRequirement(rootId, new KSAsyncCallback<ProgramRequirementInfo>(){
381 								public void onSuccess(ProgramRequirementInfo progReqInfo) {															
382 							        int minCredits = (progReqInfo.getMinCredits() == null ? 0 : progReqInfo.getMinCredits());
383 							        int maxCredits = (progReqInfo.getMaxCredits() == null ? 0 : progReqInfo.getMaxCredits());
384 							        String plainDesc = (progReqInfo.getDescr() == null ? "" : progReqInfo.getDescr().getPlain());
385 							        final RulePreviewWidget rulePreviewWidget = new RulePreviewWidget(1, progReqInfo.getShortTitle(),
386 							                getTotalCreditsString(minCredits, maxCredits),
387 							                plainDesc, progReqInfo.getStatement(),
388 							                true, getCluSetWidgetList(progReqInfo.getStatement()));
389 							        complexContent.add(rulePreviewWidget);
390 							        KSBlockingProgressIndicator.removeTask(loadDataTask);
391 									complexRequirement.open();
392 								}							
393 							});
394 						} else {
395 							complexRequirement.open();
396 						}
397 					}					
398 				});
399 				
400 				//Click handler to display the simple requirement only
401 				simpleReqLabel.addClickHandler(new ClickHandler(){
402 					public void onClick(ClickEvent event) {
403 						complexReqLabel.setVisible(true);						
404 						complexRequirement.close();
405 						simpleRequirement.setVisible(true);
406 						simpleReqLabel.setVisible(false);						
407 					}
408 				});
409 			} else {
410 				depDetails.addWidget(simpleRequirement);
411 			}
412 			
413 			depRpcServiceAsync.getRequirementComponentNL(reqComponentIdList, new KSAsyncCallback<List<String>>(){
414 				public void onSuccess(List<String> results) {
415 					for (String reqCompNL:results){
416 						int codeIdx = reqCompNL.indexOf(selectedCourseCd);
417 						SpanPanel requirement = new SpanPanel();
418 						requirement.setHTML(reqCompNL.substring(0,codeIdx) + 
419 								" <b>" + selectedCourseCd + "</b>" + reqCompNL.substring(codeIdx + selectedCourseCd.length()));
420 						simpleRequirement.add(requirement);
421 					}								
422 				}							
423 			});
424 		}
425 
426 		return depDetails;
427 	}
428 	
429 	//This generates the label for the dependency type section (eg. Pre-req requirement, course set inclusion, etc).
430 	private SpanPanel getDependencyTypeLabel(String dependencySectionKey, String dependencyType, String dependencyTypeName) {
431 		SpanPanel header = new SpanPanel();
432 		if (dependencyType.equals("joint") || dependencyType.equals("crossListed")){
433 			header.setHTML("<b>" + selectedCourseCd + "</b> is <b>" + dependencyTypeName + "</b> with the following ");
434 		} else if (dependencySectionKey.equals("course sets")){
435 			header.setHTML("<b>" + selectedCourseCd + "</b> belongs to the following course sets");
436 		} else {
437 			header.setHTML("<b>" + selectedCourseCd + "</b> is a/an <b>" + dependencyTypeName + "</b> for the following " + dependencySectionKey);			
438 		}
439     	header.setStyleName("KS-DependencyType-Label");
440 		return header;
441 	}
442 	
443 	/*
444 	 * This generates the title for the actual dependency (eg. course, course set, program), which may include links to 
445 	 * view the actual course, course set or program
446 	 */
447 	private SpanPanel getDependencyLabel(final String dependencySectionKey, String dependencyType, final String cluId,  String cluCode, String cluName, final String cluType, boolean diffAdminOrg, final String parentCluId){
448 		
449 		//Figure out the view hyperlink for course/program/course set screen based on dependencyType
450 		Anchor viewLinkAnchor = null;
451 		final String viewLinkUrl;
452 		if (LUUIConstants.CLU_TYPE_CREDIT_COURSE.equals(cluType) && 
453 				!LUUIConstants.DEP_TYPE_CROSS_LISTED.equals(dependencyType)){
454 			viewLinkAnchor = new Anchor("View Course");
455 			viewLinkUrl = AppLocations.Locations.VIEW_COURSE.toString(); 
456 		} else if ("kuali.lu.type.MajorDiscipline".equals(cluType) || "kuali.lu.type.Variation".equals(cluType)){
457 			viewLinkAnchor = new Anchor("View Program ");
458 			viewLinkUrl = AppLocations.Locations.VIEW_PROGRAM.toString(); 
459 		} else if ("kuali.lu.type.CoreProgram".equals(cluType)){
460 			viewLinkAnchor = new Anchor("View Program ");
461 			viewLinkUrl = AppLocations.Locations.VIEW_CORE_PROGRAM.toString(); 
462 		} else if (cluType.startsWith("kuali.lu.type.credential")){
463 			viewLinkAnchor = new Anchor("View Program ");
464 			viewLinkUrl = AppLocations.Locations.VIEW_BACC_PROGRAM.toString(); 
465 		} else if (LUUIConstants.DEP_TYPE_COURSE_SET.equals(dependencyType)){
466 			viewLinkAnchor = new Anchor("View Course Set");
467 			viewLinkUrl = AppLocations.Locations.VIEW_CLU_SET.toString();
468 		} else {
469 			viewLinkUrl = null;
470 		}
471 		
472 		//Add click handler to open new window for user to view the course/program/cluset in more detail
473 		if (viewLinkAnchor != null){
474 	    	viewLinkAnchor.addStyleName("KS-Dependency-View-Link");
475 	        viewLinkAnchor.addClickHandler(new ClickHandler(){
476 	
477 				@Override
478 				public void onClick(ClickEvent event) {
479 					String url =  "http://" + Window.Location.getHost() + Window.Location.getPath() +
480 						"?view=" + viewLinkUrl;
481 					if("kuali.lu.type.Variation".equals(cluType)){
482 					    url += "&docId=" + URL.encodeQueryString(parentCluId) + "&variationId=" + URL.encodeQueryString(cluId);
483 					}else {
484 					    url += "&docId=" + URL.encodeQueryString(cluId);
485 					}
486 					String features = "height=600,width=960,dependent=0,directories=1," +
487 							"fullscreen=1,location=1,menubar=1,resizable=1,scrollbars=1,status=1,toolbar=1";
488 					Window.open(url, HTMLPanel.createUniqueId(), features);				
489 				}
490 			});
491 		}		
492 			
493 		//Determine if we need to display differing org highlight
494 		String orgHighlight = (diffAdminOrg ? " <span class=\"ks-dependency-highlight\">Different Org</span> ":"");
495 		
496 		//Create dependency item header label
497 		String headerLabel = "";
498 		if (LUUIConstants.DEP_TYPE_CROSS_LISTED.equals(dependencyType)){
499 			headerLabel = cluCode + " - " + selectedCourseName + orgHighlight;
500 		} else if (LUUIConstants.DEP_TYPE_COURSE_SET.equals(dependencyType)){
501 			headerLabel = cluName;
502 		} else {
503 			headerLabel = cluCode + " - " + cluName + orgHighlight;
504 		}
505     	
506 		//Build header widget to return
507 		SpanPanel header = new SpanPanel();		
508 		header.setStyleName("KS-DependencyType-Label");	
509 		header.setHTML(headerLabel);
510 		if (viewLinkAnchor != null){
511 			header.add(viewLinkAnchor);
512 		}
513 		
514 		return header;		
515 	}
516 
517 	protected boolean hasDependencyDetails(String dependencyType){
518 		//Only course and programs have dependency details, since there could be multiple program types, easier to
519 		//check those that don't have details to show.
520 		return !(LUUIConstants.DEP_TYPE_JOINT.equals(dependencyType) || 
521 					LUUIConstants.DEP_TYPE_CROSS_LISTED.equals(dependencyType) || 
522 					LUUIConstants.DEP_TYPE_COURSE_SET.equals(dependencyType));
523 	}
524 	
525     private String getTotalCreditsString(int min, int max) {
526         return "Expected Total Credits:" + min + "-" + max;
527     }
528 
529     //TODO: This code copied from Program summary, need to create reusable version for this and program summary
530     protected Map<String, Widget> getCluSetWidgetList(StatementTreeViewInfo rule) {
531         Map<String, Widget> widgetList = new HashMap<String, Widget>();
532         Set<String> cluSetIds = new HashSet<String>();
533         findCluSetIds(rule, cluSetIds);
534         for (String clusetId : cluSetIds) {
535             widgetList.put(clusetId, new CluSetDetailsWidget(clusetId, cluSetRetriever));
536         }
537 
538         return widgetList;
539     }
540 
541     //TODO: This code copied from Program summary, need to create reusable version for this and program summary
542     private void findCluSetIds(StatementTreeViewInfo rule, Set<String> list) {
543 
544         List<StatementTreeViewInfo> statements = rule.getStatements();
545         List<ReqComponentInfo> reqComponentInfos = rule.getReqComponents();
546 
547         if ((statements != null) && (statements.size() > 0)) {
548             // retrieve all statements
549             for (StatementTreeViewInfo statement : statements) {
550                 findCluSetIds(statement, list); // inside set the children of this statementTreeViewInfo
551             }
552         } else if ((reqComponentInfos != null) && (reqComponentInfos.size() > 0)) {
553             // retrieve all req. component LEAFS
554             for (ReqComponentInfo reqComponent : reqComponentInfos) {
555                 List<ReqCompFieldInfo> fieldInfos = reqComponent.getReqCompFields();
556                 for (ReqCompFieldInfo fieldInfo : fieldInfos) {
557                     if (RulesUtil.isCluSetWidget(fieldInfo.getType())) {
558                         list.add(fieldInfo.getValue());
559                     }
560                 }
561             }
562         }
563     }
564 
565 	public KSDocumentHeader getHeader() {
566 		return header;
567 	}
568 
569 	@Override
570 	public boolean isExportButtonActive() {
571 		return true;
572 	}
573 
574 	public DependencyResultPanel getDepResultPanel() {
575 		return depResultPanel;
576 	}
577 
578 }