/*
* � Copyright IBM Corp. 2010
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.ibm.xsp.extlib.component.picker.data;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;
import com.ibm.commons.Platform;
import com.ibm.commons.util.ArrayIterator;
import com.ibm.commons.util.QuickSort;
import com.ibm.commons.util.StringUtil;
import com.ibm.jscript.InterpretException;
import com.ibm.jscript.types.FBSValue;
import com.ibm.xsp.complex.ValueBindingObjectImpl;
import com.ibm.xsp.context.FacesContextEx;
import com.ibm.xsp.util.DataPublisher;
import com.ibm.xsp.util.DataPublisher.ShadowedObject;
/**
* Simple data provider for a value picker.
* <p>
* This data provider is relying on properties that can be computed using
* a value binding.
* </p>
*/
public class SimpleValuePickerData extends ValueBindingObjectImpl implements IValuePickerData {
private Object valueList;
private String valueListSeparator;
private String labelSeparator;
private Boolean caseInsensitive;
public SimpleValuePickerData() {
}
public String[] getSourceLabels() {
return null;
}
public Object getValueList() {
if (valueList != null) {
return valueList;
}
ValueBinding vb = getValueBinding("valueList"); //$NON-NLS-1$
if (vb != null) {
return vb.getValue(getFacesContext());
}
return null;
}
public void setValueList(Object valueList) {
this.valueList = valueList;
}
public String getValueListSeparator() {
if (valueListSeparator != null) {
return valueListSeparator;
}
ValueBinding vb = getValueBinding("valueListSeparator"); //$NON-NLS-1$
if (vb != null) {
return (String)vb.getValue(getFacesContext());
}
return null;
}
public void setValueListSeparator(String valueListSeparator) {
this.valueListSeparator = valueListSeparator;
}
public String getLabelSeparator() {
if (labelSeparator != null) {
return labelSeparator;
}
ValueBinding vb = getValueBinding("labelSeparator"); //$NON-NLS-1$
if (vb != null) {
return (String)vb.getValue(getFacesContext());
}
return null;
}
public void setLabelSeparator(String labelSeparator) {
this.labelSeparator = labelSeparator;
}
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;
}
public void setCaseInsensitive(boolean caseInsensitive) {
this.caseInsensitive = caseInsensitive;
}
@Override
public void restoreState(FacesContext _context, Object _state) {
Object _values[] = (Object[]) _state;
super.restoreState(_context, _values[0]);
valueList = _values[1];
valueListSeparator = (String)_values[2];
labelSeparator = (String)_values[3];
caseInsensitive = (Boolean)_values[4];
}
@Override
public Object saveState(FacesContext _context) {
Object _values[] = new Object[5];
_values[0] = super.saveState(_context);
_values[1] = valueList;
_values[2] = valueListSeparator;
_values[3] = labelSeparator;
_values[4] = caseInsensitive;
return _values;
}
// ====================================================================
// Data access implementation
// ====================================================================
public boolean hasCapability(int capability) {
switch(capability) {
case CAPABILITY_MULTIPLESOURCES: return false;
case CAPABILITY_EXTRAATTRIBUTES: return false;
}
return true;
}
public IPickerResult readEntries(IPickerOptions options) {
FacesContext context = FacesContext.getCurrentInstance();
int start = options.getStart();
int count = options.getCount();
String key = options.getKey();
String startKey = options.getStartKey();
List<ShadowedObject> _shadowedData = pushVar(context, start, count, key, startKey);
try {
Object values = getValueList();
if(values!=null) {
String labelSep = getLabelSeparator();
if(StringUtil.isEmpty(labelSep)) {
labelSep = null;
}
List<IPickerEntry> entries = new ArrayList<IPickerEntry>(64);
for(Iterator<Object> it=getIterator(values); it.hasNext(); ) {
Object o = it.next();
if(o!=null) {
IPickerEntry e = getEntry(o,labelSep);
if(e!=null) {
entries.add(e);
}
}
}
int nEntries = -1;
return new SimplePickerResult(entries,nEntries);
}
return null;
} finally {
popVar(context,_shadowedData);
}
}
private List<ShadowedObject> pushVar(FacesContext context, int start, int count, Object key, Object startKey) {
List<ShadowedObject> _shadowedData = new ArrayList<ShadowedObject>(1);
DataPublisher dataPublisher = ((FacesContextEx)context).getDataPublisher();
dataPublisher.pushObject(_shadowedData, "start", start); // $NON-NLS-1$
dataPublisher.pushObject(_shadowedData, "count", count); // $NON-NLS-1$
dataPublisher.pushObject(_shadowedData, "key", key); // $NON-NLS-1$
dataPublisher.pushObject(_shadowedData, "startKey", startKey); // $NON-NLS-1$
return _shadowedData;
}
private void popVar(FacesContext context, List<ShadowedObject> _shadowedData) {
((FacesContextEx)context).getDataPublisher().popObjects(_shadowedData);
}
public List<IPickerEntry> loadEntries(Object[] ids, String[] attributeNames) {
FacesContext context = FacesContext.getCurrentInstance();
List<IPickerEntry> entries = new ArrayList<IPickerEntry>(ids.length);
for(int i=0; i<ids.length; i++) {
entries.add(null);
}
String labelSep = getLabelSeparator();
if(StringUtil.isEmpty(labelSep)) {
labelSep = null;
}
final boolean searchLabel = labelSep!=null;
int start = 0;
int count = Integer.MAX_VALUE;
String startKey = null;
for(int i=0; i<ids.length; i++) {
Object key = ids[i];
List<ShadowedObject> _shadowedData = pushVar(context, start, count, key, startKey);
try {
Object values = getValueList();
if(values!=null) {
boolean caseInsensitive = isCaseInsensitive();
for(Iterator<Object> it=getIterator(values); it.hasNext(); ) {
Object o = it.next();
if(o!=null) {
IPickerEntry e = getEntry(o,labelSep);
if(e!=null) {
//String value = toString(searchLabel?e.getLabel():e.getValue());
String value = toString(e.getValue());
if(caseInsensitive) {
if(StringUtil.equalsIgnoreCase(value,ids[i].toString())) {
entries.set(i,e);
break;
}
} else {
if(StringUtil.equals(value,ids[i])) {
entries.set(i,e);
break;
}
}
}
}
}
}
} finally {
popVar(context,_shadowedData);
}
}
// Sort the entries
(new QuickSort.JavaList(entries) {
@Override
public int compare(Object o1, Object o2) {
if(o1==null) {
if(o2==null) return 0;
return -1;
}
if(o2==null) {
return 1;
}
String s1 = SimpleValuePickerData.toString(searchLabel ? ((IPickerEntry)o1).getLabel() : ((IPickerEntry)o1).getValue());
String s2 = SimpleValuePickerData.toString(searchLabel ? ((IPickerEntry)o2).getLabel() : ((IPickerEntry)o2).getValue());
return StringUtil.compareToIgnoreCase(s1, s2);
}
}).sort();
return entries;
}
private static String toString(Object o) {
return o!=null ? o.toString() : null;
}
protected IPickerEntry getEntry(Object o, String sep) {
if(o instanceof FBSValue) {
try {
FBSValue v = (FBSValue)o;
if(v.isArray()) {
int l = v.getArrayLength();
if(l==1) {
return new SimplePickerResult.Entry(v.getArrayValue(0).toJavaObject(),null);
} else if(l>1) {
return new SimplePickerResult.Entry(v.getArrayValue(1).toJavaObject(),v.getArrayValue(0).toJavaObject());
} else {
return null;
}
}
o = v.stringValue();
} catch(InterpretException ex) {
Platform.getInstance().log(ex);
return null;
}
}
if(o instanceof String) {
String s = (String)o;
int pos = sep!=null ? s.indexOf(sep) : -1;
if(pos>=0) {
return new SimplePickerResult.Entry(s.substring(pos+1),s.substring(0,pos));
} else {
return new SimplePickerResult.Entry(s,null);
}
}
if(o instanceof List) {
List<?> ls = (List<?>)o;
int l = ls.size();
if(l==1) {
return new SimplePickerResult.Entry(ls.get(0),null);
} else if(l>1) {
return new SimplePickerResult.Entry(ls.get(1),ls.get(0));
} else {
return null;
}
}
if(o.getClass().isArray()) {
int l = Array.getLength(o);
if(l==1) {
return new SimplePickerResult.Entry(Array.get(o,0),null);
} else if(l>1) {
return new SimplePickerResult.Entry(Array.get(o,1),Array.get(o,0));
} else {
return null;
}
}
return null;
}
protected Iterator<Object> getIterator(Object values) {
if(values instanceof String) {
String valuesStr = (String)values;
String separator = getValueListSeparator();
if( null == separator ){
// separator defaults to newline
if( -1 != valuesStr.indexOf("\r\n") ){ // $NON-NLS-1$
separator = "\r\n"; // $NON-NLS-1$
}else{
separator = "\n"; // $NON-NLS-1$
}
}
String[] l = StringUtil.splitString(valuesStr, separator, false);
return new ArrayIterator<Object>(l);
}
if(values.getClass().isArray()) {
return new ArrayIterator<Object>(values);
}
if(values instanceof List) {
return ((List<Object>)values).iterator();
}
if(values instanceof FBSValue) {
return new JSIterator((FBSValue)values);
}
return null;
}
// Utility to iterate through JS values
private static class JSIterator implements Iterator<Object> {
private FBSValue value;
private int length;
private int current;
private JSIterator(FBSValue value) {
this.value = value;
this.length = value.getArrayLength();
this.current = 0;
}
public boolean hasNext() {
return current<length;
}
public Object next() {
if( current<length ) {
try {
return value.getArrayValue(current++);
} catch(InterpretException ex) {
Platform.getInstance().log(ex);
}
}
return null;
}
public void remove() {
}
}
}