/*
 * Copyright (c) 2015 Ngewi Fet <ngewif@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.gnucash.android.ui.common;

import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.database.Cursor;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.LayoutRes;
import android.support.annotation.StringRes;
import android.support.design.widget.NavigationView;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.widget.PopupMenu;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.uservoice.uservoicesdk.UserVoice;

import org.gnucash.android.R;
import org.gnucash.android.app.GnuCashApplication;
import org.gnucash.android.db.DatabaseSchema;
import org.gnucash.android.db.adapter.BooksDbAdapter;
import org.gnucash.android.ui.account.AccountsActivity;
import org.gnucash.android.ui.passcode.PasscodeLockActivity;
import org.gnucash.android.ui.report.ReportsActivity;
import org.gnucash.android.ui.settings.PreferenceActivity;
import org.gnucash.android.ui.transaction.ScheduledActionsActivity;
import org.gnucash.android.util.BookUtils;

import butterknife.BindView;
import butterknife.ButterKnife;


/**
 * Base activity implementing the navigation drawer, to be extended by all activities requiring one.
 * <p>
 *     Each activity inheriting from this class has an indeterminate progress bar at the top,
 *     (above the action bar) which can be used to display busy operations. See {@link #getProgressBar()}
 * </p>
 *
 * <p>Sub-classes should simply provide their layout using {@link #getContentView()} and then annotate
 * any variables they wish to use with {@link ButterKnife#bind(Activity)} annotations. The view
 * binding will be done in this base abstract class.<br>
 * The activity layout of the subclass is expected to contain {@code DrawerLayout} and
 * a {@code NavigationView}.<br>
 * Sub-class should also consider using the {@code toolbar.xml} or {@code toolbar_with_spinner.xml}
 * for the action bar in their XML layout. Otherwise provide another which contains widgets for the
 * toolbar and progress indicator with the IDs {@code R.id.toolbar} and {@code R.id.progress_indicator} respectively.
 * </p>
 * @author Ngewi Fet <ngewif@gmail.com>
 */
