001    package org.kuali.student.lum.common.client.widgets;
002    
003    import java.util.ArrayList;
004    import java.util.HashMap;
005    import java.util.List;
006    import java.util.Map;
007    
008    import org.kuali.student.common.ui.client.application.Application;
009    import org.kuali.student.common.ui.client.configurable.mvc.FieldDescriptor;
010    import org.kuali.student.common.ui.client.configurable.mvc.WidgetConfigInfo;
011    import org.kuali.student.common.ui.client.configurable.mvc.binding.HasDataValueBinding;
012    import org.kuali.student.common.ui.client.configurable.mvc.binding.ModelWidgetBindingSupport;
013    import org.kuali.student.common.ui.client.configurable.mvc.sections.Section;
014    import org.kuali.student.common.ui.client.configurable.mvc.sections.VerticalSection;
015    import org.kuali.student.common.ui.client.configurable.mvc.views.VerticalSectionView;
016    import org.kuali.student.common.ui.client.mvc.Callback;
017    import org.kuali.student.common.ui.client.mvc.DataModel;
018    import org.kuali.student.common.ui.client.mvc.DataModelDefinition;
019    import org.kuali.student.common.ui.client.mvc.HasDataValue;
020    import org.kuali.student.common.ui.client.widgets.KSDropDown;
021    import org.kuali.student.common.ui.client.widgets.KSItemLabel;
022    import org.kuali.student.common.ui.client.widgets.KSLabel;
023    import org.kuali.student.common.ui.client.widgets.field.layout.element.MessageKeyInfo;
024    import org.kuali.student.common.ui.client.widgets.layout.VerticalFlowPanel;
025    import org.kuali.student.common.ui.client.widgets.list.KSSelectedList;
026    import org.kuali.student.common.ui.client.widgets.list.SelectionChangeEvent;
027    import org.kuali.student.common.ui.client.widgets.list.SelectionChangeHandler;
028    import org.kuali.student.common.ui.client.widgets.list.impl.SimpleListItems;
029    import org.kuali.student.common.ui.client.widgets.menus.KSListPanel;
030    import org.kuali.student.common.ui.client.widgets.progress.BlockingTask;
031    import org.kuali.student.common.ui.client.widgets.progress.KSBlockingProgressIndicator;
032    import org.kuali.student.common.ui.client.widgets.search.KSPicker;
033    import org.kuali.student.r1.common.assembly.data.Data;
034    import org.kuali.student.r1.common.assembly.data.Data.DataValue;
035    import org.kuali.student.r1.common.assembly.data.Data.Value;
036    import org.kuali.student.r1.common.assembly.data.LookupMetadata;
037    import org.kuali.student.r1.common.assembly.data.LookupParamMetadata;
038    import org.kuali.student.r1.common.assembly.data.Metadata;
039    import org.kuali.student.r1.common.assembly.data.QueryPath;
040    import org.kuali.student.r2.core.search.dto.SearchParamInfo;
041    import org.kuali.student.r2.core.search.dto.SearchRequestInfo;
042    import org.kuali.student.r2.lum.clu.dto.MembershipQueryInfo;
043    
044    import com.google.gwt.core.client.GWT;
045    import com.google.gwt.dom.client.Style;
046    import com.google.gwt.event.dom.client.ClickEvent;
047    import com.google.gwt.event.dom.client.ClickHandler;
048    import com.google.gwt.event.logical.shared.CloseEvent;
049    import com.google.gwt.event.logical.shared.CloseHandler;
050    import com.google.gwt.event.shared.HandlerRegistration;
051    import com.google.gwt.user.client.Timer;
052    import com.google.gwt.user.client.ui.HTML;
053    import com.google.gwt.user.client.ui.Panel;
054    import com.google.gwt.user.client.ui.Widget;
055    
056    public class CluSetEditorWidget extends VerticalSectionView {
057    
058        private List<KSSelectedListPanelPair> selectedListPanelPairs = new ArrayList<KSSelectedListPanelPair>();
059        private DataModelDefinition modelDefinition;
060    //    private final List<HandlerRegistration> showClusetDetailsHandlerRegs = new ArrayList<HandlerRegistration>(); 
061        private final Map<String, HandlerRegistration> showCluRangeDetailsHandlerRegs = new HashMap<String, HandlerRegistration>();
062        private List<KSItemLabelPanelPair> itemLabelPanelPairs = new ArrayList<KSItemLabelPanelPair>();
063        protected static String cluSetType;
064        private String metadataId;
065        private static Map<String, DataModelDefinition> modelDefinitionCache = new HashMap<String, DataModelDefinition>();
066        private BlockingTask initializeTask = new BlockingTask("Initializing");
067        protected static boolean singularCluOnly;
068        private KSSelectedList approvedClusSelection;
069        
070        private enum CluSetManagementField {
071            APPROVED, PROPOSED, CLUSETS, RANGE
072        }
073        
074        public CluSetEditorWidget() {
075            super();
076        }
077    
078        public CluSetEditorWidget(CluSetRetriever cluSetRetriever, Enum<?> viewEnum,
079                String name, String modelId, boolean showTitle,
080                final Callback<Boolean> onReady, String cluSetType, boolean singularCluOnly) {
081            super(viewEnum, name, modelId, showTitle);
082            CluSetEditorWidget.cluSetType = cluSetType;
083            CluSetEditorWidget.singularCluOnly = singularCluOnly;
084            if (cluSetType != null && cluSetType.equals("kuali.cluSet.type.Program")) {
085                this.metadataId = "programSet";
086            } else {
087                this.metadataId = "courseSet";
088            }
089            KSBlockingProgressIndicator.addTask(initializeTask);
090            if (modelDefinitionCache.get(metadataId) == null) {
091                cluSetRetriever.getMetadata(metadataId, new Callback<Metadata>(){
092                    @Override
093                    public void exec(Metadata result) {
094                        DataModelDefinition def = new DataModelDefinition(result);
095                        modelDefinitionCache.put(metadataId, def);
096                        setDef(def);
097                        setupEditor();
098                        if (onReady != null) {
099                            onReady.exec(new Boolean(true));
100                        }
101                        KSBlockingProgressIndicator.removeTask(initializeTask);                
102                    }
103                });
104            } else {
105                DataModelDefinition def = modelDefinitionCache.get(metadataId);
106                setDef(def);
107                setupEditor();
108                if (onReady != null) {
109                    onReady.exec(new Boolean(true));
110                }
111                KSBlockingProgressIndicator.removeTask(initializeTask);                
112            }
113        }
114        
115        private void setDef(DataModelDefinition def) {
116            this.modelDefinition = def;
117        }
118        
119        public void setupEditor() {
120            String labelType = null;
121            if (cluSetType == null || !cluSetType.equals("kuali.cluSet.type.Program")) {
122                labelType = "Course";
123            } else {
124                labelType = "Program";
125            }
126            final CluSetEditOptionDropdown chooser = GWT.create(CluSetEditOptionDropdown.class);
127            SwitchSection clusetDetails = new SwitchSection(
128                    chooser,
129                    null);
130            clusetDetails.enableConfirmation(false);
131            // ****** Add Approved Clus *******
132            Section approvedClusSection = new VerticalSection();
133            FieldDescriptor approvedClusFd = addField(approvedClusSection, 
134                    CommonWidgetConstants.CLU_SET_APPROVED_CLUS_FIELD, 
135                    generateMessageInfo(CommonWidgetConstants.NEW_CLU_SET_CONTENT_APPROVED + labelType),
136                    null,
137                    null);
138            approvedClusSelection = (KSSelectedList) approvedClusFd.getFieldWidget();
139            KSListPanel approvedClusListPanel = approvedClusSelection.separateValuesPanel();
140            clusetDetails.addSection(approvedClusSection, CommonWidgetConstants.CLU_SET_SWAP_APPROVED_CLUS);
141            // END OF items related to Add Approved Clus
142    
143            // ****** Add Proposed Clus *******
144            Section proposedClusSection = new VerticalSection();
145            FieldDescriptor proposedClusFd = addField(proposedClusSection, 
146                    CommonWidgetConstants.CLU_SET_PROPOSED_CLUS_FIELD, 
147                    generateMessageInfo(CommonWidgetConstants.NEW_CLU_SET_CONTENT_PROPOSED + labelType),
148                    null,
149                    null);
150            final KSSelectedList proposedClusSelection = (KSSelectedList) proposedClusFd.getFieldWidget();
151            KSListPanel proposedClusListPanel = proposedClusSelection.separateValuesPanel();
152            clusetDetails.addSection(proposedClusSection, CommonWidgetConstants.CLU_SET_SWAP_PROPOSED_CLUS);
153            // END OF items related to Add Approved Clus
154    
155            // ****** Add Clu Range *******
156            KSItemLabel clusetRangeLabel = null;
157            if (displayField(CluSetManagementField.RANGE)) {
158                Section cluRangeSection = new VerticalSection();
159                final Picker cluSetRangePicker = configureSearch(CommonWidgetConstants.CLU_SET_CLU_SET_RANGE_EDIT_FIELD);
160                addField(cluRangeSection, 
161                        CommonWidgetConstants.CLU_SET_CLU_SET_RANGE_EDIT_FIELD, 
162                        generateMessageInfo(CommonWidgetConstants.NEW_CLU_SET_CONTENT_RANGE + labelType),
163                        cluSetRangePicker,
164                        null);
165                final CluSetRangeDataHelper clusetRangeModelHelper = new CluSetRangeDataHelper();
166                clusetRangeLabel = new KSItemLabel(true, true, clusetRangeModelHelper);
167                final KSItemLabel theClusetRangeLabel = clusetRangeLabel;
168                clusetRangeLabel.getElement().getStyle().setProperty("border", "solid 1px #cdcdcd");
169                clusetRangeLabel.getElement().getStyle().setProperty("width", "354px");
170                final FieldDescriptor cluRangeFieldDescriptor = addField(
171                        cluRangeSection, 
172                        CommonWidgetConstants.CLU_SET_CLU_SET_RANGE_FIELD, 
173                        null, 
174                        clusetRangeLabel,
175                        null);
176                cluRangeFieldDescriptor.setWidgetBinding(new CluSetRangeBinding(clusetRangeModelHelper));
177                cluSetRangePicker.getSearchWindow().addActionCompleteCallback(new Callback<Boolean>() {
178                    @Override
179                    public void exec(Boolean result) {
180                        cluSetRangePicker.getSearchWindow().hide();
181    //                  ((ModelWidgetBinding)cluRangeFieldDescriptor.getModelWidgetBinding()).setWidgetValue(widget, model, path)
182    //                  CluSetHelper cluSetHelper = CluSetHelper.wrap(model.getRoot());
183    //                  cluSetHelper.setCluRangeParams(value)
184                        final SearchRequestInfo searchRequest = cluSetRangePicker.getSearchWindow().getSearchRequest();
185                        String selectedSearchKey = searchRequest.getSearchKey();
186                        Data searchRequestData = CluSetRangeModelUtil.INSTANCE.toData(searchRequest, null);
187                        LookupMetadata lookupMetadata = null;
188    
189                        // look for the lookupMetaData corresponding to the searchRequest
190                        List<LookupMetadata> lookupMDs = new ArrayList<LookupMetadata>();
191                        lookupMDs.add(cluSetRangePicker.getInitLookupMetadata());
192                        lookupMetadata = findLookupMetadataByLookupId(selectedSearchKey, 
193                                lookupMDs, searchRequest.getParams());
194                        if (lookupMetadata == null || 
195                                !nullSafeEquals(lookupMetadata.getSearchTypeId(), 
196                                        selectedSearchKey)) {
197                            lookupMetadata = findLookupMetadataByLookupId(selectedSearchKey, 
198                                    cluSetRangePicker.getAdditionalLookupMetadata(),
199                                    searchRequest.getParams());
200                        }
201    
202                        addClusetItemViewHandler(clusetRangeModelHelper,
203                                theClusetRangeLabel,
204                                lookupMetadata,
205                                searchRequestData,
206                                searchRequest);
207                        theClusetRangeLabel.setHighlighted(true);
208                        new Timer() {
209                            @Override
210                            public void run() {
211                                theClusetRangeLabel.setHighlighted(false);
212                            }
213                        }.schedule(5000);
214                    }
215                });
216                clusetDetails.addSection(cluRangeSection, CommonWidgetConstants.CLU_SET_SWAP_CLU_SET_RANGE);
217            }
218            // END OF items related to Add Clu Range
219    
220            // ****** Add cluSets *******
221            KSListPanel cluSetsListPanel = null;
222            KSSelectedList cluSetsSelection = null;
223            if (displayField(CluSetManagementField.CLUSETS)) {
224                Section cluSetSection = new VerticalSection();
225                FieldDescriptor cluSetsTempFd = getFieldDescriptor( 
226                        CommonWidgetConstants.CLU_SET_CLU_SETS_FIELD, 
227                        generateMessageInfo(CommonWidgetConstants.NEW_CLU_SET_CONTENT_CLUSET + labelType),
228                        null,
229                        null);
230                KSSelectedList tempCluSetsSelection = (KSSelectedList) cluSetsTempFd.getFieldWidget();
231                WidgetConfigInfo config = tempCluSetsSelection.getConfig();
232                cluSetsSelection = new KSSelectedList(config, false);
233                cluSetsListPanel = cluSetsSelection.separateValuesPanel();
234                final FieldDescriptor cluSetsFd = addField(
235                        cluSetSection, 
236                        CommonWidgetConstants.CLU_SET_CLU_SETS_FIELD, 
237                        generateMessageInfo(CommonWidgetConstants.NEW_CLU_SET_CONTENT_CLUSET + labelType),
238                        cluSetsSelection, 
239                        null);
240                cluSetsFd.setWidgetBinding(new CluSetBinding());
241                clusetDetails.addSection(cluSetSection, CommonWidgetConstants.CLU_SET_SWAP_CLU_SETS);
242            }
243            // END OF items related to Add CluSets
244    
245            // display item type title if the list selected items is populated
246            // hide if the list becomes empty (thus the close listeners for each item
247            String contextName = (cluSetType != null && cluSetType.equals("kuali.cluSet.type.Program"))?
248                    "PROGRAMS" : "COURSES";
249            VerticalFlowPanel selectedValuesPanel = new VerticalFlowPanel();
250            selectedValuesPanel.getElement().getStyle().setPaddingTop(20, Style.Unit.PX);
251            VerticalFlowPanel approvedClusPanel = prepareValuesPanel(approvedClusListPanel, "APPROVED " + contextName);
252            approvedClusPanel.getElement().getStyle().setPaddingTop(15, Style.Unit.PX);
253            VerticalFlowPanel proposedClusPanel = prepareValuesPanel(proposedClusListPanel, "PROPOSED " + contextName);
254            proposedClusPanel.getElement().getStyle().setPaddingTop(15, Style.Unit.PX);
255            VerticalFlowPanel rangePanel = null;
256            if (displayField(CluSetManagementField.RANGE)) {
257                rangePanel = prepareValuesPanel(clusetRangeLabel, contextName + " RANGE");
258                rangePanel.getElement().getStyle().setPaddingTop(15, Style.Unit.PX);
259            }
260            VerticalFlowPanel cluSetsPanel = null;
261            if (displayField(CluSetManagementField.CLUSETS)) {
262                cluSetsPanel = prepareValuesPanel(cluSetsListPanel, contextName + " SETS");
263                cluSetsPanel.getElement().getStyle().setPaddingTop(15, Style.Unit.PX);
264            }
265            
266            selectedValuesPanel.add(approvedClusPanel);
267            selectedValuesPanel.add(proposedClusPanel);
268            if (displayField(CluSetManagementField.RANGE)) {
269                selectedValuesPanel.add(rangePanel);
270            }
271            if (displayField(CluSetManagementField.CLUSETS)) {
272                selectedValuesPanel.add(cluSetsPanel);
273            }
274    
275            addVisibilityHandlers(approvedClusSelection, approvedClusPanel);
276            addVisibilityHandlers(proposedClusSelection, proposedClusPanel);
277            if (displayField(CluSetManagementField.RANGE)) {
278                addVisibilityHandlers(clusetRangeLabel, rangePanel);
279            }
280            if (displayField(CluSetManagementField.CLUSETS)) {
281                addVisibilityHandlers(cluSetsSelection, cluSetsPanel);
282            }
283            
284            selectedListPanelPairs.add(new KSSelectedListPanelPair(approvedClusSelection, approvedClusPanel));
285            selectedListPanelPairs.add(new KSSelectedListPanelPair(proposedClusSelection, proposedClusPanel));
286            if (displayField(CluSetManagementField.CLUSETS)) {
287                selectedListPanelPairs.add(new KSSelectedListPanelPair(cluSetsSelection, cluSetsPanel));
288            }
289            if (displayField(CluSetManagementField.RANGE)) {
290                itemLabelPanelPairs.add(new KSItemLabelPanelPair(clusetRangeLabel, rangePanel));
291            }
292            
293            final VerticalSection choosingSection = new VerticalSection();
294            HTML prompt;
295            if(cluSetType.equals("kuali.cluSet.type.Program")){
296                choosingSection.addWidget(new HTML(Application
297                        .getApplicationContext().getMessage(CommonWidgetConstants.CLU_SET_ADD_PROGRAM_LABEL)));
298                prompt = new HTML(Application
299                        .getApplicationContext().getMessage(CommonWidgetConstants.CLU_SET_MANAGEMENT_PROGRAM_INSTRUCTIONS));
300            }
301            else{
302                choosingSection.addWidget(new HTML(Application
303                        .getApplicationContext().getMessage(CommonWidgetConstants.CLU_SET_ADD_COURSE_LABEL)));
304                prompt = new HTML(Application
305                        .getApplicationContext().getMessage(CommonWidgetConstants.CLU_SET_MANAGEMENT_COURSE_INSTRUCTIONS));
306            }
307            choosingSection.addWidget(chooser);
308            choosingSection.addSection(clusetDetails);
309            chooser.addSelectionChangeHandler(new SelectionChangeHandler() {
310                @Override
311                public void onSelectionChange(SelectionChangeEvent event) {
312                    if (chooser.getSelectedItem() != null &&
313                            !chooser.getSelectedItem().trim().isEmpty()) {
314                        choosingSection.setStyleName("KS-CluSetManagement-chooser");
315                    } else {
316                        choosingSection.setStyleName("KS-CluSetManagement-chooser-unselected");
317                    }
318                }
319            });
320            
321            this.addWidget(prompt);
322            this.addSection(choosingSection);
323            this.addWidget(selectedValuesPanel);
324        }
325        
326        private boolean displayField(CluSetManagementField field) {
327            boolean result = false;
328            switch(field) {
329                case APPROVED:
330                case PROPOSED:
331                    result = true;
332                    break;
333                case RANGE:
334                    if (!singularCluOnly && (cluSetType == null || !cluSetType.equals("kuali.cluSet.type.Program"))) {
335                        result = true;
336                    } else {
337                        result = false;
338                    }
339                    break;
340                case CLUSETS:
341                    if (!singularCluOnly) {
342                        result = true;
343                    } else {
344                        result = false;
345                    }
346                    break;
347            }
348            return result;
349        }
350        
351        private void addClusetItemViewHandler(CluSetRangeDataHelper clusetRangeModelHelper,
352                KSItemLabel clusetRangeLabel,
353                final LookupMetadata lookupMetadata,
354                Data searchRequestData,
355                final SearchRequestInfo searchRequest) {
356            clusetRangeModelHelper.setLookupMetadata(lookupMetadata);
357            clusetRangeLabel.setValue(new DataValue(searchRequestData));
358            if (showCluRangeDetailsHandlerRegs != null && 
359                    showCluRangeDetailsHandlerRegs.get(Integer.toString(clusetRangeLabel.instanceId)) != null) {
360                ((HandlerRegistration)showCluRangeDetailsHandlerRegs.get(Integer.toString(clusetRangeLabel.instanceId))).removeHandler();
361            }
362            showCluRangeDetailsHandlerRegs.put(Integer.toString(clusetRangeLabel.instanceId), 
363                    clusetRangeLabel.addShowDetailsHandler(new ClickHandler() {
364                @Override
365                public void onClick(ClickEvent event) {
366                    SearchResultsLightBox srLightBox = new SearchResultsLightBox("View Course Range",
367                            searchRequest, lookupMetadata);
368                    srLightBox.show();
369                }
370            }));
371        }
372        
373        protected MessageKeyInfo generateMessageInfo(String labelKey) {
374            return new MessageKeyInfo("clusetmanagement", "clusetmanagement", "draft", labelKey);
375        }
376        
377        private FieldDescriptor getFieldDescriptor( 
378                String fieldKey, 
379                MessageKeyInfo messageKey, 
380                Widget widget, 
381                String parentPath) {
382            QueryPath path = QueryPath.concat(parentPath, fieldKey);
383            Metadata meta = modelDefinition.getMetadata(path);
384            FieldDescriptor fd;
385            if (widget != null) {
386                fd = new FieldDescriptor(path.toString(), messageKey, meta, widget);
387            }
388            else{
389                fd = new FieldDescriptor(path.toString(), messageKey, meta);
390            }
391            return fd;
392        }
393    
394        private FieldDescriptor addField(Section section, 
395                String fieldKey, 
396                MessageKeyInfo messageKey, 
397                Widget widget, 
398                String parentPath) {
399            FieldDescriptor fd = getFieldDescriptor(fieldKey, messageKey, widget, parentPath);
400            section.addField(fd);
401            return fd;
402        }
403    
404        private static boolean nullSafeEquals(Object obj1, Object obj2) {
405            return (obj1 == null && obj2 == null ||
406                    obj1 != null && obj2 != null && obj1.equals(obj2));
407        }
408        
409        private VerticalFlowPanel prepareValuesPanel(Widget widget, String title) {
410            final VerticalFlowPanel valuesPanel = new VerticalFlowPanel();
411            valuesPanel.add(new KSLabel(title));
412            valuesPanel.add(widget);
413            valuesPanel.setVisible(false);
414            return valuesPanel;
415        }
416        
417        @Override
418        public void updateWidgetData(DataModel model) {
419            super.updateWidgetData(model);
420            // this is to refresh the lists and item labels.
421            if (selectedListPanelPairs != null) {
422                for (KSSelectedListPanelPair selectedListPanelPair : selectedListPanelPairs) {
423                    handleSelectedListVisibility(selectedListPanelPair.getKsSelectedList(), 
424                            selectedListPanelPair.getPanel());
425                }
426            }
427            if (itemLabelPanelPairs != null) {
428                for (KSItemLabelPanelPair itemLabelPanelPair : itemLabelPanelPairs) {
429                    handleListItemVisibility(itemLabelPanelPair.getKsItemLabel(), 
430                            itemLabelPanelPair.getPanel());
431                }
432            }
433        }
434    
435        private void addVisibilityHandlers(final KSItemLabel listItem,
436                final Panel selectionPanel) {
437            listItem.addValueChangeCallback(new Callback<Value>() {
438                @Override
439                public void exec(Value result) {
440                    handleListItemVisibility(listItem, selectionPanel);
441                }
442            });
443        }
444        
445        private void handleListItemVisibility(KSItemLabel listItem, Panel selectionPanel) {
446            String displayText = listItem.getDisplayText();
447            if (displayText == null || displayText.equals("")) {
448                selectionPanel.setVisible(false);
449            } else {
450                selectionPanel.setVisible(true);
451            }
452        }
453        
454        private void addVisibilityHandlers(final KSSelectedList selectionList,
455                final Panel selectionPanel) {
456            selectionList.addSelectionChangeHandler(
457                    new SelectionChangeHandler() {
458                        @Override
459                        public void onSelectionChange(SelectionChangeEvent event) {
460                            handleSelectedListVisibility(selectionList, selectionPanel);
461                        }
462                    }
463            );
464        }
465        
466        private void handleSelectedListVisibility(final KSSelectedList selectionList, final Panel selectionPanel) {
467            List<KSItemLabel> selectedItems = selectionList.getSelectedItems();
468            if (selectedItems != null && !selectedItems.isEmpty()) {
469                // show item type title
470                selectionPanel.setVisible(true);
471                for (KSItemLabel selectedItem : selectedItems) {
472                    selectedItem.addCloseHandler(new CloseHandler<KSItemLabel>() {
473                        @Override
474                        public void onClose(CloseEvent<KSItemLabel> event) {
475                            List<KSItemLabel> newSelectedItems = 
476                                selectionList.getSelectedItems();
477                            int numNewSelectedItems = (newSelectedItems == null)? 0 :
478                                newSelectedItems.size();
479                            if (numNewSelectedItems == 0) {
480                                //hide item type title
481                                selectionPanel.setVisible(false);
482                            }
483                        }
484                    });
485                }
486            }
487        }
488    
489        private Picker configureSearch(String fieldKey) {
490            QueryPath path = QueryPath.concat(null, fieldKey);
491            Metadata metaData = modelDefinition.getMetadata(path);
492            Picker picker = new Picker(metaData.getInitialLookup(), metaData.getAdditionalLookups());
493            return picker;
494        }
495    
496        private static LookupMetadata findLookupMetadataByLookupId(String searchTypeId,
497                List<LookupMetadata> lookupMetadatas,
498                List<SearchParamInfo> searchParams) {
499            LookupMetadata result = null;
500            if (lookupMetadatas != null) {
501                for (LookupMetadata lookupMetadata : lookupMetadatas) {
502                    if (nullSafeEquals(lookupMetadata.getSearchTypeId(), searchTypeId)) {
503                        // search Type id matches now add up all the params meta found to the result
504                        List<LookupParamMetadata> paramMetas = lookupMetadata.getParams();
505                        List<LookupParamMetadata> resultParamMetas = null;
506                        result = (result == null)? new LookupMetadata() : result;
507                        result.setDesc(lookupMetadata.getDesc());
508                        result.setId(lookupMetadata.getId());
509                        result.setName("");
510                        resultParamMetas = result.getParams();
511                        if (resultParamMetas == null) {
512                            resultParamMetas = new ArrayList<LookupParamMetadata>();
513                        }
514                        if (paramMetas != null) {
515                            for (LookupParamMetadata paramMeta : paramMetas) {
516                                boolean resultParamMetaFound = false;
517                                for (LookupParamMetadata resultParamMeta : resultParamMetas) {
518                                    if (paramMeta.getKey().equals(resultParamMeta)) {
519                                        resultParamMetaFound = true;
520                                        break;
521                                    }
522                                }
523                                if (!resultParamMetaFound) {
524                                    resultParamMetas.add(paramMeta);
525                                }
526                            }
527                        }
528                        result.setParams(resultParamMetas);
529                        result.setQosMetadata(lookupMetadata.getQosMetadata());
530                        result.setResultDisplayKey(lookupMetadata.getResultDisplayKey());
531                        result.setResultReturnKey(lookupMetadata.getResultReturnKey());
532                        result.setResults(lookupMetadata.getResults());
533                        result.setResultSortKey(lookupMetadata.getResultSortKey());
534                    }
535                }
536            }
537            return result;
538        }
539        
540        @Override
541        public void updateModel() {
542            
543            super.updateModel();
544        }
545    
546    
547    
548        public static class CluSetEditOptionDropdown extends KSDropDown {
549            public CluSetEditOptionDropdown(){
550                SimpleListItems editOptions = new SimpleListItems();
551    
552                if (cluSetType != null && cluSetType.equals("kuali.cluSet.type.Program")) {
553                    editOptions.addItem(CommonWidgetConstants.CLU_SET_SWAP_APPROVED_CLUS, "Approved Programs");
554                    editOptions.addItem(CommonWidgetConstants.CLU_SET_SWAP_PROPOSED_CLUS, "Proposed Programs");
555                    if (!singularCluOnly) {
556                        editOptions.addItem(CommonWidgetConstants.CLU_SET_SWAP_CLU_SETS, "Program Sets");
557                    }
558                } else {
559                    editOptions.addItem(CommonWidgetConstants.CLU_SET_SWAP_APPROVED_CLUS, Application
560                            .getApplicationContext().getMessage("clusetmanagement",
561                                    CommonWidgetConstants.CLU_SET_APPROVED_COURSE));
562                    editOptions.addItem(CommonWidgetConstants.CLU_SET_SWAP_PROPOSED_CLUS, Application
563                            .getApplicationContext().getMessage("clusetmanagement",
564                                    CommonWidgetConstants.CLU_SET_PROPOSED_COURSE));
565                    if (!singularCluOnly) {
566                        editOptions.addItem(CommonWidgetConstants.CLU_SET_SWAP_CLU_SETS, "Course Sets");
567                        editOptions.addItem(CommonWidgetConstants.CLU_SET_SWAP_CLU_SET_RANGE, "Course Ranges (Course numbers, common learning objectives, etc)");
568                    }
569                }
570                super.setListItems(editOptions);
571            }
572        }
573    
574        class KSSelectedListPanelPair {
575            private KSSelectedList ksSelectedList;
576            private Panel panel;
577            public KSSelectedListPanelPair(KSSelectedList ksSelectedList, Panel panel) {
578                setKsSelectedList(ksSelectedList);
579                setPanel(panel);
580            }
581            public KSSelectedList getKsSelectedList() {
582                return ksSelectedList;
583            }
584            public void setKsSelectedList(KSSelectedList ksSelectedList) {
585                this.ksSelectedList = ksSelectedList;
586            }
587            public Panel getPanel() {
588                return panel;
589            }
590            public void setPanel(Panel panel) {
591                this.panel = panel;
592            }
593        }
594        
595        class KSItemLabelPanelPair {
596            private KSItemLabel ksItemLabel;
597            private Panel panel;
598            public KSItemLabelPanelPair(KSItemLabel ksItemLabel, Panel panel) {
599                setKsItemLabel(ksItemLabel);
600                setPanel(panel);
601            }
602            public KSItemLabel getKsItemLabel() {
603                return ksItemLabel;
604            }
605            public void setKsItemLabel(KSItemLabel ksItemLabel) {
606                this.ksItemLabel = ksItemLabel;
607            }
608            public Panel getPanel() {
609                return panel;
610            }
611            public void setPanel(Panel panel) {
612                this.panel = panel;
613            }
614        }
615        
616        public static class Picker extends KSPicker {
617    
618            private String name;
619            private LookupMetadata initLookupMetadata;
620            private List<LookupMetadata> additionalLookupMetadata;
621    
622            public Picker(LookupMetadata inLookupMetadata, List<LookupMetadata> additionalLookupMetadata) {
623                super.init(inLookupMetadata, additionalLookupMetadata);
624                this.initLookupMetadata = inLookupMetadata;
625                this.additionalLookupMetadata = additionalLookupMetadata;
626            }
627    
628            public String getName() {
629                return name;
630            }
631    
632            public void setName(String name) {
633                this.name = name;
634            }
635    
636            public LookupMetadata getInitLookupMetadata() {
637                return initLookupMetadata;
638            }
639    
640            public void setInitLookupMetadata(LookupMetadata initLookupMetadata) {
641                this.initLookupMetadata = initLookupMetadata;
642            }
643    
644            public List<LookupMetadata> getAdditionalLookupMetadata() {
645                return additionalLookupMetadata;
646            }
647    
648            public void setAdditionalLookupMetadata(List<LookupMetadata> additionalLookupMetadata) {
649                this.additionalLookupMetadata = additionalLookupMetadata;
650            }
651            
652        }
653        
654        public class CluSetBinding extends ModelWidgetBindingSupport<HasDataValue> {
655            private HasDataValueBinding binding = HasDataValueBinding.INSTANCE;
656    
657            @Override
658            public void setModelValue(HasDataValue widget, DataModel model, String path) {
659                binding.setModelValue(widget, model, path);
660            }
661    
662            @Override
663            public void setWidgetValue(HasDataValue widget, DataModel model, String path) {
664                binding.setWidgetValue(widget, model, path);
665            }
666        }
667        
668        public class CluSetRangeBinding extends ModelWidgetBindingSupport<HasDataValue> {
669            private HasDataValueBinding binding = HasDataValueBinding.INSTANCE;
670            private CluSetRangeDataHelper clusetRangeModelHelper = null;
671            
672            public CluSetRangeBinding(CluSetRangeDataHelper clusetRangeModelHelper) {
673                this.clusetRangeModelHelper = clusetRangeModelHelper;
674            }
675            
676            @Override
677            public void setModelValue(HasDataValue widget, DataModel model, String path) {
678                binding.setModelValue(widget, model, path);
679            }
680    
681            @Override
682            public void setWidgetValue(final HasDataValue widget, DataModel model, String path) {
683                DataModel middleManModel = new DataModel();
684                if (model != null && model.getRoot() != null) {
685                    middleManModel = new DataModel(model.getDefinition(), model.getRoot().copy());
686                }
687                Metadata rangeEditMetaData = model.getMetadata(
688                        QueryPath.parse(CommonWidgetConstants.CLU_SET_CLU_SET_RANGE_EDIT_FIELD));
689                Data membershipQueryData = (Data)model.get(path);
690                MembershipQueryInfo membershipQueryInfo = (membershipQueryData == null)?
691                        null : CluSetRangeModelUtil.INSTANCE.toMembershipQueryInfo(membershipQueryData);
692                if (membershipQueryInfo != null) {
693                    String selectedSearchTypeKey = membershipQueryInfo.getSearchTypeKey();
694                    List<LookupMetadata> lookupMDs = new ArrayList<LookupMetadata>();
695                    List<SearchParamInfo> searchParams = membershipQueryInfo.getQueryParamValues();
696                    lookupMDs.add(rangeEditMetaData.getInitialLookup());
697                    LookupMetadata lookupMetadata = findLookupMetadataByLookupId(selectedSearchTypeKey, 
698                            lookupMDs, searchParams);
699                    if (lookupMetadata == null || 
700                            !nullSafeEquals(lookupMetadata.getName(), 
701                                    selectedSearchTypeKey)) {
702                        lookupMetadata = findLookupMetadataByLookupId(selectedSearchTypeKey, 
703                                rangeEditMetaData.getAdditionalLookups(), searchParams);
704                    }
705    
706                    SearchRequestInfo searchRequest = new SearchRequestInfo();
707                    searchRequest.setSearchKey(selectedSearchTypeKey);
708    //              if ()
709                    searchRequest.setParams(searchParams);
710                    searchRequest.setSortColumn(lookupMetadata.getResultSortKey());
711                    
712    //                if (showCluRangeDetailsHandlerRegs != null) {
713    //                    for (HandlerRegistration showCluRangeDetailsHandlerReg : showCluRangeDetailsHandlerRegs) {
714    //                        showCluRangeDetailsHandlerReg.removeHandler();
715    //                    }
716    //                    showCluRangeDetailsHandlerRegs.clear();
717    //                }
718                    addClusetItemViewHandler(clusetRangeModelHelper,
719                            (KSItemLabel)widget,
720                            lookupMetadata,
721                            membershipQueryData,
722                            searchRequest);
723                    ((KSItemLabel)widget).setHighlighted(true);
724                    new Timer() {
725                        @Override
726                        public void run() {
727                            ((KSItemLabel)widget).setHighlighted(false);
728                        }
729                    }.schedule(5000);
730                }
731                binding.setWidgetValue(widget, middleManModel, path);
732            }
733        }
734    }