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

import static com.android.documentsui.base.SharedMinimal.DEBUG;

import android.util.Log;
import android.view.KeyEvent;

import androidx.recyclerview.selection.SelectionTracker;

import com.android.documentsui.base.Events;
import com.android.documentsui.base.Features;
import com.android.documentsui.base.Procedure;
import com.android.documentsui.dirlist.FocusHandler;

/**
 * Handle common input events.
 */
public class SharedInputHandler {

    private static final String TAG = "SharedInputHandler";

    private final FocusHandler mFocusManager;
    private final Procedure mSearchCanceler;
    private final Procedure mDirPopper;
    private final Runnable mSearchExecutor;
    private final Features mFeatures;
    private final SelectionTracker<String> mSelectionMgr;
    private final DrawerController mDrawer;

    public SharedInputHandler(
            FocusHandler focusHandler,
            SelectionTracker<String> selectionMgr,
            Procedure searchCanceler,
            Procedure dirPopper,
            Features features,
            DrawerController drawer,
            Runnable searchExcutor) {
        mFocusManager = focusHandler;
        mSearchCanceler = searchCanceler;
        mSelectionMgr = selectionMgr;
        mDirPopper = dirPopper;
        mFeatures = features;
        mDrawer = drawer;
        mSearchExecutor = searchExcutor;
    }

    public boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
            // Unhandled ESC keys end up being rethrown back at us as BACK keys. So by returning
            // true, we make sure it always does no-op.
            case KeyEvent.KEYCODE_ESCAPE:
                return onEscape();

            case KeyEvent.KEYCODE_DEL:
                return onDelete();

            // This is the Android back button, not backspace.
            case KeyEvent.KEYCODE_BACK:
                return onBack();

            case KeyEvent.KEYCODE_TAB:
                return onTab();

            case KeyEvent.KEYCODE_SEARCH:
                mSearchExecutor.run();
                return true;

            default:
                // Instead of duplicating the switch-case in #isNavigationKeyCode, best just to
                // leave it here.
                if (Events.isNavigationKeyCode(keyCode)) {
                    // Forward all unclaimed navigation keystrokes to the directory list.
                    // This causes any stray navigation keystrokes to focus the content pane,
                    // which is probably what the user is trying to do.
                    mFocusManager.focusDirectoryList();
                    return true;
                }
                return false;
        }
    }

    private boolean onTab() {
        if (!mFeatures.isSystemKeyboardNavigationEnabled()) {
            // Tab toggles focus on the navigation drawer.
            // This should only be called in pre-O devices, since O has built-in keyboard
            // navigation
            // support.
            mFocusManager.advanceFocusArea();
            return true;
        }

        return false;
    }

    private boolean onDelete() {
        mDirPopper.run();
        return true;
    }

    private boolean onBack() {
        if (mDrawer.isPresent() && mDrawer.isOpen()) {
            mDrawer.setOpen(false);
            return true;
        }

        if (mSearchCanceler.run()) {
            return true;
        }

        if (mSelectionMgr.hasSelection()) {
            if (DEBUG) {
                Log.d(TAG, "Back pressed. Clearing existing selection.");
            }
            mSelectionMgr.clearSelection();
            return true;
        }

        return mDirPopper.run();
    }

    private boolean onEscape() {
        if (mSearchCanceler.run()) {
            return true;
        }

        if (mSelectionMgr.hasSelection()) {
            if (DEBUG) {
                Log.d(TAG, "ESC pressed. Clearing existing selection.");
            }
            mSelectionMgr.clearSelection();
            return true;
        }

        return true;
    }
}
