/*
 * 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.activities.abstracted;

import android.app.ActionBar;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Vibrator;
import android.support.v4.widget.SwipeRefreshLayout;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AbsListView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.android.volley.VolleyError;
import com.android.volley.toolbox.ImageLoader;
import com.braunster.chatsdk.R;
import com.braunster.chatsdk.Utils.Debug;
import com.braunster.chatsdk.Utils.NotificationUtils;
import com.braunster.chatsdk.Utils.asynctask.MakeThreadImage;
import com.braunster.chatsdk.Utils.helper.ChatSDKChatHelper;
import com.braunster.chatsdk.Utils.volley.VolleyUtils;
import com.braunster.chatsdk.activities.ChatSDKBaseActivity;
import com.braunster.chatsdk.activities.ChatSDKBaseThreadActivity;
import com.braunster.chatsdk.activities.ChatSDKPickFriendsActivity;
import com.braunster.chatsdk.adapter.ChatSDKMessagesListAdapter;
import com.braunster.chatsdk.dao.BMessage;
import com.braunster.chatsdk.dao.BThread;
import com.braunster.chatsdk.dao.BThreadDao;
import com.braunster.chatsdk.dao.core.DaoCore;
import com.braunster.chatsdk.dao.entities.BThreadEntity;
import com.braunster.chatsdk.fragments.ChatSDKContactsFragment;
import com.braunster.chatsdk.network.BDefines;
import com.braunster.chatsdk.network.BNetworkManager;
import com.braunster.chatsdk.network.events.BatchedEvent;
import com.braunster.chatsdk.network.events.Event;
import com.braunster.chatsdk.network.events.MessageEventListener;
import com.braunster.chatsdk.object.Batcher;
import com.braunster.chatsdk.thread.ChatSDKImageMessagesThreadPool;
import com.braunster.chatsdk.view.ChatMessageBoxView;

import org.apache.commons.lang3.StringUtils;
import org.jdeferred.DoneCallback;
import org.jdeferred.FailCallback;

import java.util.List;

import de.hdodenhof.circleimageview.CircleImageView;
import timber.log.Timber;


/**
 * Created by itzik on 6/8/2014.
 */
public abstract class ChatSDKAbstractChatActivity extends ChatSDKBaseActivity implements  AbsListView.OnScrollListener{

    private static final String TAG = ChatSDKAbstractChatActivity.class.getSimpleName();
    private static final boolean DEBUG = Debug.ChatActivity;

    public static final int ADD_USERS = 103;
    public static final int SHOW_DETAILS = 200;

    public static final String ACTION_CHAT_CLOSED = "braunster.chat.action.chat_closed";

    /** The message event listener tag, This is used so we could find and remove the listener from the EventManager.
     * It will be removed when activity is paused. or when opened again for new thread.*/
    public static final String MessageListenerTAG = TAG + "MessageTAG";
    public static final String ThreadListenerTAG = TAG + "threadTAG";

    /** The key to get the thread long id.*/
    public static final String THREAD_ID = ChatSDKBaseThreadActivity.THREAD_ID;

    public static final String THREAD_ENTITY_ID = "Thread_Entity_ID";

    public static final String LIST_POS = "list_pos";
    public static final String FROM_PUSH = "from_push";
    public static final String MSG_TIMESTAMP = "timestamp";

    /** Pass true if you want slide down animation for this activity exit. */
    public static final String ANIMATE_EXIT = "animate_exit";

    /** The key to get the path of the last captured image path in case the activity is destroyed while capturing.*/
    public static final String CAPTURED_PHOTO_PATH = "captured_photo_path";

    protected  View actionBarView;

    protected ChatSDKChatHelper chatSDKChatHelper;

    protected  ChatMessageBoxView messageBoxView;
    protected  ListView listMessages;
    protected ChatSDKMessagesListAdapter messagesListAdapter;
    protected  BThread thread;

    protected  ProgressBar progressBar;
    protected  int listPos = -1;

    protected  Bundle data;

    private boolean queueStopped = false;

    /** If set to false in onCreate the menu items wont be inflated in the menu.
     * This can be useful if you want to customize the action bar.*/
    protected boolean inflateMenuItems = true;

    /** Save the scroll state of the messages list.*/
    protected  boolean scrolling = false;

    private boolean created = true;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setEnableCardToast(true);
        super.onCreate(savedInstanceState);

        enableCheckOnlineOnResumed(true);

        if ( !getThread(savedInstanceState) )
            return;

