/*
* Created by Itzik Braun on 12/3/2015.
* Copyright (c) 2015 deluge. All rights reserved.
*
* Last Modification at: 3/12/15 4:27 PM
*/
package com.braunster.chatsdk.fragments.abstracted;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.TimingLogger;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.ProgressBar;
import com.braunster.chatsdk.R;
import com.braunster.chatsdk.Utils.Debug;
import com.braunster.chatsdk.activities.abstracted.ChatSDKAbstractChatActivity;
import com.braunster.chatsdk.adapter.ChatSDKThreadsListAdapter;
import com.braunster.chatsdk.adapter.abstracted.ChatSDKAbstractThreadsListAdapter;
import com.braunster.chatsdk.dao.BThread;
import com.braunster.chatsdk.dao.entities.Entity;
import com.braunster.chatsdk.fragments.ChatSDKBaseFragment;
import com.braunster.chatsdk.network.BNetworkManager;
import com.braunster.chatsdk.network.events.BatchedEvent;
import com.braunster.chatsdk.network.events.Event;
import com.braunster.chatsdk.object.Batcher;
import com.braunster.chatsdk.object.UIUpdater;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* Created by itzik on 6/17/2014.
*/
public class ChatSDKAbstractConversationsFragment extends ChatSDKBaseFragment {
private static final String TAG = ChatSDKAbstractConversationsFragment.class.getSimpleName();
private static boolean DEBUG = Debug.ConversationsFragment;
public static final String APP_EVENT_TAG= "ConverstaionFragment";
protected ListView listThreads;
protected ChatSDKAbstractThreadsListAdapter adapter;
protected ProgressBar progressBar;
protected TimingLogger timings;
protected UIUpdater uiUpdater;
protected boolean inflateMenuItems = true;
protected AdapterView.OnItemLongClickListener onItemLongClickListener;
protected AdapterView.OnItemClickListener onItemClickListener;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActivity().registerReceiver(receiver, new IntentFilter(ChatSDKAbstractChatActivity.ACTION_CHAT_CLOSED));
}
@Override
public void initViews() {
listThreads = (ListView) mainView.findViewById(R.id.list_threads);
progressBar = (ProgressBar) mainView.findViewById(R.id.chat_sdk_progress_bar);
initList();
}
private void initList(){
// Create the adpater only if null, This is here so we wont override the adapter given from the extended class with setAdapter.
if (adapter == null)
adapter = new ChatSDKThreadsListAdapter(getActivity());
listThreads.setAdapter(adapter);
if (onItemClickListener==null)
{
onItemClickListener = new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
startChatActivityForID(adapter.getItem(position).getId());
}
};
}
listThreads.setOnItemClickListener(onItemClickListener);
if (onItemLongClickListener== null)
{
onItemLongClickListener = new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
showAlertDialog("", getResources().getString(R.string.alert_delete_thread), getResources().getString(R.string.delete),
getResources().getString(R.string.cancel), null, new DeleteThread(adapter.getItem(position).getEntityId()));
return true;
}
};
}
listThreads.setOnItemLongClickListener(onItemLongClickListener);
}
@Override
public void loadData() {
super.loadData();
if (mainView == null)
return;
adapter.setThreadItems(BNetworkManager.sharedManager().getNetworkAdapter().threadItemsWithType(BThread.Type.Private, adapter.getItemMaker()));
}
@Override
public void loadDataOnBackground() {
super.loadDataOnBackground();
if (DEBUG) timings = new TimingLogger(TAG.substring(0, 21), "loadDataOnBackground");
if (mainView == null)
{
return;
}
final boolean isFirst;
if (uiUpdater != null)
{
isFirst = false;
uiUpdater.setKilled(true);
ChatSDKAbstractConversationsFragmentChatSDKThreadPool.getInstance().removeSchedule(uiUpdater);
}
else
{
isFirst = true;
}
final boolean hasItems = adapter != null && adapter.getThreadItems().size() > 0;
if (isFirst && !hasItems) {
loadData();
}
uiUpdater = new UIUpdater() {
@Override
public void run() {
if (isKilled() && !isFirst && hasItems)
{
return;
}
if (DEBUG) {
timings.addSplit("Loading threads");
}
List list = BNetworkManager.sharedManager().getNetworkAdapter().threadItemsWithType(BThread.Type.Private, adapter.getItemMaker());
if (DEBUG) {
timings.addSplit("Loading threads");
}
uiUpdater = null;
Message message = new Message();
message.obj = list;
message.what = 1;
handler.sendMessageAtFrontOfQueue(message);
if (DEBUG) timings.addSplit("Sending message to handler.");
}
};
ChatSDKAbstractConversationsFragmentChatSDKThreadPool.getInstance().scheduleExecute(uiUpdater,isFirst ? 1 : 0);
}
@Override
public void refreshForEntity(Entity entity) {
super.refreshForEntity(entity);
if (adapter.getCount() == 0)
return;;
adapter.replaceOrAddItem((BThread) entity);
if (progressBar.getVisibility() == View.VISIBLE)
{
progressBar.setVisibility(View.GONE);
listThreads.setVisibility(View.VISIBLE);
}
}
@Override
public void clearData() {
if (adapter != null)
{
if (uiUpdater != null)
uiUpdater.setKilled(true);
adapter.getThreadItems().clear();
adapter.notifyDataSetChanged();
}
}
private class UpdateHandler extends Handler{
public UpdateHandler(Looper mainLooper) {
super(mainLooper);
}
@SuppressWarnings("unchecked")
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what)
{
case 1:
adapter.setThreadItems((List<ChatSDKThreadsListAdapter.ThreadListItem>) msg.obj);
if (progressBar.getVisibility() == View.VISIBLE)
{
progressBar.setVisibility(View.INVISIBLE);
listThreads.setVisibility(View.VISIBLE);
}
if (DEBUG) {
timings.addSplit("Updating UI");
timings.dumpToLog();
timings.reset(TAG.substring(0, 21), "loadDataOnBackground");
}
break;
}
}
}
private UpdateHandler handler = new UpdateHandler(Looper.getMainLooper());
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
if (!inflateMenuItems)
return;
super.onCreateOptionsMenu(menu, inflater);
MenuItem item =
menu.add(Menu.NONE, R.id.action_chat_sdk_add, 10, "Add Conversation");
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
item.setIcon(R.drawable.ic_plus);
}
@Override
public boolean onOptionsItemSelected(MenuItem item){
if (!inflateMenuItems)
return super.onOptionsItemSelected(item);
/* Cant use switch in the library*/
int id = item.getItemId();
if (id == R.id.action_chat_sdk_add)
{
startPickFriendsActivity();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onResume() {
super.onResume();
// loadDataOnBackground();
BatchedEvent batchedEvents = new BatchedEvent(APP_EVENT_TAG, "", Event.Type.AppEvent, handler);
batchedEvents.setBatchedAction(Event.Type.AppEvent, 3000, new Batcher.BatchedAction<String>() {
@Override
public void triggered(List<String> list) {
loadDataOnBackground();
}
});
getNetworkAdapter().getEventManager().removeEventByTag(APP_EVENT_TAG);
getNetworkAdapter().getEventManager().addEvent(batchedEvents);
}
@Override
public void onDestroy() {
super.onDestroy();
try {
getActivity().unregisterReceiver(receiver);
} catch (Exception e) {
}
}
public void setAdapter(ChatSDKAbstractThreadsListAdapter adapter) {
this.adapter = adapter;
}
public void setInflateMenuItems(boolean inflateMenuItems) {
this.inflateMenuItems = inflateMenuItems;
}
public void filterThreads(String text){
adapter.filterItems(text);
}
private BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ChatSDKAbstractChatActivity.ACTION_CHAT_CLOSED))
{
loadDataOnBackground();
}
}
};
public ChatSDKAbstractThreadsListAdapter getAdapter() {
return adapter;
}
/** FIXME not sure if needed.
* Created by braunster on 18/08/14.
*/
private static class ChatSDKAbstractConversationsFragmentChatSDKThreadPool {
// Sets the amount of time an idle thread waits before terminating
private static final int KEEP_ALIVE_TIME = 3;
// Sets the Time Unit to seconds
private static final TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;
private LinkedBlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>();
/*
* Gets the number of available cores
* (not always the same as the maximum number of cores)
*/
private static int NUMBER_OF_CORES =
Runtime.getRuntime().availableProcessors();
private ThreadPoolExecutor threadPool;
private ScheduledThreadPoolExecutor scheduledThreadPoolExecutor;
private static ChatSDKAbstractConversationsFragmentChatSDKThreadPool instance;
public static ChatSDKAbstractConversationsFragmentChatSDKThreadPool getInstance() {
if (instance == null)
instance = new ChatSDKAbstractConversationsFragmentChatSDKThreadPool();
return instance;
}
private ChatSDKAbstractConversationsFragmentChatSDKThreadPool(){
if (NUMBER_OF_CORES <= 0)
NUMBER_OF_CORES = 2;
// Creates a thread pool manager
threadPool = new ThreadPoolExecutor(
NUMBER_OF_CORES, // Initial pool size
NUMBER_OF_CORES, // Max pool size
KEEP_ALIVE_TIME,
KEEP_ALIVE_TIME_UNIT,
workQueue);
scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(NUMBER_OF_CORES);
}
public void execute(Runnable runnable){
threadPool.execute(runnable);
}
public void scheduleExecute(Runnable runnable, long delay){
scheduledThreadPoolExecutor.schedule(runnable, delay, TimeUnit.SECONDS);
}
public boolean removeSchedule(Runnable runnable){
return scheduledThreadPoolExecutor.remove(runnable);
}
}
}