package gueei.binding.collections;
import gueei.binding.AttributeBinder;
import gueei.binding.Binder;
import gueei.binding.BindingLog;
import gueei.binding.CollectionChangedEventArg;
import gueei.binding.CollectionObserver;
import gueei.binding.IObservable;
import gueei.binding.IObservableCollection;
import gueei.binding.ISyntaxResolver.SyntaxResolveException;
import gueei.binding.utility.CachedModelReflector;
import gueei.binding.utility.EventMarkerHelper;
import gueei.binding.utility.IModelReflector;
import gueei.binding.viewAttributes.adapterView.listView.ItemViewEventMark;
import gueei.binding.viewAttributes.templates.Layout;
import java.util.Collection;
import android.content.Context;
import android.os.Handler;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
public class CollectionAdapter extends BaseAdapter implements CollectionObserver, Filterable, LazyLoadAdapter {
@Override
public int getViewTypeCount() {
return mLayout.getTemplateCount();
}
@Override
public int getItemViewType(int position) {
return mLayout.getLayoutTypeId(position);
}
protected final Handler mHandler;
protected final Context mContext;
protected final Layout mLayout, mDropDownLayout;
protected final IObservableCollection<?> mCollection;
protected final IModelReflector mReflector;
protected final Filter mFilter;
public CollectionAdapter(Context context, IModelReflector reflector, IObservableCollection<?> collection, Layout layout, Layout dropDownLayout,
Filter filter, String enableItemStatement) throws Exception {
mHandler = new Handler();
mContext = context;
mLayout = layout;
mDropDownLayout = dropDownLayout;
mCollection = collection;
mReflector = reflector;
mFilter = filter;
mEnableItemStatement = enableItemStatement;
mCollection.subscribe(this);
}
public CollectionAdapter(Context context, IModelReflector reflector, IObservableCollection<?> collection, Layout layout, Layout dropDownLayout,
String enableItemStatement) throws Exception {
this(context, reflector, collection, layout, dropDownLayout, null, enableItemStatement);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public CollectionAdapter(Context context, IObservableCollection<?> collection, Layout layout, Layout dropDownLayout, Filter filter,
String enableItemStatement) throws Exception {
this(context, new CachedModelReflector(collection.getComponentType()), collection, layout, dropDownLayout, filter, enableItemStatement);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public CollectionAdapter(Context context, IObservableCollection<?> collection, Layout layout, Layout dropDownLayout, String enableItemStatement)
throws Exception {
this(context, new CachedModelReflector(collection.getComponentType()), collection, layout, dropDownLayout, enableItemStatement);
}
public void subscribeCollectionObserver(CollectionObserver observer) {
mCollection.subscribe(observer);
}
public void unsubscribeCollectionObserver(CollectionObserver observer) {
mCollection.unsubscribe(observer);
}
public int getCount() {
return mCollection.size();
}
public Object getItem(int position) {
return mCollection.getItem(position);
}
public long getItemId(int position) {
return mCollection.getItemId(position);
}
private View getView(int position, View convertView, ViewGroup parent, Layout layout) {
View returnView = convertView;
if (position >= mCollection.size())
return returnView;
try {
ObservableMapper mapper;
mCollection.onLoad(position);
Object item = mCollection.getItem(position);
if ((convertView == null) || ((mapper = getAttachedMapper(convertView)) == null)) {
Binder.InflateResult result =
Binder.inflateView(mContext, layout.getLayoutId(position), parent, false);
layout.onAfterInflate(result, position);
ItemViewEventMark mark = new ItemViewEventMark(parent, position, mCollection.getItemId(position));
EventMarkerHelper.mark(result.rootView, mark);
mapper = new ObservableMapper();
Object model = mCollection.getItem(position);
mapper.startCreateMapping(mReflector, model);
for (View view : result.processedViews) {
AttributeBinder.getInstance().bindView(mContext, view, mapper);
}
mapper.endCreateMapping();
returnView = result.rootView;
this.putAttachedMapper(returnView, mapper);
} else {
ItemViewEventMark mark = EventMarkerHelper.getMark(returnView);
if (null != mark) {
mark.setIdAndPosition(position, mCollection.getItemId(position));
}
}
mapper.changeMapping(mReflector, item);
if (mHelper != null && !mHelper.isBusy()) {
if (item instanceof ILazyLoadRowModel){
//((LazyLoadRowModel) item).display(mCollection, position);
}
}
return returnView;
} catch (Exception e) {
e.printStackTrace();
return returnView;
}
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
return getView(position, convertView, parent, mDropDownLayout);
}
public View getView(int position, View convertView, ViewGroup parent) {
return getView(position, convertView, parent, mLayout);
}
private ObservableMapper getAttachedMapper(View convertView) {
return Binder.getViewTag(convertView).get(ObservableMapper.class);
}
private void putAttachedMapper(View convertView, ObservableMapper mapper) {
Binder.getViewTag(convertView).put(ObservableMapper.class, mapper);
}
public Filter getFilter() {
return mFilter;
}
protected Mode mMode = Mode.LoadWhenStopped;
protected LazyLoadRootAdapterHelper mHelper;
public void setRoot(AbsListView view) {
if (ILazyLoadRowModel.class.isAssignableFrom(mCollection.getComponentType()))
mHelper = new LazyLoadRootAdapterHelper(view, this, mMode);
}
public void setMode(Mode mode) {
if (mHelper != null) {
mHelper.setMode(mode);
}
mMode = mode;
}
private int lastDisplayingFirst = -1;
private int lastTotal = 0;
public void onVisibleChildrenChanged(int first, int total) {
if (total>lastTotal){
mCollection.setVisibleChildrenCount(this, total);
}
int actualCollectionSize = mCollection.size();
if (0 == actualCollectionSize) {
// nothing to show, nothing to hide, reset last*
lastDisplayingFirst = -1;
lastTotal = 0;
return;
}
// normalize NEW first and last indexes
// normalize newTotal, should be greater or equal to 0
int newTotal = total < 0 ? 0 : total;
// normalize newFirstIndex, should be less than actualCollectionSize
int newFirstIndex = (first >= actualCollectionSize) ? actualCollectionSize - 1 : first;
// normalize newFirstIndex, should be greater or equal to 0
newFirstIndex = newFirstIndex < 0 ? 0 : newFirstIndex;
// calculate last new visible index
int newLastIndex = newFirstIndex + newTotal;
// normalize newLastIndex, should be equal or greater than less than newFirstIndex
newLastIndex = (newLastIndex < newFirstIndex) ? newFirstIndex + 1 : newLastIndex;
// normalize newLastIndex, should be less than actualCollectionSize
newLastIndex = (newLastIndex > actualCollectionSize) ? actualCollectionSize : newLastIndex;
// normalize OLD first and last indexes (collection size can be changed between function calls)
// normalize oldTotal, should be greater or equal to 0
int oldTotal = lastTotal < 0 ? 0 : lastTotal;
// normalize oldFirstIndex, should be less or equal to actualCollectionSize
int oldFirstIndex = (lastDisplayingFirst > actualCollectionSize - 1) ? actualCollectionSize - 1 : lastDisplayingFirst;
// normalize oldFirstIndex, should be greater or equal to 0
oldFirstIndex = oldFirstIndex < 0 ? 0 : oldFirstIndex;
// calculate last old visible index
int oldLastIndex = oldFirstIndex + oldTotal;
// normalize oldLastIndex, should be equal or greater than less than oldFirstIndex
oldLastIndex = (oldLastIndex < oldFirstIndex) ? oldFirstIndex + 1 : oldLastIndex;
// normalize oldLastIndex, should be less or equal to actualCollectionSize
oldLastIndex = (oldLastIndex > actualCollectionSize) ? actualCollectionSize : oldLastIndex;
Object rawItem;
for (int i = newFirstIndex; i < oldFirstIndex; ++i) {
rawItem = mCollection.getItem(i);
if (rawItem instanceof ILazyLoadRowModel) {
((ILazyLoadRowModel) rawItem).display(mCollection, i);
}
}
for (int i = oldFirstIndex; i < newFirstIndex; ++i) {
rawItem = mCollection.getItem(i);
if (rawItem instanceof ILazyLoadRowModel) {
if (!((ILazyLoadRowModel) rawItem).isMapped())
((ILazyLoadRowModel) rawItem).hide(mCollection, i);
}
}
for (int i = newLastIndex; i < oldLastIndex; ++i) {
rawItem = mCollection.getItem(i);
if (rawItem instanceof ILazyLoadRowModel) {
if (!((ILazyLoadRowModel) rawItem).isMapped())
((ILazyLoadRowModel) rawItem).hide(mCollection, i);
}
}
for (int i = oldLastIndex; i < newLastIndex; ++i) {
rawItem = mCollection.getItem(i);
if (rawItem instanceof ILazyLoadRowModel) {
((ILazyLoadRowModel) rawItem).display(mCollection, i);
}
}
// set lastDisplayingFirst and lastTotal;
lastDisplayingFirst = newFirstIndex;
lastTotal = newTotal;
}
/**
* Statement that determines child item is enable/disable
*/
private String mEnableItemStatement = null;
/**
* If the statement is null (unset), all items are assumed to be enabled.
*/
@Override
public boolean areAllItemsEnabled() {
return mEnableItemStatement == null;
}
/**
* Make individual item enable/disable possible.
* This is not possible to do in Item level, but only from ListView's level since
* items are rendered by listView and listview seems to omit this value
*/
@Override
public boolean isEnabled(int position) {
if (mEnableItemStatement == null)
return true;
IObservable<?> obs;
try {
obs = Binder.getSyntaxResolver().constructObservableFromStatement(mContext, mEnableItemStatement, mCollection.getItem(position));
} catch (SyntaxResolveException e) {
BindingLog.exception("CollectionAdapter.isEnabled", e);
return false;
}
// Even if the obs is null, or it's value is null, it is enabled by default
return obs == null || !Boolean.FALSE.equals(obs.get());
}
@Override
public void onCollectionChanged(IObservableCollection<?> collection,
CollectionChangedEventArg args, Collection<Object> initiators) {
notifyDataSetChanged();
}
}