package org.ebookdroid.ui.viewer.adapters;
import org.sufficientlysecure.viewer.R;
import org.ebookdroid.common.settings.books.BookSettings;
import org.ebookdroid.core.Page;
import org.ebookdroid.core.codec.OutlineLink;
import org.ebookdroid.core.models.DocumentModel;
import org.ebookdroid.ui.viewer.IActivityController;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.util.SparseIntArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;
import android.widget.TextView;
import java.util.List;
public class OutlineAdapter extends BaseAdapter {
private int spaceWidth;
private final Drawable background;
private final Drawable selected;
private final VoidListener voidListener = new VoidListener();
private final ItemListener itemListener = new ItemListener();
private final CollapseListener collapseListener = new CollapseListener();
private final Context context;
private final OutlineLink[] objects;
private final int[] pageIndexes;
private final OutlineItemState[] states;
private final SparseIntArray mapping = new SparseIntArray();
private final int currentId;
private final int offset;
public OutlineAdapter(final Context context, final IActivityController base, final List<OutlineLink> objects,
final OutlineLink current) {
this.context = context;
final BookSettings bs = base.getBookSettings();
final DocumentModel model = base.getDocumentModel();
final Resources resources = context.getResources();
background = resources.getDrawable(R.drawable.viewer_outline_item_background);
selected = resources.getDrawable(R.drawable.viewer_outline_item_background_selected);
this.offset = bs != null ? bs.firstPageOffset : 1;
this.objects = objects.toArray(new OutlineLink[objects.size()]);
this.pageIndexes = new int[this.objects.length];
this.states = new OutlineItemState[this.objects.length];
boolean treeFound = false;
for (int i = 0; i < this.objects.length; i++) {
mapping.put(i, i);
final int next = i + 1;
if (next < this.objects.length && this.objects[i].level < this.objects[next].level) {
states[i] = OutlineItemState.COLLAPSED;
treeFound = true;
} else {
states[i] = OutlineItemState.LEAF;
}
final Page page = model.getLinkTargetPage(this.objects[i].targetPage - 1, this.objects[i].targetRect, null,
bs.splitRTL);
this.pageIndexes[i] = page != null ? page.index.viewIndex + 1 : -1;
}
currentId = current != null ? objects.indexOf(current) : -1;
if (treeFound) {
for (int parent = getParentId(currentId); parent != -1; parent = getParentId(parent)) {
states[parent] = OutlineItemState.EXPANDED;
}
rebuild();
if (getCount() == 1 && states[0] == OutlineItemState.COLLAPSED) {
states[0] = OutlineItemState.EXPANDED;
rebuild();
}
}
}
public int getParentId(final int id) {
if (0 <= id && id < objects.length) {
final int level = objects[id].level;
for (int i = id - 1; i >= 0; i--) {
if (objects[i].level < level) {
return i;
}
}
}
return -1;
}
protected void rebuild() {
mapping.clear();
int pos = 0;
int level = Integer.MAX_VALUE;
for (int cid = 0; cid < objects.length; cid++) {
if (objects[cid].level <= level) {
mapping.put(pos++, cid);
if (states[cid] == OutlineItemState.COLLAPSED) {
level = objects[cid].level;
} else {
level = Integer.MAX_VALUE;
}
}
}
}
@Override
public boolean hasStableIds() {
return false;
}
@Override
public int getCount() {
return mapping.size();
}
@Override
public OutlineLink getItem(final int position) {
final int id = mapping.get(position, -1);
return id >= 0 && id < objects.length ? objects[id] : null;
}
public String getPageIndex(final int position) {
final int id = mapping.get(position, -1);
final int index = id >= 0 && id < pageIndexes.length ? pageIndexes[id] : -1;
return index > 0 ? "" + (index - 1 + offset) : "";
}
@Override
public long getItemId(final int position) {
return mapping.get(position, -1);
}
public int getItemPosition(final OutlineLink item) {
for (int i = 0, n = getCount(); i < n; i++) {
if (item == getItem(i)) {
return i;
}
}
return -1;
}
public int getItemId(final OutlineLink item) {
for (int i = 0, n = objects.length; i < n; i++) {
if (item == objects[i]) {
return i;
}
}
return -1;
}
@Override
public View getView(final int position, final View convertView, final ViewGroup parent) {
final int id = (int) getItemId(position);
View container = null;
boolean firstTime = false;
if (convertView == null) {
container = LayoutInflater.from(context).inflate(R.layout.outline_item, parent, false);
firstTime = true;
} else {
container = convertView;
}
final TextView view = (TextView) container.findViewById(R.id.outline_title);
final ImageView btn = (ImageView) container.findViewById(R.id.outline_collapse);
final View space = container.findViewById(R.id.outline_space);
final TextView pageIndex = (TextView) container.findViewById(R.id.outline_pageindex);
final OutlineLink item = getItem(position);
view.setText(item.title.trim());
view.setTag(position);
btn.setTag(position);
pageIndex.setText(getPageIndex(position));
container.setBackgroundDrawable(id == currentId ? this.selected : this.background);
if (firstTime) {
final RelativeLayout.LayoutParams btnParams = (LayoutParams) btn.getLayoutParams();
spaceWidth = btnParams.width / 2;
container.setOnClickListener(voidListener);
view.setOnClickListener(itemListener);
}
final RelativeLayout.LayoutParams sl = (LayoutParams) space.getLayoutParams();
sl.width = item.level * spaceWidth;
space.setLayoutParams(sl);
if (states[id] == OutlineItemState.LEAF) {
btn.setOnClickListener(voidListener);
btn.setImageDrawable(null);
} else {
btn.setOnClickListener(collapseListener);
btn.setImageResource(states[id] == OutlineItemState.EXPANDED ? R.drawable.viewer_outline_item_expanded
: R.drawable.viewer_outline_item_collapsed);
}
return container;
}
private static enum OutlineItemState {
LEAF, EXPANDED, COLLAPSED;
}
private final class CollapseListener implements OnClickListener {
@Override
public void onClick(final View v) {
// System.out.println("btn.OnClickListener()");
{
final int position = ((Integer) v.getTag()).intValue();
final int id = (int) getItemId(position);
final OutlineItemState newState = states[id] == OutlineItemState.EXPANDED ? OutlineItemState.COLLAPSED
: OutlineItemState.EXPANDED;
states[id] = newState;
}
rebuild();
v.post(new Runnable() {
@Override
public void run() {
notifyDataSetChanged();
}
});
}
}
private static final class ItemListener implements OnClickListener {
@Override
public void onClick(final View v) {
for (ViewParent p = v.getParent(); p != null; p = p.getParent()) {
if (p instanceof ListView) {
final ListView list = (ListView) p;
final OnItemClickListener l = list.getOnItemClickListener();
if (l != null) {
l.onItemClick(list, v, ((Integer) v.getTag()).intValue(), 0);
}
return;
}
}
}
}
private static final class VoidListener implements OnClickListener {
@Override
public void onClick(final View v) {
}
}
}