// Copyright (c) 2017-2018, Tom Geiselmann
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software
// and associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY,WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

package com.none.tom.simplerssreader.activity;

import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.app.LoaderManager;
import android.content.Intent;
import android.content.Loader;
import android.content.res.Resources;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomNavigationView;
import android.support.design.widget.Snackbar;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.PopupMenu;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.TextView;

import com.none.tom.simplerssreader.R;
import com.none.tom.simplerssreader.feed.CurrentFeed;
import com.none.tom.simplerssreader.feed.SavedEntries;
import com.none.tom.simplerssreader.fragment.base.BaseFeedSubscriptionFragment;
import com.none.tom.simplerssreader.fragment.FeedSubscriptionEditFragment;
import com.none.tom.simplerssreader.fragment.FilterByCategoriesFragment;
import com.none.tom.simplerssreader.fragment.InitialSetupFragment;
import com.none.tom.simplerssreader.fragment.LoadCurrentFeedFragment;
import com.none.tom.simplerssreader.fragment.FeedSubscriptionFragment;
import com.none.tom.simplerssreader.fragment.SavedEntriesDeleteEntriesFragment;
import com.none.tom.simplerssreader.fragment.SavedEntriesFragment;
import com.none.tom.simplerssreader.fragment.CurrentFeedFragment;
import com.none.tom.simplerssreader.fragment.SavedEntriesSavePasswordFragment;
import com.none.tom.simplerssreader.fragment.UnsubscribeFromFeedsFragment;
import com.none.tom.simplerssreader.fragment.FeedSubscriptionsFragment;
import com.none.tom.simplerssreader.loader.IsFeedUpdateAvailableLoader;
import com.none.tom.simplerssreader.loader.OPMLImportLoader;
import com.none.tom.simplerssreader.loader.SavedEntriesSaveLoader;
import com.none.tom.simplerssreader.opml.OPMLUtils;
import com.none.tom.simplerssreader.opml.Outline;
import com.none.tom.simplerssreader.utils.ApplicationUtils;
import com.none.tom.simplerssreader.utils.FontUtils;
import com.none.tom.simplerssreader.view.Toast;
import com.none.tom.simplerssreader.utils.ErrorHandler;
import com.none.tom.simplerssreader.utils.SearchResultsCursor;
import com.none.tom.simplerssreader.utils.SharedPrefUtils;
import com.none.tom.simplerssreader.utils.SoftInputUtils;
import com.none.tom.simplerssreader.utils.ThemeUtils;
import com.none.tom.simplerssreader.utils.TypedValueUtils;
import com.none.tom.simplerssreader.view.HistoryAwareBottomNavigationView;
import com.rometools.rome.feed.synd.SyndEnclosure;
import com.rometools.rome.feed.synd.SyndEntry;

import org.joda.time.LocalDateTime;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import static com.none.tom.simplerssreader.utils.Constants.*;

