/*
 * Copyright 2017, 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.managedprovisioning.common;

import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK;

import android.app.Activity;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.text.Spanned;
import android.text.style.ClickableSpan;
import android.view.ContextMenu;
import android.view.View;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.TextView;

import com.android.managedprovisioning.R;

/**
 * Creates a new {@link ContextMenu}, and populates it with a list of links contained in a target
 * {@link TextView}.
 * <p>
 * Known issue: does not listen to TalkBack on / off events.
 */
public class AccessibilityContextMenuMaker {
    private final Activity mActivity;

    /**
     * @param activity the target {@link TextView} belongs to
     */
    public AccessibilityContextMenuMaker(Activity activity) {
        mActivity = activity;
    }

    /**
     * If {@link ClickableSpan} links present, registers a context menu with the {@link Activity}.
     * If no links present, unregisters, which is useful in case of recyclable views.
     *
     * @param textView target TextView potentially containing links.
     */
    public void registerWithActivity(TextView textView) {
        if (getSpans(getText(textView)).length == 0) {
            mActivity.unregisterForContextMenu(textView);
            textView.setAccessibilityDelegate(null);
            textView.setClickable(false);
            textView.setLongClickable(false);
            return;
        }

        mActivity.registerForContextMenu(textView);
        textView.setOnClickListener(View::showContextMenu);
        textView.setLongClickable(false);
        textView.setAccessibilityDelegate(
                new View.AccessibilityDelegate() {
                    @Override
                    public void onInitializeAccessibilityNodeInfo(View host,
                            AccessibilityNodeInfo info) {
                        super.onInitializeAccessibilityNodeInfo(host, info);
                        info.addAction(
                                new AccessibilityNodeInfo.AccessibilityAction(ACTION_CLICK.getId(),
                                        textView.getContext().getString(
                                                R.string.access_list_of_links)));
                    }
                }
        );
    }

    /**
     * Call inside
     * {@link Activity#onCreateContextMenu(ContextMenu, View, ContextMenu.ContextMenuInfo)}
     */
    public void populateMenuContent(ContextMenu menu, TextView textView) {
        if (!isScreenReaderEnabled()) {
            return;
        }

        Spanned spanned = getText(textView);
        ClickableSpan[] spans = getSpans(spanned);

        if (spanned == null || spans.length == 0) {
            return;
        }

        for (ClickableSpan span : spans) {
            int s = spanned.getSpanStart(span);
            int t = spanned.getSpanEnd(span);
            menu.add(spanned.subSequence(s, t)).setOnMenuItemClickListener(menuItem -> {
                span.onClick(textView);
                return false;
            });
        }
        menu.add(R.string.close_list).setOnMenuItemClickListener(menuItem -> {
            menu.close();
            return false;
        });
    }

    private boolean isScreenReaderEnabled() {
        AccessibilityManager am = mActivity.getSystemService(AccessibilityManager.class);
        return am.isEnabled() && am.isTouchExplorationEnabled();
    }

    private @Nullable Spanned getText(TextView textView) {
        CharSequence text = textView.getText();
        return (text instanceof Spanned) ? (Spanned) text : null;
    }

    private @NonNull ClickableSpan[] getSpans(Spanned spanned) {
        if (spanned == null) {
            return new ClickableSpan[0];
        }
        ClickableSpan[] spans = spanned.getSpans(0, spanned.length(), ClickableSpan.class);
        return spans.length == 0 ? new ClickableSpan[0] : spans;
    }
}