package org.chat21.android.ui.messages.activities;

import android.annotation.TargetApi;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.PorterDuff;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.annotation.Px;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.text.Editable;
import android.text.TextWatcher;
import android.text.style.ClickableSpan;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.bumptech.glide.Glide;
import com.bumptech.glide.request.animation.GlideAnimation;
import com.bumptech.glide.request.target.SimpleTarget;
import com.vanniktech.emoji.EmojiEditText;
import com.vanniktech.emoji.EmojiImageView;
import com.vanniktech.emoji.EmojiPopup;
import com.vanniktech.emoji.emoji.Emoji;
import com.vanniktech.emoji.listeners.OnEmojiBackspaceClickListener;
import com.vanniktech.emoji.listeners.OnEmojiClickListener;
import com.vanniktech.emoji.listeners.OnEmojiPopupDismissListener;
import com.vanniktech.emoji.listeners.OnEmojiPopupShownListener;
import com.vanniktech.emoji.listeners.OnSoftKeyboardCloseListener;
import com.vanniktech.emoji.listeners.OnSoftKeyboardOpenListener;

import org.chat21.android.R;
import org.chat21.android.core.ChatManager;
import org.chat21.android.core.chat_groups.listeners.ChatGroupsListener;
import org.chat21.android.core.chat_groups.models.ChatGroup;
import org.chat21.android.core.chat_groups.syncronizers.GroupsSyncronizer;
import org.chat21.android.core.contacts.synchronizers.ContactsSynchronizer;
import org.chat21.android.core.exception.ChatRuntimeException;
import org.chat21.android.core.messages.handlers.ConversationMessagesHandler;
import org.chat21.android.core.messages.listeners.ConversationMessagesListener;
import org.chat21.android.core.messages.listeners.SendMessageListener;
import org.chat21.android.core.messages.models.Message;
import org.chat21.android.core.presence.PresenceHandler;
import org.chat21.android.core.presence.listeners.PresenceListener;
import org.chat21.android.core.users.models.IChatUser;
import org.chat21.android.storage.OnUploadedCallback;
import org.chat21.android.storage.StorageHandler;
import org.chat21.android.ui.ChatUI;
import org.chat21.android.ui.chat_groups.activities.GroupAdminPanelActivity;
import org.chat21.android.ui.messages.adapters.MessageListAdapter;
import org.chat21.android.ui.messages.fragments.BottomSheetAttach;
import org.chat21.android.ui.messages.listeners.OnMessageClickListener;
import org.chat21.android.ui.users.activities.PublicProfileActivity;
import org.chat21.android.utils.StringUtils;
import org.chat21.android.utils.TimeUtils;
import org.chat21.android.utils.image.CropCircleTransformation;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

import static org.chat21.android.ui.ChatUI.BUNDLE_CHANNEL_TYPE;
import static org.chat21.android.utils.DebugConstants.DEBUG_NOTIFICATION;
import static org.chat21.android.utils.DebugConstants.DEBUG_USER_PRESENCE;

/**
 * Created by stefano on 31/08/2015.
 */