        chatSDKChatHelper = new ChatSDKChatHelper(this, thread, chatSDKUiHelper);
        chatSDKChatHelper.restoreSavedInstance(savedInstanceState);

        if (savedInstanceState != null)
        {
            listPos = savedInstanceState.getInt(LIST_POS, -1);
            savedInstanceState.remove(LIST_POS);
        }

        initActionBar();
    }

    @Override
    protected Bitmap getTaskDescriptionBitmap() {
        return super.getTaskDescriptionBitmap();
    }

    protected ActionBar readyActionBarToCustomView(){
        ActionBar ab = getActionBar();
        ab.setDisplayShowHomeEnabled(false);
        ab.setDisplayShowTitleEnabled(false);
        ab.setDisplayShowCustomEnabled(true);

        return ab;
    }

    protected View inflateActionBarView(int resId){
        // Inflate the custom view
        if (actionBarView == null || actionBarView.getId() != resId) {
            LayoutInflater inflater = LayoutInflater.from(this);
            actionBarView = inflater.inflate(resId, null);
        }

        return actionBarView;
    }

    protected void initActionBar(){
        if (DEBUG) Timber.d("initActionBar");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {

            ActionBar ab = readyActionBarToCustomView();

            /*http://stackoverflow.com/questions/16026818/actionbar-custom-view-with-centered-imageview-action-items-on-sides*/

            actionBarView = inflateActionBarView(R.layout.chat_sdk_actionbar_chat_activity);

            boolean changed;

            TextView txtName = (TextView) actionBarView.findViewById(R.id.chat_sdk_name);
            changed = setThreadName(txtName);


            final CircleImageView circleImageView = (CircleImageView) actionBarView.findViewById(R.id.chat_sdk_circle_image);
            final ImageView imageView = (ImageView) actionBarView.findViewById(R.id.chat_sdk_round_corner_image);

            final View.OnClickListener onClickListener = new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    onBackPressed();
                }
            };

            changed =  setThreadImage(circleImageView, imageView, onClickListener) || changed;

            if (changed)
                ab.setCustomView(actionBarView);
        }
    }

    /**
     *  Setting the thread name in the action bar.
     * */
    protected boolean setThreadName(TextView txtName){
        String displayName = thread.displayName();

        if (StringUtils.isBlank(displayName) )
            return false;

        if (txtName.getText() == null || !displayName.equals(txtName.getText().toString()))
        {
            // Set the title of the screen, This is used for the label in the screen overview on lollipop devices.
            setTitle(displayName);
            
            txtName.setText(displayName);
            txtName.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    showToast(((TextView) v).getText().toString());
                }
            });

            return true;
        }

        return false;
    }

    /**
     * Setting the thread image in the action bar.
     * */
    protected boolean setThreadImage(final CircleImageView circleImageView, final ImageView imageView, final View.OnClickListener onClickListener){
        final String imageUrl = thread.threadImageUrl();

        if (circleImageView.getTag() == null || StringUtils.isEmpty(imageUrl) || !imageUrl.equals(circleImageView.getTag()))
        {
            if (StringUtils.isEmpty(imageUrl))
                setRoundCornerDefault(circleImageView, imageView, onClickListener);
            else
            {
                // Check if there is a image saved in the cahce for this thread.
//                if (thread.getType()==BThread.Type.Private)
                    if (imageUrl.split(",").length > 1)
                    {
                        int size = getResources().getDimensionPixelSize(R.dimen.chat_sdk_chat_action_barcircle_image_view_size);
                        new MakeThreadImage(imageUrl.split(","), size, size, thread.getEntityID(), circleImageView);
                        circleImageView.setOnClickListener(onClickListener);
                        circleImageView.setVisibility(View.VISIBLE);
                        circleImageView.bringToFront();
                    }
                    else
                        VolleyUtils.getImageLoader().get(imageUrl, new ImageLoader.ImageListener() {
                            @Override
                            public void onResponse(ImageLoader.ImageContainer response, boolean isImmediate) {
                                if (response.getBitmap() != null) {
                                    circleImageView.setTag(imageUrl);
                                    circleImageView.setVisibility(View.INVISIBLE);
                                    imageView.setVisibility(View.INVISIBLE);
                                    circleImageView.setImageBitmap(response.getBitmap());
                                    circleImageView.setVisibility(View.VISIBLE);

                                    // setting the task description again so the thread image will be seeing.
                                    setTaskDescription(response.getBitmap(), getTaskDescriptionLabel(), getTaskDescriptionColor());
                                    
                                    circleImageView.setOnClickListener(onClickListener);

                                    circleImageView.bringToFront();
                                }
                            }

                            @Override
                            public void onErrorResponse(VolleyError error) {
                                setRoundCornerDefault(circleImageView, imageView, onClickListener);
                            }


                        });
            }

            return true;
        }

        return false;
    }

    /**
     * Set the default image for this thread in the action bar.
     * */
    protected void setRoundCornerDefault(CircleImageView circleImageView, ImageView roundedCornerImageView, View.OnClickListener onClickListener){
        circleImageView.setVisibility(View.INVISIBLE);
        roundedCornerImageView.setVisibility(View.INVISIBLE);

        if (thread.getTypeSafely() == BThread.Type.Public)
            roundedCornerImageView.setImageResource(R.drawable.ic_users);
        else if (thread.getUsers().size() < 3)
            roundedCornerImageView.setImageResource(R.drawable.ic_profile);
        else
            roundedCornerImageView.setImageResource(R.drawable.ic_users);

        roundedCornerImageView.setVisibility(View.VISIBLE);

        roundedCornerImageView.bringToFront();

        roundedCornerImageView.setOnClickListener(onClickListener);
    }

    protected void initViews(){
        messageBoxView = (ChatMessageBoxView) findViewById(R.id.chat_sdk_message_box);
        messageBoxView.setAlertToast(chatSDKUiHelper.getAlertToast());

        chatSDKChatHelper.setMessageBoxView(messageBoxView);

        progressBar = (ProgressBar) findViewById(R.id.chat_sdk_progressbar);

        chatSDKChatHelper.setProgressBar(progressBar);

        final SwipeRefreshLayout mSwipeRefresh = (SwipeRefreshLayout)findViewById(R.id.ptr_layout);
        
        mSwipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                if (DEBUG) Timber.d("onRefreshStarted");

                BNetworkManager.sharedManager().getNetworkAdapter().loadMoreMessagesForThread(thread)
                        .done(new DoneCallback<List<BMessage>>() {
                            @Override
                            public void onDone(List<BMessage> bMessages) {
                                if (DEBUG)
                                    Timber.d("New messages are loaded, Amount: %s", (bMessages == null ? "No messages" : bMessages.size()));

                                if (bMessages.size() < 2)
                                    showToast(getString(R.string.chat_activity_no_more_messages_to_load_toast));
                                else {
                                    // Saving the position in the list so we could back to it after the update.
                                    chatSDKChatHelper.loadMessages(true, false, -1, messagesListAdapter.getCount() + bMessages.size());
                                }

                                mSwipeRefresh.setRefreshing(false);
                            }
                        })
                        .fail(new FailCallback<Void>() {
                            @Override
                            public void onFail(Void aVoid) {
                                mSwipeRefresh.setRefreshing(false);
                            }
                        });
            }
        });

        listMessages = (ListView) findViewById(R.id.list_chat);

        chatSDKChatHelper.setListMessages(listMessages);

        if (messagesListAdapter == null)
            messagesListAdapter = new ChatSDKMessagesListAdapter(ChatSDKAbstractChatActivity.this, BNetworkManager.sharedManager().getNetworkAdapter().currentUserModel().getId());

        listMessages.setAdapter(messagesListAdapter);
        chatSDKChatHelper.setMessagesListAdapter(messagesListAdapter);
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        if (thread != null)
            outState.putLong(THREAD_ID, thread.getId());

        chatSDKChatHelper.onSavedInstanceBundle(outState);

        outState.putInt(LIST_POS, listMessages.getFirstVisiblePosition());
    }
    @Override
    protected void onStart() {
        super.onStart();

        if (thread != null && thread.getType() == BThread.Type.Public)
        {
            getNetworkAdapter().addUsersToThread(thread, getNetworkAdapter().currentUserModel());
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (DEBUG) Timber.v("onResume");

        if ( !getThread(data) )
            return;


        // Set up the UI to dismiss keyboard on touch event, Option and Send buttons are not included.
        // If list is scrolling we ignoring the touch event.
        setupTouchUIToDismissKeyboard(findViewById(R.id.chat_sdk_root_view), new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {

                // Using small delay for better accuracy in catching the scrolls.
                v.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        if (!scrolling)
                            hideSoftKeyboard(ChatSDKAbstractChatActivity.this);
                    }
                }, 300);

                return false;
            }
        }, R.id.chat_sdk_btn_chat_send_message, R.id.chat_sdk_btn_options);

        final MessageEventListener messageEventListener = new MessageEventListener(MessageListenerTAG + thread.getId(), thread.getEntityID()) {
            @Override
            public boolean onMessageReceived(BMessage message) {
                if (DEBUG) Timber.v("onMessageReceived, EntityID: %s", message.getEntityID());

                // Check that the message is relevant to the current thread.
                if (!message.getThread().getEntityID().equals(thread.getEntityID()) || message.getThreadDaoId() != thread.getId().intValue()) {
                    return false;
                }

                //Set as read.
                chatSDKChatHelper.markAsRead(message);

                boolean isAdded = messagesListAdapter.addRow(message);

                // Check if the message from the current user, If so return so we wont vibrate for the user messages.
                if (message.getBUserSender().getEntityID().equals(
                        BNetworkManager.sharedManager().getNetworkAdapter().currentUserModel().getEntityID()) )
                {
                    if (isAdded)
                    {
                        chatSDKChatHelper.scrollListTo(-1, true);
                    }
                    return false;
                }

                // We check to see that this message is really a new one and not loaded from the server.
                if (System.currentTimeMillis() - message.getDate().getTime() < 1000*60)
                {
                    Vibrator v = (Vibrator) ChatSDKAbstractChatActivity.this.getSystemService(Context.VIBRATOR_SERVICE);
                    // Vibrate for 500 milliseconds
                    v.vibrate(BDefines.VIBRATION_DURATION);
                }

                return false;
            }
        };

        final BatchedEvent threadBatchedEvent = new BatchedEvent(ThreadListenerTAG + thread.getId(), thread.getEntityID(), Event.Type.ThreadEvent, handler);
        threadBatchedEvent.setBatchedAction(Event.Type.ThreadEvent, new Batcher.BatchedAction<String>() {
            @Override
            public void triggered(List<String> list) {
                if (DEBUG) Timber.v("triggered, Users: %s", list.size());
                updateChat();
            }
        });

        new Thread(new Runnable() {
            @Override
            public void run() {

                getNetworkAdapter().getEventManager().messagesOn(thread.getEntityID(), null);
                getNetworkAdapter().getEventManager().threadUsersAddedOn(thread.getEntityID());

                // Making sure that this thread is handled by the EventManager so the user will get all the chat updates as he enters.
                // If we are not listening then we add it the the manager.
                if (!getNetworkAdapter().getEventManager().isListeningToThread(thread.getEntityID()))
                {
                    getNetworkAdapter().getEventManager().threadOn(thread.getEntityID(), null);
                }

                NotificationUtils.cancelNotification(ChatSDKAbstractChatActivity.this, BDefines.MESSAGE_NOTIFICATION_ID);

                chatSDKChatHelper.integrateUI(messageBoxView, messagesListAdapter, listMessages, progressBar);

                listMessages.setOnScrollListener(ChatSDKAbstractChatActivity.this);

                // Removing the last listener just to be sure we wont receive duplicates notifications.
                getNetworkAdapter().getEventManager().removeEventByTag(MessageListenerTAG + thread.getId());
                getNetworkAdapter().getEventManager().addEvent(messageEventListener);

                // Removing the last listener just to be sure we wont receive duplicates notifications.
                getNetworkAdapter().getEventManager().removeEventByTag(ThreadListenerTAG + thread.getId());
                getNetworkAdapter().getEventManager().addEvent(threadBatchedEvent);
            }
        }).start();


        // If the activity is just been created we load regularly, else we load and retain position
        if (!created)
            chatSDKChatHelper.loadMessagesAndRetainCurrentPos();
        else
        {
            chatSDKChatHelper.loadMessages(listPos);
        }

        created = false;
    }

    @Override
    protected void onPause() {
        super.onPause();
        getNetworkAdapter().getEventManager().removeEventByTag(MessageListenerTAG + thread.getId());
        getNetworkAdapter().getEventManager().removeEventByTag(ThreadListenerTAG + thread.getId());
    }

    /**
     * Sending a broadcast that the chat was closed, Only if there were new messages on this chat.
     * This is used for example to update the thread list that messages has been read.
     * */
    @Override
    protected void onStop() {
        super.onStop();

        if (chatSDKChatHelper.getReadCount() > 0)
            sendBroadcast(new Intent(ACTION_CHAT_CLOSED));

        if (thread != null && thread.getType() == BThread.Type.Public)
        {
            getNetworkAdapter().removeUsersFromThread(thread, getNetworkAdapter().currentUserModel());
        }
    }

    /**
     * Not used, There is a piece of code here that could be used to clean all images that was loaded for this chat from cache.
     * */
    @Override
    protected void onDestroy() {
        super.onDestroy();

        /* Clear all the images that was loaded for this chat from the cache. Currently not used but may be useful some day or to someone.
        for (String key : messagesListAdapter.getCacheKeys())
            VolleyUtils.getBitmapCache().remove(key);*/
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        if (DEBUG) Timber.v("onNewIntent");

        if ( !getThread(intent.getExtras()) )
            return;

        created = true;

        chatSDKChatHelper.setThread(thread);

        if (messagesListAdapter != null)
            messagesListAdapter.clear();

        initActionBar();

        chatSDKChatHelper.checkIfWantToShare(intent);
    }




    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (DEBUG) Timber.v("onActivityResult");

        chatSDKChatHelper.handleResult(requestCode, resultCode, data);


        if (requestCode == ADD_USERS)
        {
            if (DEBUG) Timber.d("ADD_USER_RETURN");
            if (resultCode == RESULT_OK)
            {
                updateChat();
            }
        }
        else if (requestCode == SHOW_DETAILS)
        {
            if (DEBUG) Timber.d("SHOW_DETAILS");
            if (resultCode == RESULT_OK)
            {
                // Updating the selected chat id.
                if (data != null && data.getExtras()!= null && data.getExtras().containsKey(THREAD_ID))
                {
                    if ( !getThread(data.getExtras()) )
                        return;

                    created = true;

                    chatSDKChatHelper.setThread(thread);

                    if (messagesListAdapter != null)
                        messagesListAdapter.clear();

                    initActionBar();
                }
                else
                    updateChat();


            }
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        if (!inflateMenuItems)
            return super.onCreateOptionsMenu(menu);

        // Adding the add user option only if group chat is enabled.
        if (BDefines.Options.GroupEnabled)
        {
            MenuItem item =
                    menu.add(Menu.NONE, R.id.action_chat_sdk_add, 10, getString(R.string.chat_activity_show_users_item_text));
            item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
            item.setIcon(R.drawable.ic_plus);
        }

        if (BDefines.Options.ThreadDetailsEnabled)
        {

            MenuItem itemThreadUsers =
                menu.add(Menu.NONE, R.id.action_chat_sdk_thread_details, 10, getString(R.string.chat_activity_show_thread_details));
            
            itemThreadUsers.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
            itemThreadUsers.setIcon(android.R.drawable.ic_menu_info_details);
        }
        
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        /* Cant use switch in the library*/
        int id = item.getItemId();

        if (!inflateMenuItems)
            return super.onOptionsItemSelected(item);

        if (id == R.id.action_chat_sdk_add)
        {
            startAddUsersActivity();
        }
        else if (id == R.id.action_chat_sdk_show)
        {
            showUsersDialog();
        }
        else if (id == R.id.action_chat_sdk_thread_details)
        {
            openThreadDetailsActivity();
        }

        return super.onOptionsItemSelected(item);
    }

    /**
     * Open the add users activity, Here you can see your contact list and add users to this chat.
     * The default add users activity will remove contacts that is already in this chat.
     * */
    protected void startAddUsersActivity(){
        // Showing the pick friends activity.
        Intent intent = new Intent(this, chatSDKUiHelper.pickFriendsActivity);
        intent.putExtra(ChatSDKPickFriendsActivity.MODE, ChatSDKPickFriendsActivity.MODE_ADD_TO_CONVERSATION);
        intent.putExtra(ChatSDKBaseThreadActivity.THREAD_ID, thread.getId());
        intent.putExtra(ANIMATE_EXIT, true);

        startActivityForResult(intent, ADD_USERS);

        overridePendingTransition(R.anim.slide_bottom_top, R.anim.dummy);
    }

    /**
     * Show a dialog containing all the users in this chat. */
    protected void showUsersDialog(){
        ChatSDKContactsFragment contactsFragment = ChatSDKContactsFragment.newThreadUsersDialogInstance(thread.getEntityID(), "Thread Users:", true);
        contactsFragment.show(getFragmentManager(), "Contacts");
    }

    /**
     * Open the thread details activity, Admin user can change thread name an image there.
     * */
    protected void openThreadDetailsActivity(){
        // Showing the pick friends activity.
        Intent intent = new Intent(this, chatSDKUiHelper.threadDetailsActivity);
        intent.putExtra(THREAD_ID, thread.getId());
        intent.putExtra(ANIMATE_EXIT, true);

        startActivityForResult(intent, SHOW_DETAILS);

        overridePendingTransition(R.anim.slide_bottom_top, R.anim.dummy);
    }

    /**
     * Not used, show a dialog containing all the user in this chat with custom title and option to show or hide headers.
     *
     * @param withHeaders if true the list will contain its headers for users.
     * @param title the title of the dialog.
     *
     * */
    protected void showUsersDialog(String title, boolean withHeaders){
        ChatSDKContactsFragment contactsFragment = ChatSDKContactsFragment.newThreadUsersDialogInstance(thread.getEntityID(), title, true);
        contactsFragment.setWithHeaders(withHeaders);
        contactsFragment.setTitle(title);
        contactsFragment.show(getFragmentManager(), "Contacts");
    }

    @Override
    public void onAuthenticated() {
        super.onAuthenticated();
        if (DEBUG) Timber.v("onAuthenticated");
        chatSDKChatHelper.loadMessagesAndRetainCurrentPos();
    }


    /**
     * Get the current thread from the bundle data, Thread could be in the getIntent or in onNewIntent.
     * */
    private boolean getThread(Bundle bundle){

        if (bundle != null && (bundle.containsKey(THREAD_ID) || bundle.containsKey(THREAD_ENTITY_ID)) )
        {
            this.data = bundle;
        }
        else
        {
            if ( getIntent() == null || getIntent().getExtras() == null)
            {
                finish();
                return false;
            }

            this.data = getIntent().getExtras();
        }

        if (this.data.containsKey(THREAD_ID))
        {
            thread = DaoCore.<BThread>fetchEntityWithProperty(BThread.class,
                    BThreadDao.Properties.Id,
                    this.data.getLong(THREAD_ID));
        }
        else  if (this.data.containsKey(THREAD_ENTITY_ID))
        {
            thread = DaoCore.<BThread>fetchEntityWithProperty(BThread.class,
                    BThreadDao.Properties.EntityID,
                    this.data.getString(THREAD_ENTITY_ID));
        }else{
            if (DEBUG) Timber.e("Thread id is empty");
            finish();
            return false;
        }

        if (thread == null)
        {
            if (DEBUG) Timber.e("No Thread found for given ID.");
            finish();
            return false;
        }

        return true;
    }

    /**
     * Update chat current thread using the {@link ChatSDKAbstractChatActivity#data} bundle saved.
     * Also calling the option menu to update it self. Used for showing the thread users icon if thread users amount is bigger then 2.
     * Finally update the action bar for thread image and name, The update will occur only if needed so free to call.
     *  */
    private void updateChat(){
        getThread(this.data);
        invalidateOptionsMenu();
        initActionBar();
    }

    /**
     * show the option popup when the menu key is pressed.
     * */
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode)
        {
            case KeyEvent.KEYCODE_MENU:
                messageBoxView.showOptionPopup();
                return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    /**
     * If the chat was open from a push notification we won't pass the backPress to the system instead we will navigate him to the main activity.
     * */
    @Override
    public void onBackPressed() {
        // If the message was opend from a notification back button should lead us to the main activity.
        if (data.containsKey(FROM_PUSH))
        {
            if (DEBUG) Timber.d("onBackPressed, From Push");
            data.remove(FROM_PUSH);

            chatSDKUiHelper.startMainActivity();
            return;
        }
        super.onBackPressed();
    }

    /** Used for pausing the volley image loader while the user is scrolling so the scroll will be smooth.*/
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        scrolling = scrollState != SCROLL_STATE_IDLE;

        // Pause disk cache access to ensure smoother scrolling
        if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_FLING) {
            VolleyUtils.getRequestQueue().stop();
            ChatSDKImageMessagesThreadPool.getInstance().getThreadPool().pause();
            queueStopped = true;
        }

        // Pause disk cache access to ensure smoother scrolling
        if (queueStopped && !scrolling)
        {
            ChatSDKImageMessagesThreadPool.getInstance().getThreadPool().resume();
            VolleyUtils.getRequestQueue().start();
            queueStopped = false;
        }

        messagesListAdapter.setScrolling(scrolling);
    }

    /**
     *  Not used.
     * */
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

    }

    /**
     * Get message list adapter that is used for the messages list.
     * */
    protected ChatSDKMessagesListAdapter getMessagesListAdapter() {
        return messagesListAdapter;
    }

    private Handler handler = new Handler();
}