/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * 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 com.android.calculator2;

import android.animation.Animator;
import android.app.Fragment;
import android.os.Bundle;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toolbar;

import java.util.ArrayList;

import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_DRAGGING;

public class HistoryFragment extends Fragment implements DragLayout.DragCallback {

    public static final String TAG = "HistoryFragment";
    public static final String CLEAR_DIALOG_TAG = "clear";

    private final DragController mDragController = new DragController();

    private RecyclerView mRecyclerView;
    private HistoryAdapter mAdapter;
    private DragLayout mDragLayout;

    private Evaluator mEvaluator;

    private ArrayList<HistoryItem> mDataSet = new ArrayList<>();

    private boolean mIsDisplayEmpty;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mAdapter = new HistoryAdapter(mDataSet);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        final View view = inflater.inflate(
                R.layout.fragment_history, container, false /* attachToRoot */);

        mDragLayout = (DragLayout) container.getRootView().findViewById(R.id.drag_layout);
        mDragLayout.addDragCallback(this);

        mRecyclerView = (RecyclerView) view.findViewById(R.id.history_recycler_view);
        mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                if (newState == SCROLL_STATE_DRAGGING) {
                    stopActionModeOrContextMenu();
                }
                super.onScrollStateChanged(recyclerView, newState);
            }
        });

        // The size of the RecyclerView is not affected by the adapter's contents.
        mRecyclerView.setHasFixedSize(true);
        mRecyclerView.setAdapter(mAdapter);

        final Toolbar toolbar = (Toolbar) view.findViewById(R.id.history_toolbar);
        toolbar.inflateMenu(R.menu.fragment_history);
        toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                if (item.getItemId() == R.id.menu_clear_history) {
                    final Calculator calculator = (Calculator) getActivity();
                    AlertDialogFragment.showMessageDialog(calculator, "" /* title */,
                            getString(R.string.dialog_clear),
                            getString(R.string.menu_clear_history),
                            CLEAR_DIALOG_TAG);
                    return true;
                }
                return onOptionsItemSelected(item);
            }
        });
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getActivity().onBackPressed();
            }
        });
        return view;
    }

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

        final Calculator activity = (Calculator) getActivity();
        mEvaluator = Evaluator.getInstance(activity);
        mAdapter.setEvaluator(mEvaluator);

        final boolean isResultLayout = activity.isResultLayout();
        final boolean isOneLine = activity.isOneLine();

        // Snapshot display state here. For the rest of the lifecycle of this current
        // HistoryFragment, this is what we will consider the display state.
        // In rare cases, the display state can change after our adapter is initialized.
        final CalculatorExpr mainExpr = mEvaluator.getExpr(Evaluator.MAIN_INDEX);
        mIsDisplayEmpty = mainExpr == null || mainExpr.isEmpty();

        initializeController(isResultLayout, isOneLine, mIsDisplayEmpty);

        final long maxIndex = mEvaluator.getMaxIndex();

        final ArrayList<HistoryItem> newDataSet = new ArrayList<>();

        if (!mIsDisplayEmpty && !isResultLayout) {
            // Add the current expression as the first element in the list (the layout is
            // reversed and we want the current expression to be the last one in the
            // RecyclerView).
            // If we are in the result state, the result will animate to the last history
            // element in the list and there will be no "Current Expression."
            mEvaluator.copyMainToHistory();
            newDataSet.add(new HistoryItem(Evaluator.HISTORY_MAIN_INDEX,
                    System.currentTimeMillis(), mEvaluator.getExprAsSpannable(0)));
        }
        for (long i = 0; i < maxIndex; ++i) {
            newDataSet.add(null);
        }
        final boolean isEmpty = newDataSet.isEmpty();
        mRecyclerView.setBackgroundColor(ContextCompat.getColor(activity,
                isEmpty ? R.color.empty_history_color : R.color.display_background_color));
        if (isEmpty) {
            newDataSet.add(new HistoryItem());
        }
        mDataSet = newDataSet;
        mAdapter.setDataSet(mDataSet);
        mAdapter.setIsResultLayout(isResultLayout);
        mAdapter.setIsOneLine(activity.isOneLine());
        mAdapter.setIsDisplayEmpty(mIsDisplayEmpty);
        mAdapter.notifyDataSetChanged();
    }

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

        final Calculator activity = (Calculator) getActivity();
        mDragController.initializeAnimation(activity.isResultLayout(), activity.isOneLine(),
                mIsDisplayEmpty);
    }

    @Override
    public Animator onCreateAnimator(int transit, boolean enter, int nextAnim) {
        return mDragLayout.createAnimator(enter);
    }

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

        if (mDragLayout != null) {
            mDragLayout.removeDragCallback(this);
        }

        if (mEvaluator != null) {
            // Note that the view is destroyed when the fragment backstack is popped, so
            // these are essentially called when the DragLayout is closed.
            mEvaluator.cancelNonMain();
        }
    }

    private void initializeController(boolean isResult, boolean isOneLine, boolean isDisplayEmpty) {
        mDragController.setDisplayFormula(
                (CalculatorFormula) getActivity().findViewById(R.id.formula));
        mDragController.setDisplayResult(
                (CalculatorResult) getActivity().findViewById(R.id.result));
        mDragController.setToolbar(getActivity().findViewById(R.id.toolbar));
        mDragController.setEvaluator(mEvaluator);
        mDragController.initializeController(isResult, isOneLine, isDisplayEmpty);
    }

    public boolean stopActionModeOrContextMenu() {
        if (mRecyclerView == null) {
            return false;
        }
        for (int i = 0; i < mRecyclerView.getChildCount(); i++) {
            final View view = mRecyclerView.getChildAt(i);
            final HistoryAdapter.ViewHolder viewHolder =
                    (HistoryAdapter.ViewHolder) mRecyclerView.getChildViewHolder(view);
            if (viewHolder != null && viewHolder.getResult() != null
                    && viewHolder.getResult().stopActionModeOrContextMenu()) {
                return true;
            }
        }
        return false;
    }

    /* Begin override DragCallback methods. */

    @Override
    public void onStartDraggingOpen() {
        // no-op
    }

    @Override
    public void onInstanceStateRestored(boolean isOpen) {
        if (isOpen) {
            mRecyclerView.setVisibility(View.VISIBLE);
        }
    }

    @Override
    public void whileDragging(float yFraction) {
        if (isVisible() || isRemoving()) {
            mDragController.animateViews(yFraction, mRecyclerView);
        }
    }

    @Override
    public boolean shouldCaptureView(View view, int x, int y) {
        return !mRecyclerView.canScrollVertically(1 /* scrolling down */);
    }

    @Override
    public int getDisplayHeight() {
        return 0;
    }

    /* End override DragCallback methods. */
}
