/*
 * Copyright (C) 2020 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.systemui.qs.customize;

import android.os.Bundle;
import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo;

import androidx.core.view.AccessibilityDelegateCompat;
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;

import com.android.systemui.res.R;

import java.util.List;

/**
 * Accessibility delegate for {@link TileAdapter} views.
 *
 * This delegate will populate the accessibility info with the proper actions that can be taken for
 * the different tiles:
 * <ul>
 *   <li>Add to end if the tile is not a current tile (by double tap).</li>
 *   <li>Add to a given position (by context menu). This will let the user select a position.</li>
 *   <li>Remove, if the tile is a current tile (by double tap).</li>
 *   <li>Move to a given position (by context menu). This will let the user select a position.</li>
 * </ul>
 *
 * This only handles generating the associated actions. The logic for selecting positions is handled
 * by {@link TileAdapter}.
 *
 * In order for the delegate to work properly, the asociated {@link TileAdapter.Holder} should be
 * passed along with the view using {@link View#setTag}.
 */
class TileAdapterDelegate extends AccessibilityDelegateCompat {

    private static final int MOVE_TO_POSITION_ID = R.id.accessibility_action_qs_move_to_position;
    private static final int ADD_TO_POSITION_ID = R.id.accessibility_action_qs_add_to_position;

    private TileAdapter.Holder getHolder(View view) {
        return (TileAdapter.Holder) view.getTag();
    }

    @Override
    public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
        super.onInitializeAccessibilityNodeInfo(host, info);
        TileAdapter.Holder holder = getHolder(host);
        info.setCollectionItemInfo(null);
        info.setStateDescription("");
        if (holder == null || !holder.canTakeAccessibleAction()) {
            // If there's not a holder (not a regular Tile) or an action cannot be taken
            // because we are in the middle of an accessibility action, don't create a special node.
            return;
        }

        addClickAction(host, info, holder);
        maybeAddActionAddToPosition(host, info, holder);
        maybeAddActionMoveToPosition(host, info, holder);

        if (holder.isCurrentTile()) {
            info.setStateDescription(host.getContext().getString(
                    R.string.accessibility_qs_edit_position, holder.getLayoutPosition()));
        }
    }

    @Override
    public boolean performAccessibilityAction(View host, int action, Bundle args) {
        TileAdapter.Holder holder = getHolder(host);

        if (holder == null || !holder.canTakeAccessibleAction()) {
            // If there's not a holder (not a regular Tile) or an action cannot be taken
            // because we are in the middle of an accessibility action, perform the default action.
            return super.performAccessibilityAction(host, action, args);
        }
        if (action == AccessibilityNodeInfo.ACTION_CLICK) {
            holder.toggleState();
            return true;
        } else if (action == MOVE_TO_POSITION_ID) {
            holder.startAccessibleMove();
            return true;
        } else if (action == ADD_TO_POSITION_ID) {
            holder.startAccessibleAdd();
            return true;
        } else {
            return super.performAccessibilityAction(host, action, args);
        }
    }

    private void addClickAction(
            View host, AccessibilityNodeInfoCompat info, TileAdapter.Holder holder) {
        String clickActionString;
        if (holder.canAdd()) {
            clickActionString = host.getContext().getString(
                    R.string.accessibility_qs_edit_tile_add_action);
        } else if (holder.canRemove()) {
            clickActionString = host.getContext().getString(
                    R.string.accessibility_qs_edit_remove_tile_action);
        } else {
            // Remove the default click action if tile can't either be added or removed (for example
            // if there's the minimum number of tiles)
            List<AccessibilityNodeInfoCompat.AccessibilityActionCompat> listOfActions =
                    info.getActionList(); // This is a copy
            int numActions = listOfActions.size();
            for (int i = 0; i < numActions; i++) {
                if (listOfActions.get(i).getId() == AccessibilityNodeInfo.ACTION_CLICK) {
                    info.removeAction(listOfActions.get(i));
                }
            }
            // We really don't want it to be clickable in this case.
            info.setClickable(false);
            return;
        }

        AccessibilityNodeInfoCompat.AccessibilityActionCompat action =
                new AccessibilityNodeInfoCompat.AccessibilityActionCompat(
                        AccessibilityNodeInfo.ACTION_CLICK, clickActionString);
        info.addAction(action);
        info.setClickable(true);
    }

    private void maybeAddActionMoveToPosition(
            View host, AccessibilityNodeInfoCompat info, TileAdapter.Holder holder) {
        if (holder.isCurrentTile()) {
            AccessibilityNodeInfoCompat.AccessibilityActionCompat action =
                    new AccessibilityNodeInfoCompat.AccessibilityActionCompat(MOVE_TO_POSITION_ID,
                            host.getContext().getString(
                                    R.string.accessibility_qs_edit_tile_start_move));
            info.addAction(action);
        }
    }

    private void maybeAddActionAddToPosition(
            View host, AccessibilityNodeInfoCompat info, TileAdapter.Holder holder) {
        if (holder.canAdd()) {
            AccessibilityNodeInfoCompat.AccessibilityActionCompat action =
                    new AccessibilityNodeInfoCompat.AccessibilityActionCompat(ADD_TO_POSITION_ID,
                            host.getContext().getString(
                                    R.string.accessibility_qs_edit_tile_start_add));
            info.addAction(action);
        }
    }
}
