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