public class MessageListActivity extends AppCompatActivity
        implements ConversationMessagesListener, PresenceListener, ChatGroupsListener {
    private static final String TAG = MessageListActivity.class.getName();

    public static final int _INTENT_ACTION_GET_PICTURE = 853;

    private PresenceHandler presenceHandler = null;
    private ConversationMessagesHandler conversationMessagesHandler;
    private boolean conversWithOnline = false;
    private long conversWithLastOnline = -1;

    private GroupsSyncronizer groupsSyncronizer = null;

    private RecyclerView recyclerView;
    private LinearLayoutManager mLinearLayoutManager;
    private MessageListAdapter messageListAdapter;
    private Toolbar toolbar;

    private ImageView mPictureView;
    private TextView mTitleTextView;
    private TextView mSubTitleTextView;
    private RelativeLayout mNoMessageLayout;

    private EmojiPopup emojiPopup;
    private EmojiEditText editText;
    private ViewGroup rootView;
    private ImageView emojiButton;
    private ImageView attachButton;
    private ImageView sendButton;
    private LinearLayout mEmojiBar;

    /**
     * {@code recipient} is the real contact whom is talking with.
     * it contains all the info to start a conversation.
     */
    private IChatUser recipient;
    /**
     * {@code chatGroup} is a support item witch contains all addictional info
     * about group such as the members list which cannot be included inside the {@code recipient}
     */
    private ChatGroup chatGroup;
    private String channelType; // detect if is a group or a direct conversation

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        groupsSyncronizer = ChatManager.getInstance().getGroupsSyncronizer();

        setContentView(R.layout.activity_message_list);

        registerViews();

        // retrieve recipient
        recipient = (IChatUser) getIntent().getSerializableExtra(ChatUI.BUNDLE_RECIPIENT);

        // BEGIN contactsSynchronizer
        ContactsSynchronizer contactsSynchronizer = ChatManager.getInstance().getContactsSynchronizer();
        if (contactsSynchronizer != null) {
            IChatUser matchedContact = contactsSynchronizer.findById(recipient.getId());

            if(matchedContact != null) {
                recipient = matchedContact;
            }
        }
        // END contactsSynchronizer

        // retrieve channel type
        channelType = (String) getIntent().getExtras().get(BUNDLE_CHANNEL_TYPE);
        // default case
        if (!StringUtils.isValid(channelType)) {
            channelType = Message.DIRECT_CHANNEL_TYPE;
        }

        // get the recipient from background notification
        if (isFromBackgroundNotification()) {
            recipient = getUserFromBackgroundNotification();
        }

        if (channelType.equals(Message.GROUP_CHANNEL_TYPE)) {
            chatGroup = ChatManager.getInstance().getGroupsSyncronizer().getById(recipient.getId());
        } else {
            // default case : DIRECT_CHANNEL_TYPE
        }


//        if (channelType.equals(Message.GROUP_CHANNEL_TYPE)) {
//            // retrieve group
//            chatGroup = ChatManager.getInstance().getGroupsSyncronizer().getById(recipient.getId());
//        } else {
//            // retrive contact
//            String recipientId;
//            if (recipient != null) {
//                recipientId = recipient.getId();
//            } else {
//                if (StringUtils.isValid(getIntent().getStringExtra("sender"))) {
//                    recipientId = getIntent().getStringExtra("sender");
//                    Log.d(DEBUG_NOTIFICATION, "MessageListActivity.onCreate:" +
//                            " recipientId == " + recipientId);
//                } else {
//                    throw new ChatRuntimeException("Recipient can not be retrieved! " +
//                            "Did you pass it correctly?");
//                }
//            }
//
//            // retrieve the updated recipient
//            recipient = ChatManager.getInstance().getContactsSynchronizer().findById(recipientId);
//        }



        // ######### begin conversation messages handler
        conversationMessagesHandler = ChatManager.getInstance().getConversationMessagesHandler(recipient);
        conversationMessagesHandler.upsertConversationMessagesListener(this);
        Log.d(TAG, "MessageListActivity.onCreate: conversationMessagesHandler attached");
        conversationMessagesHandler.connect();
        Log.d(TAG, "MessageListActivity.onCreate: conversationMessagesHandler connected");
        // ######### end conversation messages handler

        initRecyclerView();

        //////// toolbar
        if (channelType.equals(Message.DIRECT_CHANNEL_TYPE)) {
            if (recipient != null) {
                initDirectToolbar(recipient);
            }
        } else if (channelType.equals(Message.GROUP_CHANNEL_TYPE)) {
            if (chatGroup != null) {
                initGroupToolbar(chatGroup);
            }
        }

        // minimal settings
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        //////// end toolbar

        /////// presence manager
        if (channelType.equals(Message.DIRECT_CHANNEL_TYPE)) {
            if (recipient != null) {
                presenceHandler = ChatManager.getInstance().getPresenceHandler(recipient.getId());
                presenceHandler.upsertPresenceListener(this);
                presenceHandler.connect();
            }
        } else {
            if (recipient != null) {
                groupsSyncronizer = ChatManager.getInstance().getGroupsSyncronizer();
                groupsSyncronizer.upsertGroupsListener(this);
                groupsSyncronizer.connect();
            }
        }


        // panel which contains the edittext, the emoji button and the attach button
        initInputPanel();


    }

    // if the calling intent contains the
    private boolean isFromBackgroundNotification() {

        if (getIntent() == null) {
            return false;
        } else {
            if (!getIntent().hasExtra("sender")) {
                return false;
            } else {
                String recipient = getIntent().getStringExtra("sender");
                return StringUtils.isValid(recipient) ? true : false;
            }
        }
    }

    private IChatUser getUserFromBackgroundNotification() {
        if (StringUtils.isValid(getIntent().getStringExtra("sender"))) {
            String recipientId = getIntent().getStringExtra("sender");
            Log.d(DEBUG_NOTIFICATION, "MessageListActivity.findUserByBackgroundPushRecicpientId:" +
                    " recipientId == " + recipientId);

            return ChatManager.getInstance().getContactsSynchronizer().findById(recipientId);
        } else {
            throw new ChatRuntimeException("Recipient can not be retrieved! " +
                    "Did you pass it correctly?");
        }
    }

    @Override
    protected void onResume() {
        super.onResume();

        // set the active conversation
        ChatManager.getInstance().getConversationsHandler()
                .setCurrentOpenConversationId(recipient.getId());
        Log.d(TAG, "MessageListActivity.onResume: " +
                "currentOpenConversationId == " + recipient.getId());

        // set the current conversation as read
        ChatManager.getInstance()
                .getConversationsHandler()
                .setConversationRead(recipient.getId());
    }

    @Override
    protected void onPause() {
        // unset the active conversation
        ChatManager.getInstance().getConversationsHandler()
                .setCurrentOpenConversationId(null);
        Log.d(TAG, "MessageListActivity.onResume: currentOpenConversationId detached");

        super.onPause();
    }

    @Override
    protected void onStop() {
        Log.d(TAG, "  MessageListActivity.onStop");

        // dismiss the emoji panel
        if (emojiPopup != null) {
            emojiPopup.dismiss();
        }

        super.onStop();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "  MessageListActivity.onDestroy");

        if (presenceHandler != null) {
            presenceHandler.removePresenceListener(this);
            Log.d(TAG, "MessageListActivity.onDestroy:" +
                    " presenceHandler detached");
        }

        if (groupsSyncronizer != null) {
            groupsSyncronizer.removeGroupsListener(this);
            Log.d(TAG, "MessageListActivity.onDestroy:" +
                    " groupsSyncronizer detached");
        }

        // unset the active conversation
        ChatManager.getInstance().getConversationsHandler()
                .setCurrentOpenConversationId(null);
        Log.d(TAG, "MessageListActivity.onResume: currentOpenConversationId detached");

        // detach the conversation messages listener
        conversationMessagesHandler.removeConversationMessagesListener(this);
    }

    private void registerViews() {
        Log.d(TAG, "registerViews");

        recyclerView = (RecyclerView) findViewById(R.id.main_activity_recycler_view);
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        mPictureView = (ImageView) findViewById(R.id.toolbar_picture);
        mTitleTextView = (TextView) findViewById(R.id.toolbar_title);
        mSubTitleTextView = (TextView) findViewById(R.id.toolbar_subtitle);

        mNoMessageLayout = (RelativeLayout) findViewById(R.id.no_messages_layout);

        editText = (EmojiEditText) findViewById(R.id.main_activity_chat_bottom_message_edittext);
        rootView = (ViewGroup) findViewById(R.id.main_activity_root_view);
        emojiButton = (ImageView) findViewById(R.id.main_activity_emoji);
        attachButton = (ImageView) findViewById(R.id.main_activity_attach);
        sendButton = (ImageView) findViewById(R.id.main_activity_send);
        recyclerView = (RecyclerView) findViewById(R.id.main_activity_recycler_view);
        mEmojiBar = (LinearLayout) findViewById(R.id.main_activity_emoji_bar);
    }

    private void initDirectToolbar(final IChatUser recipient) {
        // toolbar picture
        setPicture(recipient.getProfilePictureUrl(), R.drawable.ic_person_avatar);

        // toolbar recipient display name
        mTitleTextView.setText(recipient.getFullName());

        toolbar.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(MessageListActivity.this,
                        PublicProfileActivity.class);

                intent.putExtra(ChatUI.BUNDLE_RECIPIENT, recipient);
                startActivity(intent);
            }
        });
    }

    private void initGroupToolbar(final ChatGroup chatGroup) {
        // toolbar picture
        setPicture(chatGroup.getIconURL(), R.drawable.ic_group_avatar);

        // group name
        mTitleTextView.setText(chatGroup.getName());

        // toolbar group members
        String groupMembers;
        if (chatGroup != null && chatGroup.getMembersList() != null &&
                chatGroup.getMembersList().size() > 0) {
            groupMembers = chatGroup.printMembersListWithSeparator(", ");
        } else {
            // if there are no members show the logged user as "you"
            groupMembers = getString(R.string.activity_message_list_group_info_you_label);
        }
        mSubTitleTextView.setText(groupMembers);

        toolbar.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(MessageListActivity.this,
                        GroupAdminPanelActivity.class);
                intent.putExtra(ChatUI.BUNDLE_GROUP_ID, chatGroup.getGroupId());
                startActivity(intent);
            }
        });
    }

    private void setPicture(String pictureUrl, @DrawableRes int placeholder) {
        Glide.with(getApplicationContext())
                .load(StringUtils.isValid(pictureUrl) ? pictureUrl : "")
                .placeholder(placeholder)
                .bitmapTransform(new CropCircleTransformation(getApplicationContext()))
                .into(mPictureView);
    }

    private void initRecyclerView() {
        Log.d(TAG, "initRecyclerView");

        mLinearLayoutManager = new LinearLayoutManager(this);
        mLinearLayoutManager.setStackFromEnd(true);  // put adding from bottom
        recyclerView.setLayoutManager(mLinearLayoutManager);
        initRecyclerViewAdapter(recyclerView);
    }

    private void initRecyclerViewAdapter(RecyclerView recyclerView) {
        Log.d(TAG, "initRecyclerViewAdapter");

        Log.d(TAG, "conversationMessagesHandler.getMessages(): " +
                "size() is " + conversationMessagesHandler.getMessages().size());

        messageListAdapter = new MessageListAdapter(this,
                conversationMessagesHandler.getMessages());
        messageListAdapter.setMessageClickListener(this.onMessageClickListener);
        recyclerView.setAdapter(messageListAdapter);

        // scroll to last position
        if (messageListAdapter.getItemCount() > 0) {
            int position = messageListAdapter.getItemCount() - 1;
            mLinearLayoutManager.scrollToPositionWithOffset(position, 0);
        }
    }

    /**
     * Listener called when a message is clicked.
     */
    public OnMessageClickListener onMessageClickListener = new OnMessageClickListener() {
        @Override
        public void onMessageLinkClick(TextView messageView, ClickableSpan clickableSpan) {
            Log.d(TAG, "onMessageClickListener.onMessageLinkClick");
            Log.d(TAG, "text: " + messageView.getText().toString());

            if (ChatUI.getInstance().getOnMessageClickListener() != null) {
                ChatUI.getInstance().getOnMessageClickListener()
                        .onMessageLinkClick(messageView, clickableSpan);
            } else {
                Log.d(TAG, "Chat.Configuration.getMessageClickListener() == null");
            }
        }
    };

    private void initInputPanel() {
        Log.d(TAG, "initInputPanel");

        editText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
            }

            @Override
            public void afterTextChanged(Editable s) {
                // bugfix ssue #4
                if (editText.getText().toString() == null ||
                        editText.getText().toString().isEmpty() ||
                        // source : https://stackoverflow.com/questions/28040993/check-if-string-is-only-line-breaks
                        // This regular expression will match all the strings that
                        // contain one or more characters from the set of \n and \r.
                        editText.getText().toString().matches("[\\n\\r]+")) {
                    // not valid input - hides the send button
                    sendButton.setVisibility(View.GONE);
                    attachButton.setVisibility(View.VISIBLE);
                } else {
                    // valid input - shows the send button
                    sendButton.setVisibility(View.VISIBLE);
                    attachButton.setVisibility(View.GONE);
                }
            }
        });

        emojiButton.setColorFilter(ContextCompat
                .getColor(this, R.color.emoji_icons), PorterDuff.Mode.SRC_IN);
        attachButton.setColorFilter(ContextCompat
                .getColor(this, R.color.emoji_icons), PorterDuff.Mode.SRC_IN);
        sendButton.setColorFilter(ContextCompat
                .getColor(this, R.color.emoji_icons), PorterDuff.Mode.SRC_IN);

        emojiButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(final View v) {
                emojiPopup.toggle();
            }
        });
        attachButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(final View v) {
                Log.d(TAG, "MessageListActivity.onAttachClicked");

                if (ChatUI.getInstance().getOnAttachClickListener() != null) {
                    ChatUI.getInstance().getOnAttachClickListener().onAttachClicked(null);
                }

                showAttachBottomSheet();
            }
        });

        sendButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(final View v) {
                Log.d(TAG, "onSendClicked");

                String text = editText.getText().toString();

                if (!StringUtils.isValid(text)) {
//                    Toast.makeText(MessageListActivity.this,
//                            getString(R.string.cannot_send_empty_message),
//                            Toast.LENGTH_SHORT).show();
                    return;
                }

                ChatManager.getInstance().sendTextMessage(recipient.getId(), recipient.getFullName(),
                        text, channelType, null, new SendMessageListener() {
                            @Override
                            public void onBeforeMessageSent(Message message, ChatRuntimeException chatException) {
                                if (chatException == null) {
                                    // if the message exists update it, else add it
                                    Log.d(TAG, "sendTextMessage.onBeforeMessageSent.message.id: " + message.getId());
                                    Log.d(TAG, "sendTextMessage.onBeforeMessageSent.message.recipient: " + message.getRecipient());

                                    messageListAdapter.updateMessage(message);
                                    scrollToBottom();
                                } else {

                                    Toast.makeText(MessageListActivity.this,
                                            "Failed to send message",
                                            Toast.LENGTH_SHORT).show();

                                    Log.e(TAG, "sendTextMessage.onBeforeMessageSent: ", chatException);
                                }
                            }

                            @Override
                            public void onMessageSentComplete(Message message, ChatRuntimeException chatException) {
                                if (chatException == null) {

                                    Log.d(TAG, "message sent: " + message.toString());
                                } else {
                                    Toast.makeText(MessageListActivity.this,
                                            "Failed to send message",
                                            Toast.LENGTH_SHORT).show();
                                    Log.e(TAG, "error sending message : ", chatException);
                                }
                            }
                        });

                // clear the edittext
                editText.setText("");
            }
        });
        setUpEmojiPopup();

        if (channelType.equals(Message.GROUP_CHANNEL_TYPE)) {
            if (chatGroup != null && chatGroup.getMembersList().contains(ChatManager.getInstance().getLoggedUser())) {
                mEmojiBar.setVisibility(View.VISIBLE);
            } else {
                mEmojiBar.setVisibility(View.GONE);
            }
        }
    }

    @Override
    public void onConversationMessageReceived(Message message, ChatRuntimeException e) {
        Log.d(TAG, "onConversationMessageReceived");

        if (e == null) {
            messageListAdapter.updateMessage(message);
            scrollToBottom();
        } else {
            Log.w(TAG, "Error onConversationMessageReceived ", e);
        }
    }

    @Override
    public void onConversationMessageChanged(Message message, ChatRuntimeException e) {
        Log.d(TAG, "onConversationMessageChanged");

        if (e == null) {
            messageListAdapter.updateMessage(message);
            scrollToBottom();

        } else {
            Log.w(TAG, "Error onConversationMessageReceived ", e);
        }
    }

    private void scrollToBottom() {
        // scroll to last position
        if (messageListAdapter.getItemCount() > 0) {
            int position = messageListAdapter.getItemCount() - 1;
            mLinearLayoutManager.scrollToPositionWithOffset(position, 0);
        }
    }

    private void showAttachBottomSheet() {
        Log.d(TAG, "MessageListActivity.onAttachClicked");

        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        BottomSheetAttach dialog = BottomSheetAttach.newInstance(recipient, channelType);
        dialog.show(ft, BottomSheetAttach.class.getName());
    }
