/**
*
*/
package org.openntf.domino.xsp.helpers;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import javax.activation.UnsupportedDataTypeException;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;
import com.ibm.commons.util.StringUtil;
import com.ibm.xsp.complex.ValueBindingObjectImpl;
import com.ibm.xsp.extlib.component.picker.data.IPickerEntry;
import com.ibm.xsp.extlib.component.picker.data.IPickerOptions;
import com.ibm.xsp.extlib.component.picker.data.IPickerResult;
import com.ibm.xsp.extlib.component.picker.data.IValuePickerData;
import com.ibm.xsp.extlib.component.picker.data.SimplePickerResult;
/**
* @author Nathan T. Freeman
*
* MapValuePickerData, for use with the ValuePicker control
*/
// TODO: Remove before 3.0 - all functionality introduced in ExtLib 14
public class MapValuePickerData extends ValueBindingObjectImpl implements IValuePickerData, Serializable {
@SuppressWarnings("unused")
private static final Logger log_ = Logger.getLogger(MapValuePickerData.class.getName());
private static final long serialVersionUID = 1L;
public String searchType;
public String searchStyle;
public Boolean caseInsensitive;
public Map<String, String> options;
/**
* Enum for easy and consistent access to search type options
*
* @since org.openntf.domino.xsp 5.0.0
*/
private static enum SearchType {
SEARCH_STARTFROM("startFrom"), SEARCH_MATCH("match"), SEARCH_FTSEARCH("ftSearch");
private final String value_;
private SearchType(final String value) {
value_ = value;
}
public String getValue() {
return value_;
}
}
/**
* Enum for easy access to the search styles - jumpTo and restrictToSearch
*
* @since org.openntf.domino.xsp 5.0.0
*/
private static enum SearchStyle {
SEARCH_JUMPTO("jumpTo"), SEARCH_RESTRICTTOSEARCH("restrictToSearch");
private final String value_;
private SearchStyle(final String value) {
value_ = value;
}
public String getValue() {
return value_;
}
}
public MapValuePickerData() {
}
/**
* Gets the options for the Value Picker, from the "options" property
*
* @return Map<String, String> of values
* @since org.openntf.domino.xsp 4.5.0
*/
@SuppressWarnings("unchecked")
public Map<String, String> getOptions() {
if (options != null) {
return options;
}
ValueBinding vb = getValueBinding("options"); //$NON-NLS-1$
if (vb != null) {
Object vbVal = vb.getValue(getFacesContext());
if (vbVal instanceof Map) {
return (Map<String, String>) vbVal;
} else {
try {
throw new UnsupportedDataTypeException("Value is not a map");
} catch (UnsupportedDataTypeException e) {
e.printStackTrace();
}
}
}
return null;
}
/**
* Loads the options for the Value Picker
*
* @param options
* Map<String, String>
* @since org.openntf.domino.xsp 4.5.0
*/
public void setOptions(final Map<String, String> options) {
this.options = options;
}
/**
* Gets the search type for the picker, from the "searchType" property
*
* @return String search type
* @since org.openntf.domino.xsp 5.0.0
*/
public String getSearchType() {
if (searchType != null) {
return searchType;
}
ValueBinding vb = getValueBinding("searchType"); //$NON-NLS-1$
if (vb != null) {
return (String) vb.getValue(getFacesContext());
}
return null;
}
/**
* Loads the search type
*
* @param searchType
* String search type
* @since org.openntf.domino.xsp 5.0.0
*/
public void setSearchType(final String searchType) {
this.searchType = searchType;
}
/**
* Gets the search style, from the "searchStyle" property
*
* @return String search style
* @since org.openntf.domino.xsp 5.0.0
*/
public String getSearchStyle() {
if (searchStyle != null) {
return searchStyle;
}
ValueBinding vb = getValueBinding("searchStyle"); //$NON-NLS-1$
if (vb != null) {
return (String) vb.getValue(getFacesContext());
} else {
return SearchStyle.SEARCH_JUMPTO.getValue();
}
}
/**
* Loads the search style
*
* @param searchStyle
* String search style
* @since org.openntf.domino.xsp 5.0.0
*/
public void setSearchStyle(final String searchStyle) {
this.searchStyle = searchStyle;
}
/**
* Whether the options should be searched case insensitive or not
*
* @return boolean whether case insensitive
* @since org.openntf.domino.xsp 5.0.0
*/
public boolean isCaseInsensitive() {
if (caseInsensitive != null) {
return caseInsensitive;
}
ValueBinding vb = getValueBinding("caseInsensitive");// $NON-NLS-1$
if (vb != null) {
Boolean b = (Boolean) vb.getValue(getFacesContext());
if (b != null) {
return b;
}
}
return false;
}
/**
* Loads whether the search should be done case inszensitive
*
* @param caseInsensitive
* boolean
* @since org.openntf.domino.xsp 5.0.0
*/
public void setCaseInsensitive(final boolean caseInsensitive) {
this.caseInsensitive = caseInsensitive;
}
/*
* (non-Javadoc)
*
* @see com.ibm.xsp.extlib.component.picker.data.IPickerData#getSourceLabels()
*/
@Override
public String[] getSourceLabels() {
return null;
}
/*
* (non-Javadoc)
*
* @see com.ibm.xsp.extlib.component.picker.data.IPickerData#hasCapability(int)
*/
@Override
public boolean hasCapability(final int capability) {
if (capability == IValuePickerData.CAPABILITY_LABEL || capability == IValuePickerData.CAPABILITY_SEARCHBYKEY
|| capability == IValuePickerData.CAPABILITY_SEARCHLIST)
return true;
return false;
}
/*
* This method appears to be the one that gets the entries for the picker
*
* (non-Javadoc)
*
* @see com.ibm.xsp.extlib.component.picker.data.IPickerData#readEntries(com.ibm.xsp.extlib.component.picker.data.IPickerOptions)
*/
@Override
public IPickerResult readEntries(final IPickerOptions options) {
String startKey = options.getStartKey();
String key = options.getKey();
int start = options.getStart();
int count = options.getCount();
int searchIndex = 0;
LinkedHashMap<String, String> opts = filteredOptions(key, startKey, start, searchIndex);
List<IPickerEntry> entries = new ArrayList<IPickerEntry>();
Iterator<String> it = opts.keySet().iterator();
while (it.hasNext()) {
String mapKey = it.next();
entries.add(new SimplePickerResult.Entry(opts.get(mapKey), mapKey));
}
return new SimplePickerResult(entries, count);
}
/**
* Returns the filtered options, a subset of the options for the MapValuePickerData
*
* @param key
* String typeahead key
* @param startKey
* String search option
* @param start
* int not used
* @param searchIndex
* int not used
* @return LinkedHashMap<String, String> of options filtered from the total options
* @since org.openntf.domino.xsp 4.5.0
*/
private LinkedHashMap<String, String> filteredOptions(final String key, final String startKey, final int start, final int searchIndex) {
LinkedHashMap<String, String> retVal = new LinkedHashMap<String, String>();
String searchType = getSearchType();
if (StringUtil.isNotEmpty(key)) {
// We've got a typeahead key passed in, filter to entries beginning with that key
String tmpKey = key;
if (isCaseInsensitive()) {
tmpKey = tmpKey.toLowerCase();
}
Iterator<String> it = getOptions().keySet().iterator();
while (it.hasNext()) {
String mapKey = it.next();
String tmpMapKey = mapKey;
if (isCaseInsensitive()) {
tmpMapKey = tmpMapKey.toLowerCase();
}
if (tmpMapKey.startsWith(tmpKey)) {
retVal.put(mapKey, getOptions().get(mapKey));
}
}
} else if (StringUtil.isNotEmpty(startKey)) {
// startKey is actually a search key
// We've got a search key passed in, so search and add all remaining entries
String tmpSearchKey = startKey;
if (isCaseInsensitive()) {
tmpSearchKey = tmpSearchKey.toLowerCase();
}
Iterator<String> it = getOptions().keySet().iterator();
boolean found = false;
while (it.hasNext()) {
String mapKey = it.next();
String tmpMapKey = mapKey;
if (isCaseInsensitive()) {
tmpMapKey = tmpMapKey.toLowerCase();
}
if (found) {
retVal.put(mapKey, getOptions().get(mapKey));
found = true;
} else {
if (SearchType.SEARCH_MATCH.getValue().equals(searchType)) {
if (StringUtil.equals(tmpMapKey, tmpSearchKey)) {
retVal.put(mapKey, getOptions().get(mapKey));
if (SearchStyle.SEARCH_JUMPTO.getValue().equals(getSearchStyle())) {
found = true;
}
}
} else if (SearchType.SEARCH_FTSEARCH.getValue().equals(searchType)) {
if (tmpMapKey.contains(tmpSearchKey)) {
retVal.put(mapKey, getOptions().get(mapKey));
if (SearchStyle.SEARCH_JUMPTO.getValue().equals(getSearchStyle())) {
found = true;
}
}
} else {
if (tmpMapKey.startsWith(tmpSearchKey)) {
retVal.put(mapKey, getOptions().get(mapKey));
if (SearchStyle.SEARCH_JUMPTO.getValue().equals(getSearchStyle())) {
found = true;
}
}
}
}
}
} else {
retVal.putAll(getOptions());
}
return retVal;
}
/*
* This method appears to be the one that is used for validation, to get an entry based on a value or values in the relevant component.
* The ArrayList only has values, so check values passed in and return those that exist in the options
*
* (non-Javadoc)
*
* @see com.ibm.xsp.extlib.component.picker.data.IPickerData#loadEntries(java.lang.Object[], java.lang.String[])
*/
@Override
public List<IPickerEntry> loadEntries(final Object[] values, final String[] attributes) {
List<IPickerEntry> entries = new ArrayList<IPickerEntry>();
if (null != values) {
for (int i = 0; i < values.length; i++) {
String checkStr = values[i].toString();
if (StringUtil.isNotEmpty(checkStr)) {
Iterator<String> it = getOptions().keySet().iterator();
while (it.hasNext()) {
String mapKey = it.next();
if (StringUtil.equals(checkStr, getOptions().get(mapKey))) {
entries.add(new SimplePickerResult.Entry(getOptions().get(mapKey), mapKey));
break;
}
}
}
}
}
return entries;
}
/*
* (non-Javadoc)
*
* @see com.ibm.xsp.complex.ValueBindingObjectImpl#restoreState(javax.faces.context.FacesContext, java.lang.Object)
*/
@SuppressWarnings("unchecked")
@Override
public void restoreState(final FacesContext _context, final Object _state) {
Object _values[] = (Object[]) _state;
super.restoreState(_context, _values[0]);
options = (Map<String, String>) _values[1];
searchType = (String) _values[2];
caseInsensitive = (Boolean) _values[3];
searchStyle = (String) _values[4];
}
/*
* (non-Javadoc)
*
* @see com.ibm.xsp.complex.ValueBindingObjectImpl#saveState(javax.faces.context.FacesContext)
*/
@Override
public Object saveState(final FacesContext _context) {
Object _values[] = new Object[5];
_values[0] = super.saveState(_context);
_values[1] = options;
_values[2] = searchType;
_values[3] = caseInsensitive;
_values[4] = searchStyle;
return _values;
}
}