001package org.kuali.student.lum.common.client.widgets;
002
003import java.util.ArrayList;
004import java.util.HashMap;
005import java.util.List;
006import java.util.Map;
007
008import org.kuali.student.common.ui.client.application.Application;
009import org.kuali.student.common.ui.client.configurable.mvc.FieldDescriptor;
010import org.kuali.student.common.ui.client.configurable.mvc.WidgetConfigInfo;
011import org.kuali.student.common.ui.client.configurable.mvc.binding.HasDataValueBinding;
012import org.kuali.student.common.ui.client.configurable.mvc.binding.ModelWidgetBindingSupport;
013import org.kuali.student.common.ui.client.configurable.mvc.sections.Section;
014import org.kuali.student.common.ui.client.configurable.mvc.sections.VerticalSection;
015import org.kuali.student.common.ui.client.configurable.mvc.views.VerticalSectionView;
016import org.kuali.student.common.ui.client.mvc.Callback;
017import org.kuali.student.common.ui.client.mvc.DataModel;
018import org.kuali.student.common.ui.client.mvc.DataModelDefinition;
019import org.kuali.student.common.ui.client.mvc.HasDataValue;
020import org.kuali.student.common.ui.client.widgets.KSDropDown;
021import org.kuali.student.common.ui.client.widgets.KSItemLabel;
022import org.kuali.student.common.ui.client.widgets.KSLabel;
023import org.kuali.student.common.ui.client.widgets.field.layout.element.MessageKeyInfo;
024import org.kuali.student.common.ui.client.widgets.layout.VerticalFlowPanel;
025import org.kuali.student.common.ui.client.widgets.list.KSSelectedList;
026import org.kuali.student.common.ui.client.widgets.list.SelectionChangeEvent;
027import org.kuali.student.common.ui.client.widgets.list.SelectionChangeHandler;
028import org.kuali.student.common.ui.client.widgets.list.impl.SimpleListItems;
029import org.kuali.student.common.ui.client.widgets.menus.KSListPanel;
030import org.kuali.student.common.ui.client.widgets.progress.BlockingTask;
031import org.kuali.student.common.ui.client.widgets.progress.KSBlockingProgressIndicator;
032import org.kuali.student.common.ui.client.widgets.search.KSPicker;
033import org.kuali.student.r1.common.assembly.data.Data;
034import org.kuali.student.r1.common.assembly.data.Data.DataValue;
035import org.kuali.student.r1.common.assembly.data.Data.Value;
036import org.kuali.student.r1.common.assembly.data.LookupMetadata;
037import org.kuali.student.r1.common.assembly.data.LookupParamMetadata;
038import org.kuali.student.r1.common.assembly.data.Metadata;
039import org.kuali.student.r1.common.assembly.data.QueryPath;
040import org.kuali.student.r2.core.search.dto.SearchParamInfo;
041import org.kuali.student.r2.core.search.dto.SearchRequestInfo;
042import org.kuali.student.r2.lum.clu.dto.MembershipQueryInfo;
043
044import com.google.gwt.core.client.GWT;
045import com.google.gwt.dom.client.Style;
046import com.google.gwt.event.dom.client.ClickEvent;
047import com.google.gwt.event.dom.client.ClickHandler;
048import com.google.gwt.event.logical.shared.CloseEvent;
049import com.google.gwt.event.logical.shared.CloseHandler;
050import com.google.gwt.event.shared.HandlerRegistration;
051import com.google.gwt.user.client.Timer;
052import com.google.gwt.user.client.ui.HTML;
053import com.google.gwt.user.client.ui.Panel;
054import com.google.gwt.user.client.ui.Widget;
055
056public 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}