//
//
////    private void showFilePickerDialog() {
////        Log.d(TAG, "showFilePickerDialog");
////
////        // retrieve properties
////        DialogProperties properties = getDialogProperties();
////
////        // dialog
////        FilePickerDialog dialog = new FilePickerDialog(MessageListActivity.this, properties);
////        dialog.setTitle("Select a File");
////        dialog.setDialogSelectionListener(new DialogSelectionListener() {
////            @Override
////            public void onSelectedFilePaths(String[] files) {
////                //files is the array of the paths of files selected by the Application User.
////            }
////        });
////        dialog.show();
////    }
////
////    private DialogProperties getDialogProperties() {
////        Log.d(TAG, "getDialogProperties");
////
////        // properties
////        DialogProperties properties = new DialogProperties();
////        properties.selection_mode = DialogConfigs.SINGLE_MODE;
////        properties.selection_type = DialogConfigs.FILE_SELECT;
//////        properties.root = new File(DialogConfigs.DEFAULT_DIR);
////        properties.root = Environment.getExternalStorageDirectory();
////        properties.error_dir = new File(DialogConfigs.DEFAULT_DIR);
////        properties.offset = new File(DialogConfigs.DEFAULT_DIR);
////        properties.extensions = null;
////        return properties;
////    }


    @TargetApi(19)
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent
            data) {

        if (requestCode == _INTENT_ACTION_GET_PICTURE) {
            if (data != null && data.getData() != null && resultCode == RESULT_OK) {

                Uri uri = data.getData();

                // convert the stream to a file
                File fileToUpload = new File(StorageHandler.getFilePathFromUri(this, uri));
                showConfirmUploadDialog(fileToUpload);
            }
        } else {
            super.onActivityResult(requestCode, resultCode, data);
        }
    }

    // bugfix Issue #64
    private void showConfirmUploadDialog(
            final File file) {
        Log.d(TAG, "uploadFile");

        new AlertDialog.Builder(this)
                .setTitle(getString(R.string.activity_message_list_confirm_dialog_upload_title_label))
                .setMessage(getString(R.string.activity_message_list_confirm_dialog_upload_message_label))
                .setPositiveButton(getString(android.R.string.yes), new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        // upload the file
                        uploadFile(file);
                    }
                })
                .setNegativeButton(getString(android.R.string.no), new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        dialogInterface.dismiss(); // close the alert dialog
                    }
                }).show();
    }

    // bugfix Issue #15
    private void uploadFile(File file) {
        Log.d(TAG, "uploadFile");

        // bugfix Issue #45
        final ProgressDialog progressDialog = new ProgressDialog(MessageListActivity.this);
        progressDialog.setMessage(getString(R.string.activity_message_list_progress_dialog_upload));
        progressDialog.setCancelable(false);
        progressDialog.show();

        StorageHandler.uploadFile(this, file, new OnUploadedCallback() {
            @Override
            public void onUploadSuccess(final String uid, final Uri downloadUrl, final String type) {
                Log.d(TAG, "uploadFile.onUploadSuccess - downloadUrl: " + downloadUrl);

                progressDialog.dismiss(); // bugfix Issue #45

                Glide.with(getApplicationContext())
                        .load(downloadUrl)
                        .asBitmap()
                        .into(new SimpleTarget<Bitmap>() {
                            @Override
                            public void onResourceReady(Bitmap bitmap, GlideAnimation<? super Bitmap> glideAnimation) {
                                int width = bitmap.getWidth();
                                int height = bitmap.getHeight();

                                Log.d(TAG, " MessageListActivity.uploadFile:" +
                                        " width == " + width + " - height == " + height);

                                Map<String, Object> metadata = new HashMap<>();
                                metadata.put("width", width);
                                metadata.put("height", height);
                                metadata.put("src", downloadUrl.toString());
//                                metadata.put("uid", uid);
                                metadata.put("description", "");

                                Log.d(TAG, " MessageListActivity.uploadFile:" +
                                        " metadata == " + metadata);

                                // get the localized type
                                String lastMessageText = "";
                                if (type.toLowerCase().equals(StorageHandler.Type.Image.toString().toLowerCase())) {
                                    lastMessageText = getString(R.string.activity_message_list_type_image_label);
                                } else if (type.equals(StorageHandler.Type.File)) {
                                    lastMessageText = getString(R.string.activity_message_list_type_file_label);
                                }

                                // TODO: 13/02/18 add image message to the adapter  (like text message)
                                ChatManager.getInstance().sendImageMessage(recipient.getId(),
                                        recipient.getFullName(), lastMessageText + ": " + downloadUrl.toString(), channelType,
                                        metadata, null);
                            }
                        });
            }

            @Override
            public void onProgress(double progress) {
                Log.d(TAG, "uploadFile.onProgress - progress: " + progress);

                // bugfix Issue #45
                progressDialog.setProgress((int) progress);

                // TODO: 06/09/17 progress within viewholder
            }

            @Override
            public void onUploadFailed(Exception e) {
                Log.e(TAG, "uploadFile.onUploadFailed: " + e.getMessage());

                progressDialog.dismiss(); // bugfix Issue #45

                Toast.makeText(MessageListActivity.this,
                        getString(R.string.activity_message_list_progress_dialog_upload_failed),
                        Toast.LENGTH_SHORT).show();
            }
        });
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == android.R.id.home) {
            onBackPressed();
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    // bugfix Issue #4
    @Override
    public void onBackPressed() {
        Log.d(TAG, "onBackPressed");

        if (emojiPopup != null && emojiPopup.isShowing()) {
            emojiPopup.dismiss();
        } else {
            super.onBackPressed();
        }

//        else {
//            if (isFromBackgroundNotification || isFromForegroundNotification) {
//                goToParentActivity();
//            } else {
//                finish();
//            }
//        }
    }

//    // bugfix Issue #4
//    public void goToParentActivity() {
//        Log.d(TAG, "goToParentActivity");
//        Intent upIntent = getNotificationParentActivityIntent();
//        Log.d(TAG, "upIntent: " + upIntent.toString());
//
//        // This activity is NOT part of this app's task, so create a new task
//        // when navigating up, with a synthesized back stack.
//        TaskStackBuilder.create(this)
//                // Add all of this activity's parents to the back stack
//                .addNextIntentWithParentStack(upIntent)
//                // Navigate up to the closest parent
//                .startActivities();
//        finish();
//    }
//
//    // bugfix Issue #4
//    private Intent getNotificationParentActivityIntent() {
//        Intent intent = null;
//        try {
//            // targetClass MUST NOT BE NULL
//            // targetClass MUST NOT BE NULL
//            Class<?> targetClass = Class.forName(getString(R.string.target_notification_parent_activity));
//            intent = new Intent(this, targetClass);
//        } catch (ClassNotFoundException e) {
//            String errorMessage = "cannot retrieve notification target acticity class. " + e.getMessage();
//            Log.e(TAG, errorMessage);
//        }
//
//        return intent;
//    }

    private void setUpEmojiPopup() {
        emojiPopup = EmojiPopup.Builder.fromRootView(rootView)
                .setOnEmojiBackspaceClickListener(new OnEmojiBackspaceClickListener() {
                    @Override
                    public void onEmojiBackspaceClick(final View v) {
                        Log.d(TAG, "Clicked on Backspace");
                    }
                })
                .setOnEmojiClickListener(new OnEmojiClickListener() {
                    @Override
                    public void onEmojiClick(@NonNull final EmojiImageView imageView, @NonNull final Emoji emoji) {
                        Log.d(TAG, "Clicked on emoji");
                    }
                })
                .setOnEmojiPopupShownListener(new OnEmojiPopupShownListener() {
                    @Override
                    public void onEmojiPopupShown() {
                        emojiButton.setImageResource(R.drawable.ic_keyboard_24dp);
                    }
                })
                .setOnSoftKeyboardOpenListener(new OnSoftKeyboardOpenListener() {
                    @Override
                    public void onKeyboardOpen(@Px final int keyBoardHeight) {
                        Log.d(TAG, "Opened soft keyboard");
                    }
                })
//                .setOnEmojiPopupDismissListener(new OnEmojiPopupDismissListener() {
//                    @Override
//                    public void onEmojiPopupDismiss() {
//                        emojiButton.setImageResource(R.drawable.emoji_ios_category_people);
//                    }
//                })

                .setOnEmojiPopupDismissListener(new OnEmojiPopupDismissListener() {
                    @Override
                    public void onEmojiPopupDismiss() {
                        emojiButton.setImageResource(R.drawable.emoji_ios_category_people);
                    }
                })
                .setOnSoftKeyboardCloseListener(new OnSoftKeyboardCloseListener() {
                    @Override
                    public void onKeyboardClose() {
                        Log.d(TAG, "Closed soft keyboard");
                    }
                })
                .build(editText);
    }

    @Override
    public void isUserOnline(boolean isConnected) {
        Log.d(DEBUG_USER_PRESENCE, "MessageListActivity.isUserOnline: " +
                "isConnected == " + isConnected);

        if (isConnected) {
            conversWithOnline = true;
            mSubTitleTextView.setText(getString(R.string.activity_message_list_convers_with_presence_online));
        } else {
            conversWithOnline = false;

            if (conversWithLastOnline != PresenceHandler.LAST_ONLINE_UNDEFINED) {
                mSubTitleTextView.setText(TimeUtils.getFormattedTimestamp(this, conversWithLastOnline));
                Log.d(DEBUG_USER_PRESENCE, "MessageListActivity.isUserOnline: " +
                        "conversWithLastOnline == " + conversWithLastOnline);
            } else {
                mSubTitleTextView.setText(getString(R.string.activity_message_list_convers_with_presence_offline));
            }
        }
    }

    @Override
    public void userLastOnline(long lastOnline) {
        Log.d(DEBUG_USER_PRESENCE, "MessageListActivity.userLastOnline: " +
                "lastOnline == " + lastOnline);

        conversWithLastOnline = lastOnline;

        if (!conversWithOnline) {
            mSubTitleTextView.setText(TimeUtils.getFormattedTimestamp(this, lastOnline));
        }

        if (!conversWithOnline && lastOnline == PresenceHandler.LAST_ONLINE_UNDEFINED) {
            mSubTitleTextView.setText(getString(R.string.activity_message_list_convers_with_presence_offline));
        }
    }

    @Override
    public void onPresenceError(Exception e) {
        Log.e(DEBUG_USER_PRESENCE, "MessageListActivity.onMyPresenceError: " + e.toString());

        mSubTitleTextView.setText(getString(R.string.activity_message_list_convers_with_presence_offline));
    }

    @Override
    public void onGroupAdded(ChatGroup chatGroup, ChatRuntimeException e) {
        if (e == null) {
            this.chatGroup = chatGroup;
            initGroupToolbar(chatGroup);
            initInputPanel();
        } else {
            Log.e(TAG, "MessageListActivity.onGroupAdded: " + e.toString());
        }
    }

    @Override
    public void onGroupChanged(ChatGroup chatGroup, ChatRuntimeException e) {
        if (e == null) {
            this.chatGroup = chatGroup;
            initGroupToolbar(chatGroup);
            initInputPanel();
        } else {
            Log.e(TAG, "MessageListActivity.onGroupChanged: " + e.toString());
        }
    }

    @Override
    public void onGroupRemoved(ChatRuntimeException e) {
        Log.e(TAG, "MessageListActivity.onGroupRemoved: " + e.toString());
    }
}