/*
* Copyright (C) 2009 Virgil Dobjanschi, Jeff Sharkey
*
* 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 no.java.schedule.activities.adapters;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.TouchDelegate;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.CheckBox;
import android.widget.TextView;
import no.java.schedule.R;
import no.java.schedule.activities.adapters.beans.*;
import no.java.schedule.activities.adapters.interfaces.ExpandableAdapterListener;
import no.java.schedule.provider.SessionsContract;
import no.java.schedule.provider.SessionsContract.Blocks;
import java.util.ArrayList;
import java.util.List;
import static android.provider.BaseColumns._ID;
import static no.java.schedule.provider.SessionsContract.BlocksColumns.TIME_END;
import static no.java.schedule.provider.SessionsContract.BlocksColumns.TIME_START;
import static no.java.schedule.provider.SessionsContract.SessionsColumns.*;
import static no.java.schedule.provider.SessionsContract.TracksColumns.TRACK;
/**
* The expandable sessions_menu adapter
*/
public class ExpandableSessionsAdapter extends BaseExpandableListAdapter {
private static final String SCHEDULE_TIME_SORT_ORDER = SessionsContract.BlocksColumns.TIME_START+","+ SessionsContract.SessionsColumns.ROOM +" ASC";
private static final String SCHEDULE_TRACK_SORT_ORDER = SessionsContract.Tracks.TRACK +", "+ SessionsContract.Sessions.TITLE +" ASC";
private static final String SCHEDULE_SPEAKER_SORT_ORDER = SessionsContract.SessionsColumns.SPEAKER_NAMES +", "+ SessionsContract.Sessions.TITLE +" ASC";
private final SessionsAdapter.MODE mode;
private final Context context;
private ScheduleSorting sortOrder;
private List<Block> blocks;
private View.OnClickListener starListener;
private final Uri uri;
private final String selection;
private final String[] selectionArgs;
private final ExpandableAdapterListener listener;
private ContentObserver contentObserver;
/**
* Constructor
*
* @param context The context
* @param uri The URI
* @param selection The selection
* @param selectionArgs The selection arguments
* @param sortOrder The sortOrder
* @param mode The mode (MODE_ALL, MODE_STARRED)
*/
public ExpandableSessionsAdapter(Context context, Uri uri, String selection,
String[] selectionArgs, ScheduleSorting sortOrder, SessionsAdapter.MODE mode, ExpandableAdapterListener listener) {
this.context = context;
this.sortOrder = sortOrder;
blocks = new ArrayList<Block>();
this.uri = uri;
this.selection = selection;
this.selectionArgs = selectionArgs;
this.mode = mode;
this.listener = listener;
buildItems();
registerListenersAndObservers();
}
private void registerListenersAndObservers() {
starListener = new StarredSessionListener(context);
contentObserver = new SessionListContentObserver();
context.getContentResolver().registerContentObserver(uri, true, contentObserver);
}
public Object getChild(int groupPosition, int childPosition) {
Block block = blocks.get(groupPosition);
if( block.hasSessions()) {
return block.getSession(childPosition);
} else {
return block;
}
}
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
public int getChildrenCount( int groupPosition) {
if( groupPosition >= blocks.size()){
return 0;
}
return blocks.get(groupPosition).getCount();
}
public View getChildView( int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent)
{
Block block = blocks.get(groupPosition);
boolean sessionView = block.hasSessions();
View view;
if( convertView == null){
LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = vi.inflate( R.layout.session_row, null);
} else {
view = convertView;
}
//TODO - split into separate classes rather than to rely on switches
if( sessionView)
{
SessionDisplay session = block.getSession(childPosition);
view.findViewById(R.id.session_color).setBackgroundColor(session.getColor());
String titleText = session.getTitle();
final TextView title = (TextView) view.findViewById(R.id.session_title);
title.setText(titleText);
CheckBox checkBox = ((CheckBox)view.findViewById(R.id.session_star));
checkBox.setTag( session);
checkBox.setOnClickListener(starListener);
checkBox.setChecked(session.isStarred());
checkBox.setVisibility(View.VISIBLE);
// Find and hook up larger delegate view for toggling star
View starDelegate = view.findViewById(R.id.star_delegate);
Rect largeBounds = new Rect(0, 0, 1024, 1024);
starDelegate.setTouchDelegate(new TouchDelegate(largeBounds, checkBox));
((TextView)view.findViewById(R.id.session_speakers)).setText(session.getSpeakers());
TextView sessionTrack = ((TextView)view.findViewById(R.id.session_track));
sessionTrack.setText(session.getTrack());
sessionTrack.setTextColor( session.getColor());
((TextView)view.findViewById(R.id.session_room)).setText(session.getRoom());
view.findViewById(R.id.session_room).setVisibility(View.VISIBLE);
if (session.getType().equalsIgnoreCase("presentation")){
view.findViewById(R.id.session_track).setVisibility(View.VISIBLE);
} else {
view.findViewById(R.id.session_track).setVisibility(View.GONE);
}
}
else
{
// The empty text view (already set)
view.findViewById(R.id.session_color).setBackgroundColor( 0x00000000);
((TextView)view.findViewById(R.id.session_title)).setText( context.getString(R.string.starred_slot_empty_title));
view.findViewById(R.id.session_star).setVisibility(View.GONE);
((TextView)view.findViewById(R.id.session_speakers)).setText( context.getString(R.string.starred_slot_empty_subtitle));
view.findViewById(R.id.session_track).setVisibility(View.GONE);
view.findViewById(R.id.session_room).setVisibility(View.GONE);
}
return view;
}
public Object getGroup( int groupPosition) {
return blocks.get( groupPosition);
}
public int getGroupCount(){
return blocks.size();
}
public long getGroupId( int groupPosition){
return groupPosition;
}
public View getGroupView( int groupPosition, boolean isExpanded, View convertView, ViewGroup parent){
Block block = blocks.get(groupPosition);
View groupView;
if( convertView == null) {
LayoutInflater vi = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE);
groupView = vi.inflate( R.layout.exp_time_slot_separator_row_view, null);
} else {
groupView = convertView;
}
final TextView title = (TextView) groupView.findViewById(R.id.text_sep);
title.setText( block.getHeading());
final TextView count = (TextView) groupView.findViewById(R.id.text_count);
if( block.hasSessions()) {
count.setText(context.getString(R.string.group_session_count, block.getCount()));
} else {
count.setText( "");
}
return groupView;
}
public boolean hasStableIds() {
return true;
}
public boolean isChildSelectable( int groupPosition, int childPosition) {
return true;
}
/**
* Release the adapter
*/
public void close() {
blocks.clear();
if (contentObserver != null) {
context.getContentResolver().unregisterContentObserver(contentObserver);
contentObserver = null;
}
}
/**
* Build the items
*/
private void buildItems() {
if (mode == SessionsAdapter.MODE.SCHEDULE) {
buildAllItems(sortOrder);
} else {
buildStarredItems(sortOrder);
}
}
private void buildAllItems(ScheduleSorting sorting) {
List<Block> newList = new ArrayList<Block>();
Cursor cursor = context.getContentResolver().query(uri, null, selection, selectionArgs, sortOrderSQLFor(sorting));
if (cursor != null && cursor.moveToFirst()) {
Block block=null;
String lastBlockId = "";
do {
final Session session = createSession(cursor);
final String blockId = blockIdFor(session, sorting);
if (!lastBlockId.equals(blockId)){
block = createBlockFor(session,sorting);
lastBlockId = blockId !=null ? blockId : "";
newList.add( block);
}
block.addSession(session);
} while (cursor.moveToNext());
}
cursor.close();
blocks = newList;
}
private Block createBlockFor(Session session, ScheduleSorting sorting) {
switch(sorting){
default:
case SCHEDULE:
return new TimeBlock(context, session);
case TRACKS:
return new TrackBlock(context, session.getTrack());
case SPEAKERS:
return new SpeakerBlock(context, session.getSpeakers());
}
}
private String blockIdFor(Session session, ScheduleSorting sorting) {
switch(sorting){
default:
case SCHEDULE:
long blockStart = ScheduleTimeUtil.findBlockStart(session.getStartTime());
return String.valueOf(blockStart);
case TRACKS:
return session.getTrack();
case SPEAKERS:
return session.getSpeakers();
}
}
private String sortOrderSQLFor(ScheduleSorting sorting) {
switch(sorting){
default:
case SCHEDULE:
return SCHEDULE_TIME_SORT_ORDER;
case TRACKS:
return SCHEDULE_TRACK_SORT_ORDER;
case SPEAKERS:
return SCHEDULE_SPEAKER_SORT_ORDER;
}
}
private Session createSession(Cursor cursor) {
final String title = cursor.getString( cursor.getColumnIndexOrThrow( TITLE ));
final String speakers = cursor.getString( cursor.getColumnIndexOrThrow( SPEAKER_NAMES ));
final String room = cursor.getString( cursor.getColumnIndexOrThrow( ROOM ));
final String track = cursor.getString( cursor.getColumnIndexOrThrow( TRACK ));
final int color = cursor.getInt( cursor.getColumnIndexOrThrow(SessionsContract.TracksColumns.COLOR ));
final boolean starred = cursor.getInt( cursor.getColumnIndexOrThrow( STARRED )) == 1;
final long startTime = cursor.getLong( cursor.getColumnIndexOrThrow( TIME_START ));
final long endTime = cursor.getLong( cursor.getColumnIndexOrThrow( TIME_END ));
final int id = cursor.getInt( cursor.getColumnIndexOrThrow( _ID ));
final String type = cursor.getString( cursor.getColumnIndexOrThrow( TYPE));
return new Session(context, id, startTime, endTime, title, speakers, room, track, color, starred, type);
}
/**
* Build the items
* @param sortOrder
*/
private void buildStarredItems(ScheduleSorting sortOrder) { //TODO refactor into "buildall"
List<Block> newList = new ArrayList<Block>();
List<Session> list = new ArrayList<Session>();
Cursor cursor = context.getContentResolver().query(uri, null, selection, selectionArgs, sortOrderSQLFor(sortOrder));
if (cursor != null) {
if (cursor.moveToFirst()) {
do {
list.add(createSession(cursor));
} while (cursor.moveToNext());
}
cursor.close();
}
Cursor bcursor = context.getContentResolver().query(Blocks.CONTENT_URI, null, null, null, null);
TimeBlock lastBlock = null;
if (bcursor != null) {
if (bcursor.moveToFirst()) {
int btsi = bcursor.getColumnIndexOrThrow(TIME_START);
int btei = bcursor.getColumnIndexOrThrow(TIME_END);
// Generate the items
do {
long startTime = bcursor.getLong(btsi);
long endTime = bcursor.getLong(btei);
TimeBlock block = new TimeBlock(context, startTime, endTime);
if (lastBlock!=null && block.getStartSlotTime() == lastBlock.getStartSlotTime()){
continue;
}
newList.add( block);
lastBlock = block;
while (list.size() > 0) {
Session si = list.get(0);
if (si.getStartTime() == startTime) {
block.addSession(list.remove(0));
} else {
break;
}
}
} while (bcursor.moveToNext());
}
bcursor.close();
}
blocks = newList;
}
public void setSorting(ScheduleSorting sorting) {
this.sortOrder = sorting;
buildItems();
}
private class SessionListContentObserver extends ContentObserver {
public SessionListContentObserver() {
super(new Handler());
}
@Override
public void onChange(boolean selfChange) {
int beforeCount = blocks.size();
buildItems();
notifyDataSetChanged();
if( blocks.size() != beforeCount) {
ExpandableSessionsAdapter.this.listener.onNewData();
}
}
}
}