package com.digitallizard.bbcnewsreader.fragments;
import java.util.ArrayList;
import java.util.Arrays;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Message;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.actionbarsherlock.app.SherlockFragment;
import com.digitallizard.bbcnewsreader.Item;
import com.digitallizard.bbcnewsreader.ItemLayout;
import com.digitallizard.bbcnewsreader.R;
import com.digitallizard.bbcnewsreader.ReaderActivity;
import com.digitallizard.bbcnewsreader.ResourceService;
import com.digitallizard.bbcnewsreader.ServiceManager;
import com.digitallizard.bbcnewsreader.ServiceManager.MessageReceiver;
import com.digitallizard.bbcnewsreader.data.DatabaseHandler;
public class FrontpageFragment extends SherlockFragment implements MessageReceiver {
private static final int ITEM_MIN_WIDTH = 100;
private static final int MAX_ITEMS_PER_ROW_PORTRAIT = 3;
private static final int MAX_ITEMS_PER_ROW_LANDSCAPE = 5;
private static final int MAX_ITEMS_PER_ROW_TABLET_LANDSCAPE = 5;
private static final int PORTRAIT_CODE = 0;
private static final float THUMB_HEIGHT_RATIO = 9/16f;
private static final float FRAGMENT_SCREEN_RATIO = 3/5f; //FIXME this is not the right way to do this
private DatabaseHandler database;
private ServiceManager service;
private FrontPageClickHandler clickHandler;
private String[] categoryNames;
private ArrayList<RelativeLayout> physicalCategories;
private ItemLayout[][] physicalItems;
private int categoryRowLength; // the number of items to show per row
public interface FrontPageClickHandler {
public void onItemClick(int id);
public void onCategoryClick(String title);
}
public void handleMessage(Message msg) {
switch (msg.what) {
case ResourceService.MSG_FULL_LOAD_COMPLETE:
loadUnloadedThumbs();
break;
case ResourceService.MSG_CATEGORY_LOADED:
categoryLoadFinished(msg.getData().getString(ResourceService.KEY_CATEGORY));
break;
case ResourceService.MSG_THUMB_LOADED:
updateItemThumb(msg.getData().getInt(ResourceService.KEY_ITEM_ID));
break;
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// bind to the service
service = new ServiceManager(getActivity(), this);
service.doBindService();
// bind to the database
database = new DatabaseHandler(this.getActivity());
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.frontpage, container, false);
createNewsDisplay(inflater, view);
return view;
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// check that the parent has implemented the correct callbacks
try {
clickHandler = (FrontPageClickHandler) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement FrontPageClickHandlers");
}
}
@Override
public void onDestroy() {
super.onDestroy();
// unbind the service
service.doUnbindService();
}
public void createNewsDisplay(LayoutInflater inflater, View container) {
//FIXME entire layout system needs fixing
LinearLayout content = (LinearLayout) container.findViewById(R.id.newsScrollerContent); // a reference to the layout where we put the news
// clear the content area
content.removeAllViewsInLayout();
// find the width and work out how many items we can add and how wide they should be
int rowPixelWidth = ((WindowManager) getActivity().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getWidth();
// take into account screen orientation and device type
int maxItemsPerRow = MAX_ITEMS_PER_ROW_PORTRAIT;
if(((WindowManager) getActivity().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation() != PORTRAIT_CODE) {
maxItemsPerRow = MAX_ITEMS_PER_ROW_LANDSCAPE;
}
//FIXME dangerous
if(((ReaderActivity) getActivity()).getCurrentDisplayMode() == ReaderActivity.DISPLAY_MODE_TABLET_LANDSCAPE) {
rowPixelWidth = (int) Math.floor(rowPixelWidth * FRAGMENT_SCREEN_RATIO);
maxItemsPerRow = MAX_ITEMS_PER_ROW_TABLET_LANDSCAPE;
}
int rowWidth = (int) Math.floor(rowPixelWidth / this.getResources().getDisplayMetrics().density); // formula to convert from pixels to dp
categoryRowLength = (int) Math.floor(rowWidth / ITEM_MIN_WIDTH);
if (categoryRowLength > maxItemsPerRow) {
categoryRowLength = maxItemsPerRow;
}
int thumbWidth = (int) Math.floor(rowPixelWidth / categoryRowLength);
int thumbHeight = (int) Math.floor(((float) thumbWidth) * THUMB_HEIGHT_RATIO);
// create the categories
categoryNames = database.getEnabledCategories()[1]; // string array with category names in it
physicalCategories = new ArrayList<RelativeLayout>(categoryNames.length);
physicalItems = new ItemLayout[categoryNames.length][categoryRowLength]; // the array to hold the news items
// loop through adding category views
for (int i = 0; i < categoryNames.length; i++) {
// create the category title bar
RelativeLayout categoryTitleBar = (RelativeLayout) inflater.inflate(R.layout.list_category_item, null);
// set a click listener
categoryTitleBar.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
// FIXME there must be a more elegant way of doing this...
// find the id of the category and report the click
int id = physicalCategories.indexOf(view);
clickHandler.onCategoryClick(categoryNames[id]);
}
});
// change the name
TextView name = (TextView) categoryTitleBar.findViewById(R.id.categoryTitle);
name.setText(categoryNames[i]);
// store the category title bar and add it to the scroller
physicalCategories.add(i, categoryTitleBar); // store the category for future use
content.addView(categoryTitleBar);
// create an item row and add items to it
//TableRow itemRow = new TableRow(getActivity());
LinearLayout itemRow = new LinearLayout(getActivity());
for (int j = 0; j < categoryRowLength; j++) {
// add a new item to the display
ItemLayout item = (ItemLayout) inflater.inflate(R.layout.list_news_item, null);
item.setPadding(1, 0, 1, 0);
item.setImageSize(thumbWidth, thumbHeight);
// set a click listener
item.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
// retrieve the title of this activity
ItemLayout item = (ItemLayout) view; // cast the view to a an itemlayout
// check there is an item at this view
if (item.isItem()) {
// report the click
clickHandler.onItemClick(item.getId());
}
}
});
physicalItems[i][j] = item; // store the item for future use
itemRow.addView(item); // add the item to the display
}
// add the row to the display
content.addView(itemRow);
// populate this category with news
displayCategoryItems(i);
}
}
private void displayCategoryItems(int category) {
// load from the database, if there's anything in it
Item[] items = database.getItems(categoryNames[category], categoryRowLength);
if (items != null) {
// change the physical items to match this
for (int i = 0; i < categoryRowLength; i++) {
// check we have not gone out of range of the available news
if (i < items.length) {
physicalItems[category][i].setTitle(items[i].getTitle());
physicalItems[category][i].setId(items[i].getId());
// try and get an thumbnail for this item
byte[] thumbBytes = items[i].getThumbnailBytes();
// check if any image data was returned
if (Arrays.equals(thumbBytes, ReaderActivity.NO_THUMBNAIL_URL_CODE)) {
// set the image to the no thumbnail image
physicalItems[category][i].setImage(R.drawable.no_thumb);
physicalItems[category][i].setImageLoaded(false);
}
else if (thumbBytes != null) {
// try to construct an image out of the bytes given by the database
Bitmap imageBitmap = BitmapFactory.decodeByteArray(thumbBytes, 0, thumbBytes.length); // load the image into a bitmap
physicalItems[category][i].setImage(imageBitmap);
physicalItems[category][i].setImageLoaded(true);
}
else {
// set the image to the default grey image
physicalItems[category][i].setImage(R.drawable.no_thumb_grey);
physicalItems[category][i].setImageLoaded(false);
}
}
}
}
}
private void categoryLoadFinished(String category) {
// the database has finished loading a category, we can update
// FIXME very inefficient way to turn (string) name into (int) id
int id = 0; // the id of the category
for (int i = 0; i < categoryNames.length; i++) {
// check if the name we have been given matches this category
if (category.equals(categoryNames[i])) {
id = i;
}
}
displayCategoryItems(id); // redisplay this category
}
private void updateItemThumb(int id) {
// loop through categories
for (int i = 0; i < physicalItems.length; i++) {
for (int t = 0; t < physicalItems[i].length; t++) {
if (physicalItems[i][t].getId() == id) {
// try and get an image for this item
byte[] imageBytes = database.getThumbnail(id);
// check if any image data was returned
if (Arrays.equals(imageBytes, ReaderActivity.NO_THUMBNAIL_URL_CODE)) {
// sets the image to the no thumbnail image
physicalItems[i][t].setImage(R.drawable.no_thumb);
physicalItems[i][t].setImageLoaded(false);
}
else if (imageBytes != null) {
// try to construct an image out of the bytes given by the database
Bitmap imageBitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length); // load the image into a bitmap
physicalItems[i][t].setImage(imageBitmap);
physicalItems[i][t].setImageLoaded(true);
}
else {
// set the image to the no thumbnail loaded image
physicalItems[i][t].setImage(R.drawable.no_thumb_grey);
physicalItems[i][t].setImageLoaded(false);
}
}
}
}
}
private void loadUnloadedThumbs() {
// find unloaded images
for(int i = 0; i < physicalItems.length; i++) {
for(int j = 0; j < physicalItems[i].length; j++) {
// only try and load the images if the item is set
if(!physicalItems[i][j].isImageLoaded() && physicalItems[i][j].isItem()) {
Bundle bundle = new Bundle();
bundle.putInt(ResourceService.KEY_ITEM_ID, physicalItems[i][j].getId());
service.sendMessageToService(ResourceService.MSG_LOAD_THUMB, bundle);
}
}
}
}
}