package treehou.se.habit.ui.adapter;
import android.content.Context;
import android.support.annotation.IntDef;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import se.treehou.ng.ohcommunicator.connector.models.OHServer;
import se.treehou.ng.ohcommunicator.connector.models.OHSitemap;
import treehou.se.habit.R;
public class SitemapListAdapter extends RecyclerView.Adapter<SitemapListAdapter.SitemapBaseHolder> {
@IntDef({STATE_SUCCESS, STATE_LOADING, STATE_ERROR})
public @interface ServerState {}
public static final int STATE_SUCCESS = 0;
public static final int STATE_LOADING = 1;
public static final int STATE_ERROR = 2;
protected LayoutInflater inflater;
protected Context context;
private Map<OHServer, SitemapItem> items = new HashMap<>();
private SitemapSelectedListener sitemapSelectedListener = new DummySitemapSelectListener();
private static class SitemapItem{
public OHServer server;
public @ServerState int state = STATE_LOADING;
public List<OHSitemap> sitemaps = new ArrayList<>();
public SitemapItem(OHServer server) {
this.server = server;
}
public void addItem(OHSitemap sitemap){
sitemaps.add(sitemap);
state = STATE_SUCCESS;
}
}
public class SitemapBaseHolder extends RecyclerView.ViewHolder {
public TextView lblServer;
public SitemapBaseHolder(View itemView) {
super(itemView);
lblServer = (TextView) itemView.findViewById(R.id.lbl_server);
}
}
public class SitemapHolder extends SitemapBaseHolder {
public TextView lblName;
public SitemapHolder(View view) {
super(view);
lblName = (TextView) itemView.findViewById(R.id.lbl_sitemap);
}
}
public interface SitemapSelectedListener {
void onSelected(OHServer server, OHSitemap sitemap);
void onErrorSelected(OHServer server);
}
class DummySitemapSelectListener implements SitemapSelectedListener {
@Override
public void onSelected(OHServer server, OHSitemap sitemap) {}
@Override
public void onErrorSelected(OHServer server) {}
}
public class SitemapErrorHolder extends SitemapBaseHolder {
public SitemapErrorHolder(View view) {
super(view);
}
}
public class SitemapLoadHolder extends SitemapBaseHolder {
public SitemapLoadHolder(View view) {
super(view);
}
}
public class GetResult {
public SitemapItem item;
public OHSitemap sitemap;
public GetResult(SitemapItem item, OHSitemap sitemap) {
this.sitemap = sitemap;
this.item = item;
}
}
public SitemapListAdapter(Context context) {
if (context == null) {
throw new IllegalArgumentException("Context cannot be null");
}
this.context = context;
this.inflater = LayoutInflater.from(context);
}
@Override
public SitemapBaseHolder onCreateViewHolder(ViewGroup viewGroup, int type) {
LayoutInflater inflater = LayoutInflater.from(context);
if (STATE_SUCCESS == type) {
View itemView = inflater.inflate(R.layout.item_sitemap, null);
return new SitemapHolder(itemView);
} else if (STATE_LOADING == type) {
View itemView = inflater.inflate(R.layout.item_sitemap_load, null);
return new SitemapLoadHolder(itemView);
} else {
View serverLoadFail = inflater.inflate(R.layout.item_sitemap_failed, null);
return new SitemapErrorHolder(serverLoadFail);
}
}
@Override
public void onBindViewHolder(final SitemapBaseHolder sitemapHolder, int position) {
int type = getItemViewType(position);
final GetResult item = getItem(position);
final OHSitemap sitemap = item.sitemap;
final OHServer server = item.item.server;
if (STATE_SUCCESS == type) {
SitemapHolder holder = (SitemapHolder) sitemapHolder;
holder.lblName.setText(sitemap.getDisplayName());
holder.lblServer.setText(server.getDisplayName());
sitemapHolder.itemView.setOnClickListener(v -> sitemapSelectedListener.onSelected(server, sitemap));
} else if (STATE_LOADING == type) {
SitemapLoadHolder holder = (SitemapLoadHolder) sitemapHolder;
holder.lblServer.setText(server.getDisplayName());
} else if (STATE_ERROR == type) {
SitemapErrorHolder holder = (SitemapErrorHolder) sitemapHolder;
holder.lblServer.setText(server.getDisplayName());
holder.itemView.setOnClickListener(v -> sitemapSelectedListener.onErrorSelected(server));
}
}
@Override
public int getItemViewType(int position) {
int count = 0;
for (SitemapItem item : items.values()) {
if (STATE_SUCCESS == item.state) {
if (position >= count && position < (count + item.sitemaps.size())) {
return STATE_SUCCESS;
}
count += item.sitemaps.size();
} else if (STATE_ERROR == item.state) {
if (count == position) {
return STATE_ERROR;
}
count++;
} else if (STATE_LOADING == item.state) {
if (count == position) {
return STATE_LOADING;
}
count++;
}
}
return STATE_LOADING;
}
@Override
public int getItemCount() {
int count = 0;
for (SitemapItem item : items.values()) {
if (item.state == STATE_SUCCESS) {
count += item.sitemaps.size();
} else {
count++;
}
}
return count;
}
/**
* Returns item at a certain position
*
* @param position item to grab item for
* @return
*/
public GetResult getItem(int position) {
GetResult result = null;
int count = 0;
for (SitemapItem item : items.values()) {
if (STATE_SUCCESS == item.state) {
for (OHSitemap sitemap : item.sitemaps) {
if (count == position) {
result = new GetResult(item, sitemap);
return result;
}
count++;
}
} else {
if (count == position) {
result = new GetResult(item, null);
break;
}
count++;
}
}
return result;
}
public void addAll(OHServer server, List<OHSitemap> sitemapIds) {
for (OHSitemap sitemap : sitemapIds) {
add(server, sitemap);
}
}
public void add(OHServer server, OHSitemap sitemap) {
SitemapItem item = items.get(server);
if (item == null) {
item = new SitemapItem(server);
items.put(item.server, item);
}
item.addItem(sitemap);
notifyDataSetChanged();
}
/**
* Remove all sitemap entries from adapter.
*/
public void clear() {
items.clear();
notifyItemRangeRemoved(0, items.size() - 1);
}
public void remove(OHSitemap sitemap) {
int pos = findPosition(sitemap);
remove(sitemap, pos);
}
public void remove(OHSitemap sitemap, int position) {
SitemapItem item = null; // TODO items.get(serverDB.getId());
if (sitemap == null) {
return;
}
item.sitemaps.remove(sitemap);
notifyItemRemoved(position);
}
/**
* Add listener for when sitemap item is clicked
*
* @param sitemapSelectedListener listens for click on sitemap.
*/
public void setSitemapSelectedListener(SitemapSelectedListener sitemapSelectedListener) {
if (sitemapSelectedListener == null) {
this.sitemapSelectedListener = new DummySitemapSelectListener();
return;
}
this.sitemapSelectedListener = sitemapSelectedListener;
}
private int findPosition(final OHSitemap sitemap) {
int count = 0;
for (SitemapItem item : items.values()) {
if (STATE_SUCCESS == item.state) {
for (OHSitemap sitemapIter : item.sitemaps) {
if (sitemap == sitemapIter) {
return count;
}
count++;
}
} else {
count++;
}
}
return -1;
}
/**
* Get a sitemap item. Creates a new server item if no item exists.
*
* @param server server to get sitemap item for.
* @return
*/
private SitemapItem getItem(OHServer server) {
SitemapItem item = items.get(server);
if (item == null) {
item = new SitemapItem(server);
items.put(server, item);
}
return item;
}
public void setServerState(OHServer server, @ServerState int state) {
SitemapItem item = getItem(server);
item.state = state;
notifyDataSetChanged();
}
public boolean contains(OHSitemap sitemap) {
return items.containsKey(sitemap.getServer()) && items.get(sitemap.getServer()).sitemaps.contains(sitemap);
}
}