public abstract class BaseDrawerActivity extends PasscodeLockActivity implements
    PopupMenu.OnMenuItemClickListener {

    public static final int ID_MANAGE_BOOKS = 0xB00C;
    @BindView(R.id.drawer_layout) DrawerLayout mDrawerLayout;
    @BindView(R.id.nav_view) NavigationView mNavigationView;
    @BindView(R.id.toolbar) Toolbar mToolbar;
    @BindView(R.id.toolbar_progress) ProgressBar mToolbarProgress;
    protected TextView mBookNameTextView;

    protected ActionBarDrawerToggle mDrawerToggle;

    public static final int REQUEST_OPEN_DOCUMENT = 0x20;

    private class DrawerItemClickListener implements NavigationView.OnNavigationItemSelectedListener {

        @Override
        public boolean onNavigationItemSelected(MenuItem menuItem) {
            onDrawerMenuItemClicked(menuItem.getItemId());
            return true;
        }

    }

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

        //if a parameter was passed to open an account within a specific book, then switch
        String bookUID = getIntent().getStringExtra(UxArgument.BOOK_UID);
        if (bookUID != null && !bookUID.equals(BooksDbAdapter.getInstance().getActiveBookUID())){
            BookUtils.activateBook(bookUID);
        }

        ButterKnife.bind(this);
        setSupportActionBar(mToolbar);
        final ActionBar actionBar = getSupportActionBar();
        if (actionBar != null){
            actionBar.setHomeButtonEnabled(true);
            actionBar.setDisplayHomeAsUpEnabled(true);
            actionBar.setTitle(getTitleRes());
        }

        mToolbarProgress.getIndeterminateDrawable().setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN);

        View headerView = mNavigationView.getHeaderView(0);
        headerView.findViewById(R.id.drawer_title).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onClickAppTitle(v);
            }
        });

        mBookNameTextView = (TextView) headerView.findViewById(R.id.book_name);
        mBookNameTextView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onClickBook(v);
            }
        });
        updateActiveBookName();
        setUpNavigationDrawer();
    }

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

    /**
     * Return the layout to inflate for this activity
     * @return Layout resource identifier
     */
    public abstract @LayoutRes int getContentView();

    /**
     * Return the title for this activity.
     * This will be displayed in the action bar
     * @return String resource identifier
     */
    public abstract @StringRes int getTitleRes();

    /**
     * Returns the progress bar for the activity.
     * <p>This progress bar is displayed above the toolbar and should be used to show busy status
     * for long operations.<br/>
     * The progress bar visibility is set to {@link View#GONE} by default. Make visible to use </p>
     * @return Indeterminate progress bar.
     */
    public ProgressBar getProgressBar(){
        return mToolbarProgress;
    }

    /**
     * Sets up the navigation drawer for this activity.
     */
    private void setUpNavigationDrawer() {
        mNavigationView.setNavigationItemSelectedListener(new DrawerItemClickListener());

        mDrawerToggle = new ActionBarDrawerToggle(
                this,                  /* host Activity */
                mDrawerLayout,         /* DrawerLayout object */
                R.string.drawer_open,  /* "open drawer" description */
                R.string.drawer_close  /* "close drawer" description */
        ) {

            /** Called when a drawer has settled in a completely closed state. */
            public void onDrawerClosed(View view) {
                super.onDrawerClosed(view);
            }

            /** Called when a drawer has settled in a completely open state. */
            public void onDrawerOpened(View drawerView) {
                super.onDrawerOpened(drawerView);
            }
        };

        mDrawerLayout.setDrawerListener(mDrawerToggle);
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        mDrawerToggle.syncState();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        mDrawerToggle.onConfigurationChanged(newConfig);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == android.R.id.home){
            if (!mDrawerLayout.isDrawerOpen(mNavigationView))
                mDrawerLayout.openDrawer(mNavigationView);
            else
                mDrawerLayout.closeDrawer(mNavigationView);
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    /**
     * Update the display name of the currently active book
     */
    protected void updateActiveBookName(){
        mBookNameTextView.setText(BooksDbAdapter.getInstance().getActiveBookDisplayName());
    }

    /**
     * Handler for the navigation drawer items
     * */
    protected void onDrawerMenuItemClicked(int itemId) {
        switch (itemId){
            case R.id.nav_item_open: { //Open... files
                //use the storage access framework
                Intent openDocument = new Intent(Intent.ACTION_OPEN_DOCUMENT);
                openDocument.addCategory(Intent.CATEGORY_OPENABLE);
                openDocument.setType("text/*|application/*");
                String[] mimeTypes = {"text/*", "application/*"};
                openDocument.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
                startActivityForResult(openDocument, REQUEST_OPEN_DOCUMENT);
            }
            break;

            case R.id.nav_item_favorites: { //favorite accounts
                Intent intent = new Intent(this, AccountsActivity.class);
                intent.putExtra(AccountsActivity.EXTRA_TAB_INDEX,
                        AccountsActivity.INDEX_FAVORITE_ACCOUNTS_FRAGMENT);
                intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP);
                startActivity(intent);
            }
                break;

            case R.id.nav_item_reports: {
                Intent intent = new Intent(this, ReportsActivity.class);
                intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
                startActivity(intent);
            }
                break;

/*
            //todo: Re-enable this when Budget UI is complete
            case R.id.nav_item_budgets:
                startActivity(new Intent(this, BudgetsActivity.class));
                break;
*/
            case R.id.nav_item_scheduled_actions: { //show scheduled transactions
                Intent intent = new Intent(this, ScheduledActionsActivity.class);
                intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
                startActivity(intent);
            }
                break;

            case R.id.nav_item_export:
                AccountsActivity.openExportFragment(this);
                break;

            case R.id.nav_item_settings: //Settings activity
                startActivity(new Intent(this, PreferenceActivity.class));
                break;

            case R.id.nav_item_help:
                SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
                prefs.edit().putBoolean(UxArgument.SKIP_PASSCODE_SCREEN, true).apply();
                UserVoice.launchUserVoice(this);
                break;
        }
        mDrawerLayout.closeDrawer(mNavigationView);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode == Activity.RESULT_CANCELED) {
            super.onActivityResult(requestCode, resultCode, data);
            return;
        }

        switch (requestCode) {
            case AccountsActivity.REQUEST_PICK_ACCOUNTS_FILE:
                AccountsActivity.importXmlFileFromIntent(this, data, null);
                break;
            case BaseDrawerActivity.REQUEST_OPEN_DOCUMENT: //this uses the Storage Access Framework
                final int takeFlags = data.getFlags()
                        & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                AccountsActivity.importXmlFileFromIntent(this, data, null);
                getContentResolver().takePersistableUriPermission(data.getData(), takeFlags);
                break;
            default:
                super.onActivityResult(requestCode, resultCode, data);
                break;
        }
    }

    @Override
    public boolean onMenuItemClick(MenuItem item) {
        long id = item.getItemId();
        if (id == ID_MANAGE_BOOKS){
            Intent intent = new Intent(this, PreferenceActivity.class);
            intent.setAction(PreferenceActivity.ACTION_MANAGE_BOOKS);
            startActivity(intent);
            mDrawerLayout.closeDrawer(mNavigationView);
            return true;
        }
        BooksDbAdapter booksDbAdapter = BooksDbAdapter.getInstance();
        String bookUID = booksDbAdapter.getUID(id);
        if (!bookUID.equals(booksDbAdapter.getActiveBookUID())){
            BookUtils.loadBook(bookUID);
            finish();
        }
        AccountsActivity.start(GnuCashApplication.getAppContext());
        return true;
    }

    public void onClickAppTitle(View view){
        mDrawerLayout.closeDrawer(mNavigationView);
        AccountsActivity.start(this);
    }

    public void onClickBook(View view){
        PopupMenu popup = new PopupMenu(this, view);
        popup.setOnMenuItemClickListener(this);

        Menu menu = popup.getMenu();
        int maxRecent = 0;
        Cursor cursor = BooksDbAdapter.getInstance().fetchAllRecords(null, null,
                DatabaseSchema.BookEntry.COLUMN_MODIFIED_AT + " DESC");
        while (cursor.moveToNext() && maxRecent++ < 5) {
            long id = cursor.getLong(cursor.getColumnIndexOrThrow(DatabaseSchema.BookEntry._ID));
            String name = cursor.getString(cursor.getColumnIndexOrThrow(DatabaseSchema.BookEntry.COLUMN_DISPLAY_NAME));
            menu.add(0, (int)id, maxRecent, name);
        }
        menu.add(0, ID_MANAGE_BOOKS, maxRecent, R.string.menu_manage_books);

        popup.show();
    }
}