public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks {
    private static final String KEY_FRAGMENT_TAG = "key_fragment_tag";
    private static final String KEY_OPML_IMPORT = "key_opml_import";
    private static final String KEY_ENTRY_URLS = "key_entry_urls";
    private static final String KEY_ENTRY_TITLES = "key_entry_titles";

    private boolean mBackStackEntryPopped;
    private boolean mFeedSubscriptionsChanged;
    private boolean mLoadNewCurrentFeed;
    private boolean mFeedSubscriptionsRemoved;
    private boolean mIsCategoriesFilterApplied;

    private int[] mActionBarInsets;

    private List<Integer> mSelectedRecyclerViewPositions;

    private SearchResultsCursor mSearchResultsCursor;

    private HistoryAwareBottomNavigationView mBottomNavigationView;
    private android.view.ActionMode mActionMode;

    private CurrentFeedFragment mCurrentFeedFragment;
    private FeedSubscriptionsFragment mFeedSubscriptionsFragment;
    private SavedEntriesFragment mSavedEntriesFragment;
    private InitialSetupFragment mInitialSetupFragment;
    private LoadCurrentFeedFragment mLoadCurrentFeedFragment;

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

        getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,
                WindowManager.LayoutParams.FLAG_SECURE);

        ThemeUtils.setCurrentTheme(this);

        setContentView(R.layout.activity_main);

        mBottomNavigationView = findViewById(R.id.BottomNavigationView);
        mBottomNavigationView.setOnNavigationItemSelectedListener(
                new BottomNavigationView.OnNavigationItemSelectedListener() {
                    @Override
                    public boolean onNavigationItemSelected(@NonNull final MenuItem item) {
                        if (mActionMode != null) {
                            mActionMode.finish();
                        }

                        if (isSearchViewExpanded()) {
                            hideSearchView();
                        }

                        getCurrentFeedFragment().finishLayoutRefreshing();

                        if (mBackStackEntryPopped) {
                            return true;
                        }

                        switch (item.getItemId()) {
                            case R.id.action_view_current_feed:
                                if (isCurrentFeedLoadingOrLoadingFailed()) {
                                    replaceFragment(getLoadCurrentFeedFragment(), true);
                                } else {
                                    replaceFragment(getCurrentFeedFragment(), true);
                                }
                                break;
                            case R.id.action_view_feed_subscriptions:
                                replaceFragment(getFeedSubscriptionsFragment(), true);
                                break;
                            case R.id.action_view_saved_entries:
                                replaceFragment(getSavedEntriesFragment(), true);
                                break;
                            default:
                                return false;
                        }

                        return true;
                    }
                });

        mBottomNavigationView.setOnNavigationItemReselectedListener(
                new BottomNavigationView.OnNavigationItemReselectedListener() {
            @Override
            public void onNavigationItemReselected(@NonNull final MenuItem item) {
                switch (item.getItemId()) {
                    case R.id.action_view_current_feed:
                        if (getCurrentFeedFragment().isVisible()) {
                            getCurrentFeedFragment().scrollTo(0);
                        }
                        break;
                    case R.id.action_view_feed_subscriptions:
                        if (getFeedSubscriptionsFragment().isVisible()) {
                            getFeedSubscriptionsFragment().scrollToTop();
                        }
                        break;
                    case R.id.action_view_saved_entries:
                        if (getSavedEntriesFragment().isVisible()) {
                            getSavedEntriesFragment().scrollToTop();
                        }
                        break;
                    default:
                        break;
                }
            }
        });

        final Intent intent = getIntent();
        final String feedUrl = intent.getDataString();

        if (!TextUtils.isEmpty(feedUrl)) {
           newFeedSubscriptionIntentReceived(feedUrl, true);
        } else if (savedInstanceState == null) {
            loadCurrentFeedOrShowInitialSetup();
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();

        if (isFinishing()) {
            ApplicationUtils.setFeedLoadingFailed(false);
        }
    }

    @Override
    public void onBackPressed() {
        if (isSearchViewExpanded()) {
            hideSearchView();
        } else {
            final FragmentManager fm = getFragmentManager();
            mBackStackEntryPopped = fm.popBackStackImmediate();
            final int entryCnt = fm.getBackStackEntryCount();

            if (entryCnt > 0) {
                final FragmentManager.BackStackEntry entry = fm.getBackStackEntryAt(entryCnt - 1);
                final Fragment fragment = fm.findFragmentByTag(entry.getName());

                if (fragment instanceof CurrentFeedFragment) {
                    mBottomNavigationView.setSelectedItemId(R.id.action_view_current_feed);
                } else if (fragment instanceof FeedSubscriptionsFragment) {
                    mBottomNavigationView.setSelectedItemId(R.id.action_view_feed_subscriptions);
                } else if (fragment instanceof SavedEntriesFragment) {
                    mBottomNavigationView.setSelectedItemId(R.id.action_view_saved_entries);
                } else {
                    mBackStackEntryPopped = fm.popBackStackImmediate();
                    mBottomNavigationView.setSelectedItemId(R.id.action_view_feed_subscriptions);
                }

                mBackStackEntryPopped = false;
            } else {
                super.onBackPressed();
            }
        }
    }


    @Override
    protected void onNewIntent(final Intent intent) {
        super.onNewIntent(intent);

        setIntent(intent);

        final String feedUrl = intent.getDataString();

        if (!TextUtils.isEmpty(feedUrl)) {
            newFeedSubscriptionIntentReceived(feedUrl, false);
        }
    }

    @Override
    public void onSaveInstanceState(final Bundle outState) {
        super.onSaveInstanceState(outState);

        final FragmentManager fm = getFragmentManager();

        if (fm.findFragmentByTag(CurrentFeedFragment.TAG) != null) {
            outState.putString(KEY_FRAGMENT_TAG, CurrentFeedFragment.TAG);
        } else if (fm.findFragmentByTag(FeedSubscriptionsFragment.TAG) != null) {
            outState.putString(KEY_FRAGMENT_TAG, FeedSubscriptionsFragment.TAG);
        } else if (fm.findFragmentByTag(SavedEntriesFragment.TAG) != null) {
            outState.putString(KEY_FRAGMENT_TAG, SavedEntriesFragment.TAG);
        } else if (fm.findFragmentByTag(InitialSetupFragment.TAG) != null) {
            outState.putString(KEY_FRAGMENT_TAG, InitialSetupFragment.TAG);
        } else if (fm.findFragmentByTag(LoadCurrentFeedFragment.TAG) != null) {
            outState.putString(KEY_FRAGMENT_TAG, LoadCurrentFeedFragment.TAG);
        }

        if (mActionMode != null) {
            mActionMode.finish();
        }
    }

    @Override
    public void onRestoreInstanceState(final Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);

        final String fragmentTag = savedInstanceState.getString(KEY_FRAGMENT_TAG);

        if (!TextUtils.isEmpty(fragmentTag) && fragmentTag.equals(InitialSetupFragment.TAG)) {
            mBottomNavigationView.setVisibility(View.GONE);
        }
    }

    @Override
    protected void onActivityResult(final int requestCode, final int resultCode,
                                    final Intent resultData) {
        super.onActivityResult(requestCode, resultCode, resultData);

        if (resultCode == RESULT_OK) {
            if (requestCode == REQUEST_CODE_SELECT_OPML_FILE) {
                performOPMLImport(resultData.getData());
            } else if (requestCode == REQUEST_CODE_CREATE_ALTER_OPML_FILE) {
                performOPMLExport(resultData.getData());
            } else if (requestCode == REQUEST_CODE_OPEN_SETTINGS &&
                    (resultData.getBooleanExtra(INTENT_EXTRA_THEME_CHANGED, false) ||
                            resultData.getBooleanExtra(INTENT_EXTRA_FONT_SIZE_CHANGED, false))) {
                recreate();
            }
        } else if (requestCode == REQUEST_CODE_SELECT_OPML_FILE && isNotInInitialSetup()) {
            BaseFeedSubscriptionFragment.getInstance().show(getSupportFragmentManager(),
                    BaseFeedSubscriptionFragment.TAG);
        }
    }

    @Override
    public boolean onCreateOptionsMenu(final Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main_action_bar, menu);

        return true;
    }

    @Override
    public boolean onPrepareOptionsMenu(final Menu menu) {
        final MenuItem itemUpdate = menu.findItem(R.id.action_update);
        final MenuItem itemSortEntries = menu.findItem(R.id.action_sort_entries);
        final MenuItem itemExportAsOPML = menu.findItem(R.id.action_opml_export);
        final MenuItem itemFilter = menu.findItem(R.id.action_filter_by_categories);
        final MenuItem itemSearch = menu.findItem(R.id.action_search);
        final MenuItem itemSettings = menu.findItem(R.id.action_settings);
        final MenuItem itemFilterSubs = menu.findItem(R.id.action_filter_subscriptions_by_category);

        final boolean isSearchViewNotExpanded = !isSearchViewExpanded();

        if (isNotInInitialSetup()) {
            if (getLoadCurrentFeedFragment().isAdded()) {
                toggleMenuItemVisibility(itemSearch, false);
                toggleMenuItemVisibility(itemSortEntries, false);
                toggleMenuItemVisibility(itemFilterSubs, false);
                toggleMenuItemVisibility(itemExportAsOPML, false);
            } else if (getCurrentFeedFragment().isAdded()) {
                toggleMenuItemVisibility(itemSortEntries, false);
                toggleMenuItemVisibility(itemFilterSubs, false);
                toggleMenuItemVisibility(itemExportAsOPML, false);

                if (isSearchViewNotExpanded) {
                    toggleMenuItemVisibility(itemUpdate, true);
                    toggleMenuItemVisibility(itemSearch, true);
                }

                if (CurrentFeed.isRSSFeed() && CurrentFeed.isCategoriesAvailable() &&
                        isSearchViewNotExpanded) {
                    toggleMenuItemVisibility(itemFilter, true);
                }
            } else if (getFeedSubscriptionsFragment().isAdded()) {
                toggleMenuItemVisibility(itemUpdate, false);
                toggleMenuItemVisibility(itemSortEntries, false);
                toggleMenuItemVisibility(itemFilter, false);

                if (isSearchViewNotExpanded) {
                    toggleMenuItemVisibility(itemFilterSubs, true);
                    toggleMenuItemVisibility(itemExportAsOPML, true);
                    toggleMenuItemVisibility(itemSearch, true);
                }
            } else if (getSavedEntriesFragment().isAdded()) {
                toggleMenuItemVisibility(itemUpdate, false);
                toggleMenuItemVisibility(itemFilter, false);
                toggleMenuItemVisibility(itemFilterSubs, false);
                toggleMenuItemVisibility(itemExportAsOPML, false);

                if (isSearchViewNotExpanded) {
                    toggleMenuItemVisibility(itemSortEntries, true);
                    toggleMenuItemVisibility(itemSearch, true);
                }

                final MenuItem itemSortOrderAsc =
                        menu.findItem(R.id.action_sort_order_ascending);
                final MenuItem itemSortOrderDesc =
                        menu.findItem(R.id.action_sort_order_descending);

                if (getSavedEntriesFragment().getSortOrder() == SORT_ORDER_DESCENDING) {
                    itemSortOrderDesc.setEnabled(false);

                    if (!itemSortOrderAsc.isVisible()) {
                        itemSortOrderAsc.setVisible(true);
                    }
                } else {
                    itemSortOrderAsc.setEnabled(false);

                    if (!itemSortOrderDesc.isVisible()) {
                        itemSortOrderDesc.setVisible(true);
                    }
                }
            }

            if (isSearchViewNotExpanded) {
                toggleMenuItemVisibility(itemSettings, true);
            }
        }

        return true;
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean onOptionsItemSelected(final MenuItem item) {
        switch (item.getItemId()) {
            case R.id.action_search:
                showSearchView();
                return true;
            case R.id.action_update:
                getCurrentFeedFragment().checkForCurrentFeedUpdate();
                return true;
            case R.id.action_filter_by_categories:
                showFilterByCategoriesFragment();
                return true;
            case R.id.action_filter_subscriptions_by_category:
                showCategoriesPopupMenu(findViewById(R.id.action_filter_subscriptions_by_category));
                return true;
            case R.id.action_sort_order_ascending:
                getSavedEntriesFragment().changeSortOrder(SORT_ORDER_ASCENDING);
                invalidateOptionsMenu();
                return true;
            case R.id.action_sort_order_descending:
                getSavedEntriesFragment().changeSortOrder(SORT_ORDER_DESCENDING);
                invalidateOptionsMenu();
                return true;
            case R.id.action_opml_export:
                startActivityWithAction(Intent.ACTION_CREATE_DOCUMENT);
                return true;
            case R.id.action_settings:
                startActivityForResult(new Intent(this, SettingsActivity.class),
                        REQUEST_CODE_OPEN_SETTINGS);
                return true;
            case android.R.id.home:
                onBackPressed();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    @Override
    public Loader onCreateLoader(final int id, final Bundle args) {
        switch (id) {
            case IsFeedUpdateAvailableLoader.ID:
                return new IsFeedUpdateAvailableLoader(this);
            case OPMLImportLoader.ID:
                return new OPMLImportLoader(this,
                        Uri.parse(args.getString(KEY_OPML_IMPORT)));
            case SavedEntriesSaveLoader.ID:
                return new SavedEntriesSaveLoader(this,
                        args.getStringArrayList(KEY_ENTRY_URLS),
                        args.getStringArrayList(KEY_ENTRY_TITLES));
            default:
                return null;
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public void onLoadFinished(final Loader loader, final Object data) {
        final int id = loader.getId();

        switch (id) {
            case IsFeedUpdateAvailableLoader.ID:
                onFeedUpdateResult((String) data);
                break;
            case OPMLImportLoader.ID:
                onOPMLImportResult((List<Outline>) data);
                break;
            case SavedEntriesSaveLoader.ID:
                Toast.info(this, getString(R.string.toast_entry_save_succeeded));
                break;
            default:
                break;
        }

        getLoaderManager().destroyLoader(id);
    }

    @Override
    public void onLoaderReset(final Loader loader) {}

    private void onFeedUpdateResult(final String newId) {
        getCurrentFeedFragment().currentFeedUpdateCheckFinished();

        final int errno = ErrorHandler.getErrno();

        if (errno < 0) {
            Toast.error(this, ErrorHandler.resolveErrorMessage(this, errno));
        } else {
            final int position = SharedPrefUtils.getCurrentFeedAdapterPosition(this);
            SharedPrefUtils.updateFeedIdAt(this, position, newId);

            getCurrentFeedFragment().scrollToTop();
        }
    }

    private void onOPMLImportResult(final List<Outline> outlines) {
        final int errno = ErrorHandler.getErrno();

        if (errno < 0) {
            Toast.error(this, ErrorHandler.resolveErrorMessage(this, errno));
        } else {
            Toast.info(this, getString(R.string.toast_opml_import_succeeded));

            if (isNotInInitialSetup()) {
                SharedPrefUtils.putOutlines(this, outlines);
                getFeedSubscriptionsFragment().feedSubscriptionsChanged();
            } else {
                SharedPrefUtils.putOutlines(this, outlines);

                removeFragment(getInitialSetupFragment(), false, true);

                mBottomNavigationView.setVisibility(View.VISIBLE);
                toggleActionBarVisibility(true);

                if (mFeedSubscriptionsRemoved) {
                    mFeedSubscriptionsRemoved = false;
                } else {
                    bottomNavigationViewSelectItemId(R.id.action_view_current_feed, true);
                }

                loadCurrentFeed(true);
            }
        }
    }

    public void addFeedSubscription(final List<String> metaData) {
        final int position = SharedPrefUtils.putFeedMetaData(this, metaData);

        if (getFeedSubscriptionsFragment().isAdded()) {
            getFeedSubscriptionsFragment().feedSubscriptionsChanged(position);

            Toast.info(this, getString(R.string.activity_main_feed_subscription_added));
        }

        if (getInitialSetupFragment().isAdded()) {
            removeFragment(getInitialSetupFragment(), false, false);

            bottomNavigationViewSelectItemId(R.id.action_view_current_feed, true);
            mBottomNavigationView.setVisibility(View.VISIBLE);

            toggleActionBarVisibility(true);

            if (ApplicationUtils.hasFeedLoadingFailed()) {
                ApplicationUtils.setFeedLoadingFailed(false);
            }

            loadCurrentFeed(false);
        }
    }

    private void addFragment(final Fragment fragment, final boolean addToBackStack,
                             final boolean allowStateLoss) {
        final FragmentManager fm = getFragmentManager();

        final FragmentTransaction transaction = fm.beginTransaction();

        final String tag;

        if (fragment instanceof CurrentFeedFragment) {
            tag = CurrentFeedFragment.TAG;
        } else if (fragment instanceof FeedSubscriptionsFragment) {
            tag = FeedSubscriptionsFragment.TAG;
        } else if (fragment instanceof SavedEntriesFragment) {
            tag = SavedEntriesFragment.TAG;
        } else if (fragment instanceof InitialSetupFragment) {
            tag = InitialSetupFragment.TAG;
        } else {
            tag = LoadCurrentFeedFragment.TAG;
        }

        transaction.add(R.id.FragmentContainer, fragment, tag);

        if (addToBackStack) {
            transaction.addToBackStack(tag);
        }

        if (allowStateLoss) {
            transaction.commitAllowingStateLoss();
        } else {
            transaction.commit();
        }
        fm.executePendingTransactions();
    }

    private void alterMenuItemAlpha(final MenuItem item, final boolean enable) {
        if (enable) {
            if (!item.isEnabled()) {
                item.setEnabled(true);
                item.getIcon().setAlpha(ICON_ALPHA_NORMAL);
            }
        } else if (item.isEnabled()) {
            item.setEnabled(false);
            item.getIcon().setAlpha(ICON_ALPHA_LOW);
        }
    }

    private void bottomNavigationViewSelectItemId(final int id, final boolean noAction) {
        if (mBottomNavigationView.getSelectedItemId() != id) {
            if (!noAction) {
                mBottomNavigationView.setSelectedItemId(id);
            } else {
                mBottomNavigationView.setSelectedItemIdNoAction(id);
            }
        }
    }

    public void bottomNavigationViewSelectPreviousItemId() {
        mBottomNavigationView.setPreviousSelectedItemId();
    }

    public void currentFeedLoaded() {
        if (getLoadCurrentFeedFragment().isAdded()) {
            removeFragment(getLoadCurrentFeedFragment(), false, true);
            addFragment(getCurrentFeedFragment(), true, true);
        }

        final int position = SharedPrefUtils.getCurrentFeedAdapterPosition(this);

        final List<SyndEntry> entries = CurrentFeed.get().getEntries();

        if (!entries.isEmpty()) {
            SharedPrefUtils.updateFeedIdAt(this, position, entries.get(0).getUri());
        }
    }

    private String getActionModeQuantityString(final int quantity) {
        final Resources res = getResources();

        if (getCurrentFeedFragment().isAdded()) {
            return res.getQuantityString(R.plurals.action_mode_current_feed, quantity);
        } else if (getFeedSubscriptionsFragment().isAdded()) {
            return res.getQuantityString(R.plurals.action_mode_feed_subscriptions, quantity);
        }

        return res.getQuantityString(R.plurals.action_mode_saved_entries, quantity);
    }

    private CurrentFeedFragment getCurrentFeedFragment() {
        if (mCurrentFeedFragment == null) {
            final Fragment fragment = getFragmentManager()
                    .findFragmentByTag(CurrentFeedFragment.TAG);

            if (fragment != null) {
                mCurrentFeedFragment = (CurrentFeedFragment) fragment;
            } else {
                mCurrentFeedFragment = new CurrentFeedFragment();
            }
        }

        return mCurrentFeedFragment;
    }

    private FeedSubscriptionsFragment getFeedSubscriptionsFragment() {
        if (mFeedSubscriptionsFragment == null) {
            final Fragment fragment = getFragmentManager()
                    .findFragmentByTag(FeedSubscriptionsFragment.TAG);

            if (fragment != null) {
                mFeedSubscriptionsFragment = (FeedSubscriptionsFragment) fragment;
            } else {
                mFeedSubscriptionsFragment = new FeedSubscriptionsFragment();
            }
        }

        return mFeedSubscriptionsFragment;
    }

    private InitialSetupFragment getInitialSetupFragment() {
        if (mInitialSetupFragment == null) {
            final Fragment fragment = getFragmentManager()
                    .findFragmentByTag(InitialSetupFragment.TAG);

            if (fragment != null) {
                mInitialSetupFragment = (InitialSetupFragment) fragment;
            } else {
                mInitialSetupFragment = new InitialSetupFragment();
            }
        }

        return mInitialSetupFragment;
    }

    private LoadCurrentFeedFragment getLoadCurrentFeedFragment() {
        if (mLoadCurrentFeedFragment == null) {
            final Fragment fragment = getFragmentManager()
                    .findFragmentByTag(LoadCurrentFeedFragment.TAG);

            if (fragment != null) {
                mLoadCurrentFeedFragment = (LoadCurrentFeedFragment) fragment;
            } else {
                mLoadCurrentFeedFragment = new LoadCurrentFeedFragment();
            }
        }

        return mLoadCurrentFeedFragment;
    }

    public SavedEntriesFragment getSavedEntriesFragment() {
        if (mSavedEntriesFragment == null) {
            final Fragment fragment = getFragmentManager()
                    .findFragmentByTag(SavedEntriesFragment.TAG);

            if (fragment != null) {
                mSavedEntriesFragment = (SavedEntriesFragment) fragment;
            } else {
                mSavedEntriesFragment = new SavedEntriesFragment();
            }
        }

        return mSavedEntriesFragment;
    }

    @SuppressWarnings("BooleanMethodIsAlwaysInverted")
    public boolean isCategoriesFilterApplied() {
        return mIsCategoriesFilterApplied;
    }

    private boolean isCurrentFeedLoadingOrLoadingFailed() {
        if (mLoadNewCurrentFeed) {
            mLoadNewCurrentFeed = false;
            return true;
        }
        return getLoadCurrentFeedFragment().isFeedLoading() ||
                ApplicationUtils.hasFeedLoadingFailed();
    }

    private boolean isNotInInitialSetup() {
        return !TextUtils.isEmpty(SharedPrefUtils.getCurrentFeedUrl(this));
    }

    public boolean isRecyclerViewItemSelected(final int position) {
        return mSelectedRecyclerViewPositions != null &&
                mSelectedRecyclerViewPositions.contains(position);
    }

    private void loadCurrentFeed(final boolean allowStateLoss) {
        if (getFeedSubscriptionsFragment().isAdded()) {
            replaceFragment(getLoadCurrentFeedFragment(), true);
        }

        addFragment(getLoadCurrentFeedFragment(), false, allowStateLoss);
    }

    private void loadCurrentFeedOrShowInitialSetup() {
        if (isNotInInitialSetup()) {
            loadCurrentFeed(false);
        } else {
            mBottomNavigationView.setVisibility(View.GONE);
            addFragment(getInitialSetupFragment(), false, false);
        }
    }

    private void migrateCurrentFeedToPosition(final int position) {
        final LoadCurrentFeedFragment loadCurrentFeedFragment = getLoadCurrentFeedFragment();

        loadCurrentFeedFragment.cancelFeedLoading();
        loadCurrentFeedFragment.setLastViewedAdapterPosition(position);

        SharedPrefUtils.putCurrentFeedAdapterPosition(this, position);

        mFeedSubscriptionsChanged = false;
        mLoadNewCurrentFeed = true;
    }

    private void newFeedSubscriptionIntentReceived(final String feedUrl,
                                                   final boolean coldLaunch) {
        if (isNotInInitialSetup()) {
            if (coldLaunch) {
                ApplicationUtils.setFeedLoadingFailed(true);
                mBottomNavigationView.setSelectedItemId(R.id.action_view_feed_subscriptions);
            } else {
                bottomNavigationViewSelectItemId(R.id.action_view_feed_subscriptions, false);

                final FeedSubscriptionFragment feedSubscriptionFragment =
                        FeedSubscriptionFragment.getInstance(feedUrl);

                if (feedSubscriptionFragment.isAdded()) {
                    feedSubscriptionFragment.dismiss();
                }
            }
        } else {
            addFragment(getInitialSetupFragment(), false, false);
            mBottomNavigationView.setVisibility(View.GONE);
        }

        FeedSubscriptionFragment.getInstance(feedUrl).show(getFragmentManager(),
                FeedSubscriptionFragment.TAG);
    }

    private void performEntrySave() {
        if (!TextUtils.isEmpty(SharedPrefUtils.getString(MainActivity.this,
                KEY_HASHED_PASSWORD))) {
            final int size = mSelectedRecyclerViewPositions.size();

            final ArrayList<String> entryUrls = new ArrayList<>(size);
            final ArrayList<String> entryTitles = new ArrayList<>(size);

            final List<SyndEntry> entries =
                    CurrentFeed.get().getEntries();

            for (final Integer position : mSelectedRecyclerViewPositions) {
                final SyndEntry entry = entries.get(position - 1);

                entryUrls.add(entry.getLink());
                entryTitles.add(entry.getTitle());
            }

            SavedEntriesSavePasswordFragment
                    .getInstance(entryUrls, entryTitles)
                    .show(getFragmentManager(),
                            SavedEntriesSavePasswordFragment.TAG);
        } else {
            Toast.info(MainActivity.this,
                    getString(R.string.toast_entry_save_no_password_set));
        }
    }

    private void performOPMLImport(final Uri uri) {
        final Bundle args = new Bundle();
        args.putString(KEY_OPML_IMPORT, uri.toString());

        getLoaderManager().restartLoader(OPMLImportLoader.ID, args, this);
    }

    private void performOPMLExport(final Uri uri) {
        try {
            OPMLUtils.performExport(this, uri);

            Toast.info(this, getString(R.string.toast_opml_export_succeeded));
        } catch (final IOException e) {
            if (e instanceof FileNotFoundException) {
                ErrorHandler.setErrno(ErrorHandler.ERROR_FILE_NOT_FOUND);
            } else {
                ErrorHandler.setErrno(ErrorHandler.ERROR_IO);
            }
            Toast.error(this, ErrorHandler.resolveErrorMessage(this, ErrorHandler.getErrno()));
        }
    }

    private void recyclerViewScrollTo(final int position, final List<Integer> highlight) {
        if (getCurrentFeedFragment().isAdded()) {
            if (highlight != null) {
                getCurrentFeedFragment().highlightVisibleSearchResults(highlight);
            }
            getCurrentFeedFragment().scrollTo(position);
        } else if (getFeedSubscriptionsFragment().isAdded()) {
            if (highlight != null) {
                getFeedSubscriptionsFragment().highlightVisibleSearchResults(highlight);
            }
            getFeedSubscriptionsFragment().scrollTo(position);
        } else {
            if (highlight != null) {
                getSavedEntriesFragment().highlightVisibleSearchResults(highlight);
            }
            getSavedEntriesFragment().scrollTo(position);
        }
    }

    @SuppressWarnings("SameParameterValue")
    private void removeFragment(final Fragment fragment, final boolean addToBackStack,
                                final boolean allowStateLoss) {
        final FragmentManager fm = getFragmentManager();

        final FragmentTransaction transaction = fm.beginTransaction();

        final String tag;

        if (fragment instanceof CurrentFeedFragment) {
            tag = CurrentFeedFragment.TAG;
        } else if (fragment instanceof FeedSubscriptionsFragment) {
            tag = FeedSubscriptionsFragment.TAG;
        } else if (fragment instanceof SavedEntriesFragment) {
            tag = SavedEntriesFragment.TAG;
        } else if (fragment instanceof InitialSetupFragment) {
            tag = InitialSetupFragment.TAG;
        } else {
            tag = LoadCurrentFeedFragment.TAG;
        }

        transaction.remove(fragment);

        if (addToBackStack) {
            transaction.addToBackStack(tag);
        }

        if (allowStateLoss) {
            transaction.commitAllowingStateLoss();
        } else {
            transaction.commit();
        }
        fm.executePendingTransactions();
    }

    private void replaceFragment(final Fragment fragment, final boolean addToBackStack) {
        final FragmentManager fm = getFragmentManager();

        final FragmentTransaction transaction = fm.beginTransaction();

        final String tag;

        if (fragment instanceof CurrentFeedFragment) {
            tag = CurrentFeedFragment.TAG;
        } else if (fragment instanceof FeedSubscriptionsFragment) {
            tag = FeedSubscriptionsFragment.TAG;
        } else if (fragment instanceof SavedEntriesFragment) {
            tag = SavedEntriesFragment.TAG;
        } else if (fragment instanceof InitialSetupFragment) {
            tag = InitialSetupFragment.TAG;
        } else {
            tag = LoadCurrentFeedFragment.TAG;
        }

        transaction.replace(R.id.FragmentContainer, fragment, tag);

        if (addToBackStack) {
            transaction.addToBackStack(tag);
        }

        transaction.commit();
        fm.executePendingTransactions();
    }

    private <T> void resetCardViewBackground(final T positions, final Class<T> clazz) {
        if (getCurrentFeedFragment().isAdded()) {
            getCurrentFeedFragment().resetCardViewBackground(positions, clazz);
        } else if (getFeedSubscriptionsFragment().isAdded()) {
            getFeedSubscriptionsFragment().resetCardViewBackground(positions, clazz);
        } else {
            getSavedEntriesFragment().resetCardViewBackground(positions, clazz);
        }
    }

    @SuppressWarnings("ConstantConditions")
    private void setActionBarColor(final int colorId) {
        getSupportActionBar().setBackgroundDrawable(new ColorDrawable(getColor(colorId)));
    }

    private void setStatusBarColor(final int colorId) {
        getWindow().setStatusBarColor(getColor(colorId));
    }

    private void showCategoriesPopupMenu(final View view) {
        final String allCategories = getString(R.string.all_categories);

        final PopupMenu popupMenu =
                new PopupMenu(this, view, Gravity.NO_GRAVITY, R.attr.actionOverflowMenuStyle, 0);

        popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(final MenuItem item) {
                final String title = String.valueOf(item.getTitle());

                getFeedSubscriptionsFragment().changeSelectedCategory(title);

                return true;
            }
        });

        final Menu menu = popupMenu.getMenu();

        menu.add(allCategories);

        final Set<String> categories = SharedPrefUtils.getFeedMetaDataCategories(this);

        for (final String category : categories) {
            menu.add(category);
        }

        popupMenu.setGravity(Gravity.TOP);
        popupMenu.show();
    }

    public void showFeedSubscriptionBaseFragment() {
        if (isNotInInitialSetup()) {
            BaseFeedSubscriptionFragment.getInstance().show(getSupportFragmentManager(),
                    BaseFeedSubscriptionFragment.TAG);
        }
    }

    private void showFilterByCategoriesFragment() {
        FilterByCategoriesFragment.getInstance(CurrentFeed.getCategories())
                .show(getFragmentManager(), FilterByCategoriesFragment.TAG);
    }

    public void showSelectedFeed(final int position) {
        final int lastViewedPosition = SharedPrefUtils.getCurrentFeedAdapterPosition(this);

        if (mFeedSubscriptionsChanged || lastViewedPosition != position) {
            migrateCurrentFeedToPosition(position);
        }

        bottomNavigationViewSelectItemId(R.id.action_view_current_feed, false);

        invalidateOptionsMenu();
    }

    public void startActivityWithAction(final String intentAction) {
        final Intent intent = new Intent(intentAction);

        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("text/xml");

        if (intentAction.equals(Intent.ACTION_OPEN_DOCUMENT)) {
            startActivityForResult(intent, REQUEST_CODE_SELECT_OPML_FILE);
        } else if (intentAction.equals(Intent.ACTION_CREATE_DOCUMENT)) {
            final LocalDateTime dateTime = new LocalDateTime();

            final String OPMLExportTitle = String.format("%s-%s:%s:%s:%s_%s.%s.%s",
                    TAG.toLowerCase(),
                    dateTime.getHourOfDay(), dateTime.getMinuteOfHour(),
                    dateTime.getSecondOfMinute(), dateTime.getMillisOfSecond(),
                    dateTime.getDayOfMonth(), dateTime.getMonthOfYear(),
                    dateTime.getYear());

            intent.putExtra(Intent.EXTRA_TITLE, OPMLExportTitle);

            startActivityForResult(intent, REQUEST_CODE_CREATE_ALTER_OPML_FILE);
        }
    }

    @SuppressWarnings("ConstantConditions")
    private void toggleActionBarVisibility(final boolean visible) {
        final ActionBar actionBar = getSupportActionBar();

        if (visible) {
            if (!actionBar.isShowing()) {
                actionBar.show();
            }
        } else if (actionBar.isShowing()) {
            actionBar.hide();
        }
    }

    private void toggleMenuItemVisibility(final MenuItem item, final boolean visible) {
        if (visible) {
            if (!item.isVisible()) {
                item.setVisible(true);
            }
        } else if (item.isVisible()) {
            item.setVisible(false);
        }
    }

    private void toggleSystemUiVisibility(final boolean reset) {
        final View view = getWindow().getDecorView();

        if (reset) {
            view.setSystemUiVisibility(0);
        } else {
            view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
        }
    }

    public void unsubscribeFromSelectedFeeds(final List<String> keys) {
        mActionMode.finish();

        if (SharedPrefUtils.deleteFeedMetaData(this, keys)) {
            migrateCurrentFeedToPosition(0);
        }

        mFeedSubscriptionsChanged = true;

        getFeedSubscriptionsFragment().feedSubscriptionsChanged();

        if (SharedPrefUtils.isFeedMetaDataEmpty(this)) {
            final LoadCurrentFeedFragment loadCurrentFeedFragment = getLoadCurrentFeedFragment();
            if (loadCurrentFeedFragment.isAdded() && loadCurrentFeedFragment.isFeedLoading()) {
                getLoadCurrentFeedFragment().cancelFeedLoading();
            }

            final Loader feedUpdateLoader =
                    getLoaderManager().getLoader(IsFeedUpdateAvailableLoader.ID);

            if (feedUpdateLoader != null && feedUpdateLoader.isStarted()) {
                feedUpdateLoader.cancelLoad();
            }

            SharedPrefUtils.putCurrentFeedAdapterPosition(this, 0);

            CurrentFeed.set(null);

            removeFragment(getFeedSubscriptionsFragment(), false, false);

            toggleActionBarVisibility(false);

            getFragmentManager().popBackStackImmediate(null,
                    FragmentManager.POP_BACK_STACK_INCLUSIVE);

            mCurrentFeedFragment = null;
            mFeedSubscriptionsFragment = null;
            mSavedEntriesFragment = null;
            mInitialSetupFragment = null;
            mLoadCurrentFeedFragment = null;

            mBottomNavigationView.setVisibility(View.GONE);

            replaceFragment(getInitialSetupFragment(), false);

            invalidateOptionsMenu();
        }
    }

    public void updateFeedMetaData(final int index, final List<String> feedMetaData) {
        SharedPrefUtils.updateFeedMetaDataAt(this, index, feedMetaData);
        getFeedSubscriptionsFragment().feedSubscriptionsChanged();

        Toast.info(this, getString(R.string.fragment_feed_subscription_edit_success));
    }

    private void updateActionModeTitles(final String element) {
        if (mActionMode != null) {
            final StringBuilder subtitle = new StringBuilder();

            for (int i = 0; i < mSelectedRecyclerViewPositions.size(); i++) {
                final Integer position = mSelectedRecyclerViewPositions.get(i);
                final String title;

                if (getCurrentFeedFragment().isAdded()) {
                    title = CurrentFeed.get().getEntries().get(position - 1).getTitle();
                } else if (getFeedSubscriptionsFragment().isAdded()) {
                    title = SharedPrefUtils.getFeedMetaDataTitleAt(this, position);
                } else {
                    title = SavedEntries.getSavedEntryTitleAt(position);
                }

                if (i > 0) {
                    subtitle.append(String.format(", %s", title));
                } else {
                    subtitle.append(title);
                }
            }

            mActionMode.setTitle(String.format("%s %s %s",
                    mSelectedRecyclerViewPositions.size(),
                    element,
                    getString(R.string.selected)));
            mActionMode.setSubtitle(subtitle.toString());
        }
    }

    @SuppressWarnings("ConstantConditions")
    public boolean isSearchViewExpanded() {
        return TextUtils.isEmpty(getSupportActionBar().getTitle());
    }

    public SearchResultsCursor getSearchResultsCursor() {
        return mSearchResultsCursor;
    }

    private void onSearchViewNavigateCursor(final boolean next) {
        if (mSearchResultsCursor != null && !mSearchResultsCursor.isEmpty()) {
            final int previous = mSearchResultsCursor.current();

            if (next) {
                recyclerViewScrollTo(mSearchResultsCursor.next(), null);
            } else {
                recyclerViewScrollTo(mSearchResultsCursor.previous(), null);
            }

            final int current = mSearchResultsCursor.current();

            if (getCurrentFeedFragment().isAdded()) {
                getCurrentFeedFragment().updateHighlightedSearchResult(previous, current);
            } else if (getFeedSubscriptionsFragment().isAdded()) {
                getFeedSubscriptionsFragment().updateHighlightedSearchResult(previous, current);
            } else {
                getSavedEntriesFragment().updateHighlightedSearchResult(previous, current);
            }
        }
    }

    @SuppressWarnings("ConstantConditions")
    private void showSearchViewNoResultsSnackbar() {
        final View view;

        if (getCurrentFeedFragment().isAdded()) {
            view = getCurrentFeedFragment().getLayout();
        } else if (getFeedSubscriptionsFragment().isAdded()) {
            view = getFeedSubscriptionsFragment().getLayout();
        } else {
            view = getSavedEntriesFragment().getLayout();
        }

        final Snackbar snackbar =
                Snackbar.make(view, R.string.snackbar_no_search_results, Snackbar.LENGTH_LONG);

        final View snackbarView = snackbar.getView();
        final TextView snackbarText =
                snackbarView.findViewById(android.support.design.R.id.snackbar_text);
        final TextView snackbarAction =
                snackbarView.findViewById(android.support.design.R.id.snackbar_action);

        final float fontSize = FontUtils.getFontSizeInSp(this);

        snackbarText.setTextSize(fontSize);
        snackbarAction.setTextSize(fontSize);

        snackbar.setAction(R.string.snackbar_action_retry, new View.OnClickListener() {
            @Override
            public void onClick(final View view) {
                final EditText searchEditText = getSupportActionBar().getCustomView()
                        .findViewById(R.id.ActivityMainSearchEditText);

                SoftInputUtils.forceShowSoftInput( MainActivity.this, searchEditText);
            }
        });
        snackbar.show();
    }

    private void onSearchViewQueryChange(final String query, final ImageButton navigateBack,
                                   final TextView results) {
        final boolean isDarkThemeSelected = ThemeUtils.isDarkThemeSelected(this);
        final Drawable drawable;

        if (!TextUtils.isEmpty(query)) {
            if (isDarkThemeSelected) {
                drawable = getDrawable(R.drawable.ic_clear_white_24dp);
            } else {
                drawable = getDrawable(R.drawable.ic_clear_black_24dp);
            }
        } else {
            if (results.getVisibility() != View.INVISIBLE) {
                results.setVisibility(View.INVISIBLE);
            }

            if (isDarkThemeSelected) {
                drawable = getDrawable(R.drawable.ic_arrow_back_white_24dp);
            } else {
                drawable = getDrawable(R.drawable.ic_arrow_back_black_24dp);
            }
        }

        if (navigateBack.getDrawable() != drawable) {
            navigateBack.setImageDrawable(drawable);
        }

        if (mSearchResultsCursor != null && !mSearchResultsCursor.isEmpty()) {
            resetCardViewBackground(mSearchResultsCursor.getAll(), List.class);
            mSearchResultsCursor = null;
        }
    }

    private void onSearchViewQuerySubmit(final String query, final TextView results) {
        if (getCurrentFeedFragment().isAdded()) {
            mSearchResultsCursor = CurrentFeed.getSearchResults(query);
        } else if (getFeedSubscriptionsFragment().isAdded()) {
            mSearchResultsCursor = SharedPrefUtils.getSearchResultsFor(MainActivity.this, query);
        } else {
            mSearchResultsCursor = SavedEntries.getSearchResults((query));
        }

        if (!mSearchResultsCursor.isEmpty()) {
            showSearchViewCursorPosition(results);
            recyclerViewScrollTo(mSearchResultsCursor.first(), mSearchResultsCursor.getAll());
        } else {
            showSearchViewNoResultsSnackbar();
        }
    }

    @SuppressWarnings("ConstantConditions")
    private void hideSearchView() {
        final ActionBar actionBar = getSupportActionBar();
        final android.support.v7.widget.Toolbar toolbar =
                (android.support.v7.widget.Toolbar) actionBar.getCustomView().getParent();

        final EditText searchEditText = actionBar.getCustomView()
                .findViewById(R.id.ActivityMainSearchEditText);

        if (!TextUtils.isEmpty(searchEditText.getText().toString())) {
            searchEditText.setText(null);

            SoftInputUtils.forceShowSoftInput(this, toolbar);
        } else {
            final List<Integer> ids = Arrays.asList(R.attr.colorPrimary,
                    R.attr.colorPrimaryDark);

            TypedValueUtils.resolveResourceIds(MainActivity.this, ids);

            setActionBarColor(ids.get(0));
            setStatusBarColor(ids.get(1));

            toggleSystemUiVisibility(true);

            toolbar.setContentInsetsAbsolute(mActionBarInsets[0], mActionBarInsets[1]);

            SoftInputUtils.dismissSoftInput(this, toolbar);

            actionBar.setCustomView(null);
            actionBar.setDisplayShowCustomEnabled(false);

            actionBar.setDisplayShowTitleEnabled(true);

            invalidateOptionsMenu();
        }
    }

    private void showSearchViewCursorPosition(final TextView results) {
        if (mSearchResultsCursor != null) {
            final String currentPosition = mSearchResultsCursor.toString();

            if (!TextUtils.isEmpty(currentPosition)) {
                if (results.getVisibility() != View.VISIBLE) {
                    results.setVisibility(View.VISIBLE);
                }
                results.setText(currentPosition);
            }
        }
    }

    @SuppressWarnings("ConstantConditions")
    private void showSearchView() {
        final ActionBar actionBar = getSupportActionBar();

        final List<Integer> ids = Arrays.asList(
                R.attr.colorActionBarSearchViewExpanded,
                R.attr.colorStatusBarSearchViewExpanded);

        TypedValueUtils.resolveResourceIds(MainActivity.this, ids);

        setActionBarColor(ids.get(0));
        setStatusBarColor(ids.get(1));

        actionBar.setDisplayShowTitleEnabled(false);

        actionBar.setCustomView(R.layout.activity_main_search_view);
        actionBar.setDisplayShowCustomEnabled(true);

        invalidateOptionsMenu();

        final View view = actionBar.getCustomView();

        final android.support.v7.widget.Toolbar toolbar =
                (android.support.v7.widget.Toolbar) view.getParent();

        mActionBarInsets = new int[] {
                toolbar.getContentInsetLeft(),
                toolbar.getContentInsetRight()
        };

        toolbar.setContentInsetsAbsolute(0, 0);

        final EditText searchEditText = view.findViewById(R.id.ActivityMainSearchEditText);
        final TextView results = view.findViewById(R.id.ActivityMainResultsTextView);
        final ImageButton navigateBack = view.findViewById(R.id.ActivityMainBackImageButton);
        final ImageButton previous = view.findViewById(R.id.ActivityMainSearchPreviousImageButton);
        final ImageButton next = view.findViewById(R.id.ActivityMainSearchNextImageButton);

        results.setVisibility(View.INVISIBLE);

        if (ThemeUtils.isDarkThemeSelected(this)) {
            navigateBack.setImageDrawable(getDrawable(R.drawable.ic_arrow_back_white_24dp));
            previous.setImageDrawable(getDrawable(R.drawable.ic_navigate_before_white_24dp));
            next.setImageDrawable(getDrawable(R.drawable.ic_navigate_next_white_24dp));
        } else {
            toggleSystemUiVisibility(false);
        }

        searchEditText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(final CharSequence query, final int i,
                                          final int i1, final int i2) {}

            @Override
            public void onTextChanged(final CharSequence query, final int i,
                                      final int i1, final int i2) {
                onSearchViewQueryChange(String.valueOf(query), navigateBack, results);
            }

            @Override
            public void afterTextChanged(final Editable editable) {}
        });

        searchEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(final TextView textView, final int id,
                                          final KeyEvent keyEvent) {
                if (id == EditorInfo.IME_ACTION_SEARCH) {
                    SoftInputUtils.dismissSoftInput(MainActivity.this, toolbar);

                    onSearchViewQuerySubmit(searchEditText.getText().toString(), results);
                }
                return results.getVisibility() != View.INVISIBLE;
            }
        });

        navigateBack.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(final View view) {
                hideSearchView();
            }
        });

        previous.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(final View view) {
                onSearchViewNavigateCursor(false);
                showSearchViewCursorPosition(results);
            }
        });

        next.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(final View view) {
                onSearchViewNavigateCursor(true);
                showSearchViewCursorPosition(results);
            }
        });

        SoftInputUtils.forceShowSoftInput(this, searchEditText);
    }

    @SuppressWarnings("deprecation")
    public void startOrUpdateActionMode(final int position) {
        final boolean isCurrentFeedSelected = getCurrentFeedFragment().isAdded();
        final boolean isFeedSubscriptionsSelected = getFeedSubscriptionsFragment().isAdded();

        if (mActionMode != null) {
            final int selectionCnt;

            if (!mSelectedRecyclerViewPositions.contains(position)) {
                mSelectedRecyclerViewPositions.add(position);

                selectionCnt = mSelectedRecyclerViewPositions.size();

                updateActionModeTitles(getActionModeQuantityString(selectionCnt));
            } else {
                mSelectedRecyclerViewPositions.remove(Integer.valueOf(position));

                selectionCnt = mSelectedRecyclerViewPositions.size();

                if (selectionCnt < 1) {
                    resetCardViewBackground(position, Integer.class);
                    mActionMode.finish();
                } else if (selectionCnt < 2) {
                    updateActionModeTitles(getActionModeQuantityString(selectionCnt));
                } else if (selectionCnt > 1) {
                    updateActionModeTitles(getActionModeQuantityString(selectionCnt));
                }

                resetCardViewBackground(position, Integer.class);
            }
            return;
        }

        mSelectedRecyclerViewPositions = new ArrayList<>(Collections.singletonList(position));

        final int index = position - 1;

        mActionMode = startActionMode(new android.view.ActionMode.Callback() {
            @Override
            public boolean onCreateActionMode(final android.view.ActionMode mode, final Menu menu) {
                mode.getMenuInflater().inflate(R.menu.activity_main_action_mode, menu);

                setStatusBarColor(TypedValueUtils.resolveResourceId(MainActivity.this,
                        R.attr.colorStatusBarActionMode));

                final int size = mSelectedRecyclerViewPositions.size();

                mode.setTitle(String.format("%s %s %s",
                        size,
                        getActionModeQuantityString(size),
                        getString(R.string.selected)));

                String subtitle;

                if (isCurrentFeedSelected) {
                    subtitle = CurrentFeed.get().getEntries().get(index).getTitle();
                } else if (isFeedSubscriptionsSelected) {
                    subtitle = SharedPrefUtils.getFeedMetaDataTitleAt(MainActivity.this, position);
                } else {
                    subtitle = SavedEntries.getSavedEntryTitleAt(position);
                }

                if (mSelectedRecyclerViewPositions.size() > 1) {
                    subtitle = String.format("%s,...", subtitle);
                }

                mode.setSubtitle(subtitle);

                return true;
            }

            @Override
            public boolean onPrepareActionMode(final android.view.ActionMode mode,
                                               final Menu menu) {
                final MenuItem itemReadEntry = menu.findItem(R.id.action_read_entry);
                final MenuItem itemReadComments = menu.findItem(R.id.action_read_comments);
                final MenuItem itemViewEnclosure = menu.findItem(R.id.action_view_enclosure);
                final MenuItem itemSaveEntries = menu.findItem(R.id.action_save_entries);

                if (isCurrentFeedSelected) {
                    final SyndEntry entry =
                            CurrentFeed.get().getEntries().get(index);

                    final boolean linkEmpty = TextUtils.isEmpty(entry.getLink());
                    final boolean commentsEmpty = TextUtils.isEmpty(entry.getComments());

                    if (mSelectedRecyclerViewPositions.size() > 1) {
                        itemReadEntry.setVisible(false);
                        itemReadComments.setVisible(false);
                        itemViewEnclosure.setVisible(false);

                        if (linkEmpty) {
                            itemSaveEntries.setVisible(false);
                        }
                    } else {
                        if (!linkEmpty) {
                            itemReadEntry.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
                            itemReadEntry.setVisible(true);
                        } else {
                            itemReadEntry.setVisible(false);
                        }

                        if (!commentsEmpty) {
                            itemReadComments.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
                            itemReadComments.setVisible(true);
                        } else {
                            itemReadComments.setVisible(false);
                        }

                        final List<SyndEnclosure> enclosures = entry.getEnclosures();

                        if (enclosures != null && !enclosures.isEmpty()) {
                            itemViewEnclosure.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
                            itemViewEnclosure.setVisible(true);
                        } else {
                            itemViewEnclosure.setVisible(false);
                        }

                        itemSaveEntries.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
                    }
                } else if (isFeedSubscriptionsSelected) {
                    final MenuItem itemUnsubscribeFromFeeds =
                            menu.findItem(R.id.action_unsubscribe_from_feeds);
                    final MenuItem itemEditSubscription =
                            menu.findItem(R.id.action_edit_subscription);

                    itemReadEntry.setVisible(false);
                    itemReadComments.setVisible(false);
                    itemViewEnclosure.setVisible(false);
                    itemSaveEntries.setVisible(false);

                    itemUnsubscribeFromFeeds.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
                    itemUnsubscribeFromFeeds.setVisible(true);

                    if (mSelectedRecyclerViewPositions.size() > 1) {
                        itemEditSubscription.setVisible(false);
                    } else {
                        itemEditSubscription.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
                        itemEditSubscription.setVisible(true);
                    }
                } else {
                    final MenuItem itemDeleteSavedEntries =
                            menu.findItem(R.id.action_delete_entries);

                    itemReadComments.setVisible(false);
                    itemViewEnclosure.setVisible(false);
                    itemSaveEntries.setVisible(false);

                    itemDeleteSavedEntries.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);

                    itemDeleteSavedEntries.setVisible(true);

                    if (mSelectedRecyclerViewPositions.size() > 1) {
                        itemReadEntry.setVisible(false);
                    } else {
                        itemReadEntry.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
                        if (!itemReadEntry.isVisible()) {
                            itemReadEntry.setVisible(true);
                        }
                    }
                }

                return true;
            }

            @Override
            public boolean onActionItemClicked(final android.view.ActionMode mode,
                                               final MenuItem item) {
                switch (item.getItemId()) {
                    case R.id.action_read_entry:
                        if (isCurrentFeedSelected) {
                            final String link = CurrentFeed.get().getEntries()
                                    .get(index).getLink();

                            startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(link)));
                        } else {
                            startActivity(new Intent(Intent.ACTION_VIEW,
                                    Uri.parse(SavedEntries.getSavedEntryUrlAt(
                                            mSelectedRecyclerViewPositions.get(0)))));
                        }
                        mode.finish();
                        return true;
                    case R.id.action_read_comments:
                        final String comments = CurrentFeed.get().getEntries()
                                .get(index).getComments();

                        mode.finish();
                        startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(comments)));
                        return true;
                    case R.id.action_view_enclosure:
                        final Intent intent = new Intent(MainActivity.this, PodcastActivity.class);
                        intent.putExtra(INTENT_EXTRA_PODCAST, index);

                        mode.finish();
                        startActivity(intent);
                        return true;
                    case R.id.action_save_entries:
                        performEntrySave();
                        mode.finish();
                        return true;
                    case R.id.action_unsubscribe_from_feeds:
                        final List<String> feedUnsubscriptions =
                                SharedPrefUtils.getFeedMetaDataTitlesAt(MainActivity.this,
                                        mSelectedRecyclerViewPositions);

                        UnsubscribeFromFeedsFragment
                                .getInstance((ArrayList<String>) feedUnsubscriptions)
                                .show(getFragmentManager(),
                                        UnsubscribeFromFeedsFragment.TAG);
                        return true;
                    case R.id.action_delete_entries:
                        SavedEntriesDeleteEntriesFragment
                                .getInstance(mSelectedRecyclerViewPositions)
                                .show(getFragmentManager(),
                                        SavedEntriesDeleteEntriesFragment.TAG);

                        mode.finish();
                        return true;
                    case R.id.action_edit_subscription:
                        FeedSubscriptionEditFragment.getInstance(position)
                                .show(getFragmentManager(),
                                        FeedSubscriptionEditFragment.TAG);

                        mode.finish();
                        return true;
                    default:
                        return false;
                }
            }

            @Override
            public void onDestroyActionMode(final android.view.ActionMode mode) {
                setStatusBarColor(TypedValueUtils.resolveResourceId(MainActivity.this,
                        R.attr.colorPrimaryDark));

                resetCardViewBackground(mSelectedRecyclerViewPositions, List.class);

                mSelectedRecyclerViewPositions = null;
                mActionMode = null;
            }
        });
    }

    public void startActionMode(final List<Integer> positions) {
        if (mActionMode != null) {
            return;
        }

        mIsCategoriesFilterApplied = true;
        mSelectedRecyclerViewPositions = positions;

        mActionMode = startActionMode(new android.view.ActionMode.Callback() {
            private int mCursor;

            @Override
            public boolean onCreateActionMode(final android.view.ActionMode mode, final Menu menu) {
                mode.getMenuInflater().inflate(R.menu.activity_main_action_mode_filter, menu);

                final MenuItem itemPrevious = menu.findItem(R.id.action_filter_previous);
                final MenuItem itemNext = menu.findItem(R.id.action_filter_next);
                final MenuItem itemSkipToEnd = menu.findItem(R.id.action_filter_skip_to_end);

                setStatusBarColor(TypedValueUtils.resolveResourceId(MainActivity.this,
                        R.attr.colorStatusBarActionMode));

                if (ThemeUtils.isDarkThemeSelected(MainActivity.this)) {
                    itemPrevious.setIcon(getDrawable(R.drawable.ic_arrow_upward_white_24dp));
                    itemNext.setIcon(getDrawable(R.drawable.ic_arrow_downward_white_24dp));
                }

                itemNext.getIcon().setAlpha(ICON_ALPHA_NORMAL);
                itemSkipToEnd.getIcon().setAlpha(ICON_ALPHA_NORMAL);

                final CurrentFeedFragment fragment = getCurrentFeedFragment();

                fragment.highlightVisibleSearchResults(positions);
                fragment.scrollTo(positions.get(mCursor));

                return true;
            }

            @Override
            public boolean onPrepareActionMode(final android.view.ActionMode mode,
                                               final Menu menu) {
                final MenuItem itemPrevious = menu.findItem(R.id.action_filter_previous);
                final MenuItem itemNext = menu.findItem(R.id.action_filter_next);
                final MenuItem itemSkipToStart = menu.findItem(R.id.action_filter_skip_to_start);
                final MenuItem itemSkipToEnd = menu.findItem(R.id.action_filter_skip_to_end);

                final int size = positions.size();

                if (size == 1) {
                    alterMenuItemAlpha(itemPrevious, false);
                    alterMenuItemAlpha(itemNext, false);
                    alterMenuItemAlpha(itemSkipToStart, false);
                    alterMenuItemAlpha(itemSkipToEnd, false);
                } else if (mCursor == 0) {
                    alterMenuItemAlpha(itemPrevious, false);
                    alterMenuItemAlpha(itemSkipToStart, false);

                    if (!itemNext.isEnabled()) {
                        alterMenuItemAlpha(itemNext, true);
                        alterMenuItemAlpha(itemSkipToEnd, true);
                    }
                } else if (mCursor == size - 1) {
                    alterMenuItemAlpha(itemNext, false);
                    alterMenuItemAlpha(itemSkipToEnd, false);

                    if (!itemPrevious.isEnabled()) {
                        alterMenuItemAlpha(itemPrevious, true);
                        alterMenuItemAlpha(itemSkipToStart, true);
                    }
                } else if (!itemPrevious.isEnabled()) {
                    alterMenuItemAlpha(itemPrevious, true);
                    alterMenuItemAlpha(itemSkipToStart, true);
                } else if (!itemNext.isEnabled()) {
                    alterMenuItemAlpha(itemNext, true);
                    alterMenuItemAlpha(itemSkipToEnd, true);
                }

                mode.setTitle(String.format("%s %s %s",
                        mCursor + 1,
                        getString(R.string.of), size));

                final String title = CurrentFeed.get().getEntries()
                        .get(positions.get(mCursor) - 1).getTitle();

                mode.setSubtitle(title);

                return true;
            }

            @Override
            public boolean onActionItemClicked(final android.view.ActionMode mode,
                                               final MenuItem item) {
                switch (item.getItemId()) {
                    case R.id.action_filter_next:
                        mCursor++;
                        getCurrentFeedFragment().scrollTo(positions.get(mCursor));

                        mode.invalidate();
                        return true;
                    case R.id.action_filter_previous:
                        mCursor--;
                        getCurrentFeedFragment().scrollTo(positions.get(mCursor));

                        mode.invalidate();
                        return true;
                    case R.id.action_filter_skip_to_start:
                        mCursor = 0;
                        getCurrentFeedFragment().scrollTo(positions.get(mCursor));

                        mode.invalidate();
                        return true;
                    case R.id.action_filter_skip_to_end:
                        mCursor = positions.size() - 1;
                        getCurrentFeedFragment().scrollTo(positions.get(mCursor));

                        mode.invalidate();
                        return true;
                    default:
                        return false;
                }
            }

            @Override
            public void onDestroyActionMode(final android.view.ActionMode mode) {
                setStatusBarColor(TypedValueUtils.resolveResourceId(MainActivity.this,
                        R.attr.colorPrimaryDark));

                resetCardViewBackground(positions, List.class);

                mIsCategoriesFilterApplied = false;

                mSelectedRecyclerViewPositions = null;
                mActionMode = null;
            }
        });
    }
}