/**
* galaxy inc.
* meetup client for android
*/
package com.galaxy.meetup.client.android.common;
import android.content.Context;
import android.database.Cursor;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
/**
*
* @author sihai
*
*/
public abstract class EsCompositeCursorAdapter extends BaseAdapter {
private static final int INITIAL_CAPACITY = 2;
protected final Context mContext;
private Partition[] mPartitions;
private int mSize = 0;
private int mCount = 0;
private boolean mCacheValid = true;
private boolean mNotificationsEnabled = true;
private boolean mNotificationNeeded;
public EsCompositeCursorAdapter(Context context) {
this(context, INITIAL_CAPACITY);
}
public EsCompositeCursorAdapter(Context context, int initialCapacity) {
mContext = context;
mPartitions = new Partition[INITIAL_CAPACITY];
}
public Context getContext() {
return mContext;
}
public void addPartition(boolean showIfEmpty, boolean hasHeader) {
addPartition(new Partition(showIfEmpty, hasHeader));
}
public void addPartition(Partition partition) {
if (mSize >= mPartitions.length) {
int newCapacity = mSize + 2;
Partition[] newAdapters = new Partition[newCapacity];
System.arraycopy(mPartitions, 0, newAdapters, 0, mSize);
mPartitions = newAdapters;
}
mPartitions[mSize++] = partition;
invalidate();
notifyDataSetChanged();
}
public void removePartition(int partitionIndex) {
Cursor cursor = mPartitions[partitionIndex].cursor;
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
System.arraycopy(mPartitions, partitionIndex + 1, mPartitions, partitionIndex,
mSize - partitionIndex - 1);
mSize--;
invalidate();
notifyDataSetChanged();
}
public void clearPartitions() {
for (int i = 0; i < mSize; i++) {
mPartitions[i].cursor = null;
}
invalidate();
notifyDataSetChanged();
}
public void close() {
for (int i = 0; i < mSize; i++) {
Cursor cursor = mPartitions[i].cursor;
if (cursor != null && !cursor.isClosed()) {
cursor.close();
mPartitions[i].cursor = null;
}
}
mSize = 0;
invalidate();
notifyDataSetChanged();
}
public void setHasHeader(int partitionIndex, boolean flag) {
mPartitions[partitionIndex].hasHeader = flag;
invalidate();
}
public void setShowIfEmpty(int partitionIndex, boolean flag) {
mPartitions[partitionIndex].showIfEmpty = flag;
invalidate();
}
public Partition getPartition(int partitionIndex) {
if (partitionIndex >= mSize) {
throw new ArrayIndexOutOfBoundsException(partitionIndex);
}
return mPartitions[partitionIndex];
}
protected void invalidate() {
mCacheValid = false;
}
public int getPartitionCount() {
return mSize;
}
protected void ensureCacheValid() {
if (mCacheValid) {
return;
}
mCount = 0;
for (int i = 0; i < mSize; i++) {
Cursor cursor = mPartitions[i].cursor;
int count = cursor != null ? cursor.getCount() : 0;
if (mPartitions[i].hasHeader) {
if (count != 0 || mPartitions[i].showIfEmpty) {
count++;
}
}
mPartitions[i].count = count;
mCount += count;
}
mCacheValid = true;
}
public boolean hasHeader(int partition) {
return mPartitions[partition].hasHeader;
}
public int getCount() {
ensureCacheValid();
return mCount;
}
public final int getCount(int i) {
ensureCacheValid();
int j;
if(mPartitions[i].cursor == null)
j = 0;
else
j = mPartitions[i].cursor.getCount();
return j;
}
public Cursor getCursor(int partition) {
return mPartitions[partition].cursor;
}
public void changeCursor(int partition, Cursor cursor) {
Cursor prevCursor = mPartitions[partition].cursor;
if (prevCursor != cursor) {
if (prevCursor != null && !prevCursor.isClosed()) {
prevCursor.close();
}
mPartitions[partition].cursor = cursor;
if (cursor != null) {
mPartitions[partition].idColumnIndex = cursor.getColumnIndex("_id");
}
invalidate();
notifyDataSetChanged();
}
}
public boolean isPartitionEmpty(int partition) {
Cursor cursor = mPartitions[partition].cursor;
return cursor == null || cursor.getCount() == 0;
}
public int getPartitionForPosition(int position) {
ensureCacheValid();
int start = 0;
for (int i = 0; i < mSize; i++) {
int end = start + mPartitions[i].count;
if (position >= start && position < end) {
return i;
}
start = end;
}
return -1;
}
public int getOffsetInPartition(int position) {
ensureCacheValid();
int start = 0;
for (int i = 0; i < mSize; i++) {
int end = start + mPartitions[i].count;
if (position >= start && position < end) {
int offset = position - start;
if (mPartitions[i].hasHeader) {
offset--;
}
return offset;
}
start = end;
}
return -1;
}
public int getPositionForPartition(int partition) {
ensureCacheValid();
int position = 0;
for (int i = 0; i < partition; i++) {
position += mPartitions[i].count;
}
return position;
}
@Override
public int getViewTypeCount() {
return getItemViewTypeCount() + 1;
}
public int getItemViewTypeCount() {
return 1;
}
protected int getItemViewType(int partition, int position) {
return 1;
}
@Override
public int getItemViewType(int position) {
ensureCacheValid();
int start = 0;
for (int i = 0; i < mSize; i++) {
int end = start + mPartitions[i].count;
if (position >= start && position < end) {
int offset = position - start;
if (mPartitions[i].hasHeader && offset == 0) {
return IGNORE_ITEM_VIEW_TYPE;
}
return getItemViewType(i, position);
}
start = end;
}
throw new ArrayIndexOutOfBoundsException(position);
}
public View getView(int position, View convertView, ViewGroup parent) {
ensureCacheValid();
int start = 0;
for (int i = 0; i < mSize; i++) {
int end = start + mPartitions[i].count;
if (position >= start && position < end) {
int offset = position - start;
if (mPartitions[i].hasHeader) {
offset--;
}
View view;
if (offset == -1) {
view = getHeaderView(i, mPartitions[i].cursor, convertView, parent);
} else {
if (!mPartitions[i].cursor.moveToPosition(offset)) {
throw new IllegalStateException("Couldn't move cursor to position "
+ offset);
}
view = getView(i, mPartitions[i].cursor, offset, convertView, parent);
}
if (view == null) {
throw new NullPointerException("View should not be null, partition: " + i
+ " position: " + offset);
}
return view;
}
start = end;
}
throw new ArrayIndexOutOfBoundsException(position);
}
protected View getHeaderView(int partition, Cursor cursor, View convertView,
ViewGroup parent) {
View view = convertView != null
? convertView
: newHeaderView(mContext, partition, cursor, parent);
bindHeaderView(view, partition, cursor);
return view;
}
protected View newHeaderView(Context context, int partition, Cursor cursor, ViewGroup parent) {
return null;
}
protected void bindHeaderView(View view, int partition, Cursor cursor) {
}
protected View getView(int partition, Cursor cursor, int position, View convertView,
ViewGroup parent) {
View view;
if (convertView != null) {
view = convertView;
} else {
view = newView(mContext, partition, cursor, position, parent);
}
bindView(view, partition, cursor, position);
return view;
}
protected abstract View newView(Context context, int partition, Cursor cursor, int position, ViewGroup parent);
protected abstract void bindView(View v, int partition, Cursor cursor, int position);
public Object getItem(int position) {
ensureCacheValid();
int start = 0;
for (int i = 0; i < mSize; i++) {
int end = start + mPartitions[i].count;
if (position >= start && position < end) {
int offset = position - start;
if (mPartitions[i].hasHeader) {
offset--;
}
if (offset == -1) {
return null;
}
Cursor cursor = mPartitions[i].cursor;
cursor.moveToPosition(offset);
return cursor;
}
start = end;
}
return null;
}
public long getItemId(int position) {
ensureCacheValid();
int start = 0;
for (int i = 0; i < mSize; i++) {
int end = start + mPartitions[i].count;
if (position >= start && position < end) {
int offset = position - start;
if (mPartitions[i].hasHeader) {
offset--;
}
if (offset == -1) {
return 0;
}
if (mPartitions[i].idColumnIndex == -1) {
return 0;
}
Cursor cursor = mPartitions[i].cursor;
if (cursor == null || cursor.isClosed() || !cursor.moveToPosition(offset)) {
return 0;
}
return cursor.getLong(mPartitions[i].idColumnIndex);
}
start = end;
}
return 0;
}
@Override
public boolean areAllItemsEnabled() {
for (int i = 0; i < mSize; i++) {
if (mPartitions[i].hasHeader) {
return false;
}
}
return true;
}
@Override
public boolean isEnabled(int position) {
ensureCacheValid();
int start = 0;
for (int i = 0; i < mSize; i++) {
int end = start + mPartitions[i].count;
if (position >= start && position < end) {
int offset = position - start;
if (mPartitions[i].hasHeader && offset == 0) {
return false;
} else {
return isEnabled(i, offset);
}
}
start = end;
}
return false;
}
protected boolean isEnabled(int partition, int position) {
return true;
}
public void setNotificationsEnabled(boolean flag) {
mNotificationsEnabled = flag;
if (flag && mNotificationNeeded) {
notifyDataSetChanged();
}
}
@Override
public void notifyDataSetChanged() {
if (mNotificationsEnabled) {
mNotificationNeeded = false;
super.notifyDataSetChanged();
} else {
mNotificationNeeded = true;
}
}
public final void checkPartitions(String s, String s1) {
int i = -1 + mSize;
while(i >= 0) {
Partition partition = mPartitions[i];
Cursor cursor;
if(partition != null)
cursor = partition.cursor;
else
cursor = null;
if(cursor == null)
Log.i(s, (new StringBuilder("partcheck s:")).append(s1).append(" emptypart:").append(i).toString());
else
if(cursor.isClosed())
Log.i(s, (new StringBuilder("partcheck s:")).append(s1).append(" stalepart:").append(i).toString());
i--;
}
}
//=============================================================================================================================
//
//=============================================================================================================================
public static class Partition {
boolean showIfEmpty;
boolean hasHeader;
Cursor cursor;
int idColumnIndex;
int count;
public Partition(boolean showIfEmpty, boolean hasHeader) {
this.showIfEmpty = showIfEmpty;
this.hasHeader = hasHeader;
}
public boolean getShowIfEmpty() {
return showIfEmpty;
}
public boolean getHasHeader() {
return hasHeader;
}
}
}