// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chrome.browser.contextmenu;

import android.content.Context;
import android.text.style.ForegroundColorSpan;
import android.text.style.RelativeSizeSpan;
import android.text.style.SuperscriptSpan;

import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;

import org.chromium.chrome.R;
import org.chromium.chrome.browser.DefaultBrowserInfo;
import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
import org.chromium.chrome.browser.share.LensUtils;
import org.chromium.components.browser_ui.styles.SemanticColorUtils;
import org.chromium.ui.text.SpanApplier;
import org.chromium.ui.text.SpanApplier.SpanInfo;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * List of all predefined Context Menu Items available in Chrome.
 */
class ChromeContextMenuItem {
    @IntDef({Item.OPEN_IN_NEW_CHROME_TAB, Item.OPEN_IN_CHROME_INCOGNITO_TAB,
            Item.OPEN_IN_BROWSER_ID, Item.OPEN_IN_NEW_TAB, Item.OPEN_IN_INCOGNITO_TAB,
            Item.OPEN_IN_OTHER_WINDOW, Item.OPEN_IN_NEW_WINDOW, Item.OPEN_IN_EPHEMERAL_TAB,
            Item.COPY_LINK_ADDRESS, Item.COPY_LINK_TEXT, Item.SAVE_LINK_AS, Item.SHARE_LINK,
            Item.DIRECT_SHARE_LINK, Item.READ_LATER, Item.LOAD_ORIGINAL_IMAGE, Item.SAVE_IMAGE,
            Item.OPEN_IMAGE, Item.OPEN_IMAGE_IN_NEW_TAB, Item.OPEN_IMAGE_IN_EPHEMERAL_TAB,
            Item.COPY_IMAGE, Item.SEARCH_BY_IMAGE, Item.SEARCH_WITH_GOOGLE_LENS,
            Item.SHOP_IMAGE_WITH_GOOGLE_LENS, Item.SHARE_IMAGE, Item.DIRECT_SHARE_IMAGE, Item.CALL,
            Item.SEND_MESSAGE, Item.ADD_TO_CONTACTS, Item.COPY, Item.SAVE_VIDEO,
            Item.OPEN_IN_CHROME, Item.OPEN_IN_NEW_TAB_IN_GROUP, Item.SHARE_HIGHLIGHT,
            Item.REMOVE_HIGHLIGHT, Item.LEARN_MORE})
    @Retention(RetentionPolicy.SOURCE)
    public @interface Item {
        // Values are numerated from 0 and can't have gaps.
        // The menu and string IDs below must be kept in sync with this list.
        // Custom Tab Group
        int OPEN_IN_NEW_CHROME_TAB = 0;
        int OPEN_IN_CHROME_INCOGNITO_TAB = 1;
        int OPEN_IN_BROWSER_ID = 2;
        // Link Group
        int OPEN_IN_NEW_TAB = 3;
        int OPEN_IN_NEW_TAB_IN_GROUP = 4;
        int OPEN_IN_INCOGNITO_TAB = 5;
        int OPEN_IN_OTHER_WINDOW = 6;
        int OPEN_IN_NEW_WINDOW = 7;
        int OPEN_IN_EPHEMERAL_TAB = 8;
        int COPY_LINK_ADDRESS = 9;
        int COPY_LINK_TEXT = 10;
        int SAVE_LINK_AS = 11;
        int SHARE_LINK = 12;
        int DIRECT_SHARE_LINK = 13;
        int READ_LATER = 14;
        // Image Group
        int LOAD_ORIGINAL_IMAGE = 15;
        int SAVE_IMAGE = 16;
        int OPEN_IMAGE = 17;
        int OPEN_IMAGE_IN_NEW_TAB = 18;
        int OPEN_IMAGE_IN_EPHEMERAL_TAB = 19;
        int COPY_IMAGE = 20;
        int SEARCH_BY_IMAGE = 21;
        int SEARCH_WITH_GOOGLE_LENS = 22;
        int SHOP_IMAGE_WITH_GOOGLE_LENS = 23;
        int SHARE_IMAGE = 24;
        int DIRECT_SHARE_IMAGE = 25;
        // Message Group
        int CALL = 26;
        int SEND_MESSAGE = 27;
        int ADD_TO_CONTACTS = 28;
        int COPY = 29;
        // Video Group
        int SAVE_VIDEO = 30;
        // Other
        int OPEN_IN_CHROME = 31;
        // Shared Highlighting options
        int SHARE_HIGHLIGHT = 32;
        int REMOVE_HIGHLIGHT = 33;
        int LEARN_MORE = 34;
        // ALWAYS UPDATE!
        int NUM_ENTRIES = 35;
    }

    /**
     * Mapping from {@link Item} to the ID found in the ids.xml.
     */
    private static final int[] MENU_IDS = {
            R.id.contextmenu_open_in_new_chrome_tab, // Item.OPEN_IN_NEW_CHROME_TAB
            R.id.contextmenu_open_in_chrome_incognito_tab, // Item.OPEN_IN_CHROME_INCOGNITO_TAB
            R.id.contextmenu_open_in_browser_id, // Item.OPEN_IN_BROWSER_ID
            R.id.contextmenu_open_in_new_tab, // Item.OPEN_IN_NEW_TAB
            R.id.contextmenu_open_in_new_tab_in_group, // Item.OPEN_IN_NEW_TAB_IN_GROUP
            R.id.contextmenu_open_in_incognito_tab, // Item.OPEN_IN_INCOGNITO_TAB
            R.id.contextmenu_open_in_other_window, // Item.OPEN_IN_OTHER_WINDOW
            R.id.contextmenu_open_in_new_window, // Item.OPEN_IN_NEW_WINDOW
            R.id.contextmenu_open_in_ephemeral_tab, // Item.OPEN_IN_EPHEMERAL_TAB
            R.id.contextmenu_copy_link_address, // Item.COPY_LINK_ADDRESS
            R.id.contextmenu_copy_link_text, // Item.COPY_LINK_TEXT
            R.id.contextmenu_save_link_as, // Item.SAVE_LINK_AS
            R.id.contextmenu_share_link, // Item.SHARE_LINK
            R.id.contextmenu_direct_share_link, // Item.DIRECT_SHARE_LINK
            R.id.contextmenu_read_later, // Item.READ_LATER
            R.id.contextmenu_load_original_image, // Item.LOAD_ORIGINAL_IMAGE
            R.id.contextmenu_save_image, // Item.SAVE_IMAGE
            R.id.contextmenu_open_image, // Item.OPEN_IMAGE
            R.id.contextmenu_open_image_in_new_tab, // Item.OPEN_IMAGE_IN_NEW_TAB
            R.id.contextmenu_open_image_in_ephemeral_tab, // Item.OPEN_IMAGE_IN_EPHEMERAL_TAB
            R.id.contextmenu_copy_image, // Item.COPY_IMAGE
            R.id.contextmenu_search_by_image, // Item.SEARCH_BY_IMAGE
            R.id.contextmenu_search_with_google_lens, // Item.SEARCH_WITH_GOOGLE_LENS
            R.id.contextmenu_shop_image_with_google_lens, // Item.SHOP_IMAGE_WITH_GOOGLE_LENS
            R.id.contextmenu_share_image, // Item.SHARE_IMAGE
            R.id.contextmenu_direct_share_image, // Item.DIRECT_SHARE_IMAGE
            R.id.contextmenu_call, // Item.CALL
            R.id.contextmenu_send_message, // Item.SEND_MESSAGE
            R.id.contextmenu_add_to_contacts, // Item.ADD_TO_CONTACTS
            R.id.contextmenu_copy, // Item.COPY
            R.id.contextmenu_save_video, // Item.SAVE_VIDEO
            R.id.contextmenu_open_in_chrome, // Item.OPEN_IN_CHROME
            R.id.contextmenu_share_highlight, // Item.SHARE_HIGHLIGHT
            R.id.contextmenu_remove_highlight, // Item.REMOVE_HIGHLIGHT
            R.id.contextmenu_learn_more, // Item.LEARN_MORE
    };

    /**
     * Mapping from {@link Item} to the ID of the string that describes the action of the item.
     */
    private static final int[] STRING_IDS = {
            R.string.contextmenu_open_in_new_chrome_tab, // Item.OPEN_IN_NEW_CHROME_TAB:
            R.string.contextmenu_open_in_chrome_incognito_tab, // Item.OPEN_IN_CHROME_INCOGNITO_TAB:
            0, // Item.OPEN_IN_BROWSER_ID is not handled by this mapping.
            R.string.contextmenu_open_in_new_tab, // Item.OPEN_IN_NEW_TAB:
            R.string.contextmenu_open_in_new_tab_group, // Item.OPEN_IN_NEW_TAB_IN_GROUP
            R.string.contextmenu_open_in_incognito_tab, // Item.OPEN_IN_INCOGNITO_TAB:
            R.string.contextmenu_open_in_other_window, // Item.OPEN_IN_OTHER_WINDOW:
            R.string.contextmenu_open_in_new_window, // Item.OPEN_IN_NEW_WINDOW:
            R.string.contextmenu_open_in_ephemeral_tab, // Item.OPEN_IN_EPHEMERAL_TAB:
            R.string.contextmenu_copy_link_address, // Item.COPY_LINK_ADDRESS:
            R.string.contextmenu_copy_link_text, // Item.COPY_LINK_TEXT:
            R.string.contextmenu_save_link, // Item.SAVE_LINK_AS:
            R.string.contextmenu_share_link, // Item.SHARE_LINK
            0, // Item.DIRECT_SHARE_LINK is not handled by this mapping.
            R.string.contextmenu_read_later, // Item.READ_LATER
            R.string.contextmenu_load_original_image, // Item.LOAD_ORIGINAL_IMAGE:
            R.string.contextmenu_save_image, // Item.SAVE_IMAGE:
            R.string.contextmenu_open_image, // Item.OPEN_IMAGE:
            R.string.contextmenu_open_image_in_new_tab, // Item.OPEN_IMAGE_IN_NEW_TAB:
            R.string.contextmenu_open_image_in_ephemeral_tab, // Item.OPEN_IMAGE_IN_EPHEMERAL_TAB:
            R.string.contextmenu_copy_image, // Item.COPY_IMAGE:
            R.string.contextmenu_search_web_for_image, // Item.SEARCH_BY_IMAGE:
            LensUtils.getLensContextMenuText(), // Item.SEARCH_WITH_GOOGLE_LENS:
            R.string.contextmenu_shop_image_with_google_lens, // Item.SHOP_IMAGE_WITH_GOOGLE_LENS:
            R.string.contextmenu_share_image, // Item.SHARE_IMAGE
            0, // Item.DIRECT_SHARE_IMAGE is not handled by this mapping.
            R.string.contextmenu_call, // Item.CALL:
            R.string.contextmenu_send_message, // Item.SEND_MESSAGE:
            R.string.contextmenu_add_to_contacts, // Item.ADD_TO_CONTACTS:
            R.string.contextmenu_copy, // Item.COPY:
            R.string.contextmenu_save_video, // Item.SAVE_VIDEO:
            R.string.menu_open_in_chrome, // Item.OPEN_IN_CHROME:
            R.string.contextmenu_share_highlight, // Item.SHARE_HIGHLIGHT
            R.string.contextmenu_remove_highlight, // Item.REMOVE_HIGHLIGHT
            R.string.contextmenu_learn_more, // Item.LEARN_MORE
    };

    /**
     * Returns the menu id for a given {@link @Item}.
     * @param item The {@link @Item}.
     * @return Menu id associated with the {@code item}.
     */
    public static int getMenuId(@Item int item) {
        assert MENU_IDS.length == Item.NUM_ENTRIES;
        return MENU_IDS[item];
    }

    /**
     * Get string ID from the ID of the item.
     * @param context The activity context.
     * @param item #Item Item ID.
     * @return Returns the string that describes the action of the item.
     */
    private static @StringRes int getStringId(Context context, @Item int item) {
        assert STRING_IDS.length == Item.NUM_ENTRIES;

        return STRING_IDS[item];
    }

    /**
     * Transforms the id of the item into a string. It manages special cases that need minor
     * changes due to templating.
     * @param context Requires to get the string resource related to the item.
     * @param item Context menu item id.
     * @param showInProductHelp Whether the menu item should show the new superscript label.
     * @return Returns a string for the menu item.
     */
    public static CharSequence getTitle(
            Context context, @Item int item, boolean showInProductHelp) {
        switch (item) {
            case Item.OPEN_IN_BROWSER_ID:
                return DefaultBrowserInfo.getTitleOpenInDefaultBrowser(false);
            case Item.SEARCH_BY_IMAGE:
                return context.getString(getStringId(context, item),
                        TemplateUrlServiceFactory.getForProfile(Profile.getLastUsedRegularProfile())
                                .getDefaultSearchEngineTemplateUrl()
                                .getShortName());
            case Item.READ_LATER:
                return addOrRemoveNewLabel(context, item, null, showInProductHelp);
            case Item.OPEN_IN_EPHEMERAL_TAB:
                return addOrRemoveNewLabel(context, item,
                        ChromePreferenceKeys.CONTEXT_MENU_OPEN_IN_EPHEMERAL_TAB_CLICKED,
                        showInProductHelp);
            case Item.OPEN_IMAGE_IN_EPHEMERAL_TAB:
                return addOrRemoveNewLabel(context, item,
                        ChromePreferenceKeys.CONTEXT_MENU_OPEN_IMAGE_IN_EPHEMERAL_TAB_CLICKED,
                        showInProductHelp);
            case Item.SEARCH_WITH_GOOGLE_LENS:
                return addOrRemoveNewLabel(context, item,
                        ChromePreferenceKeys.CONTEXT_MENU_SEARCH_WITH_GOOGLE_LENS_CLICKED,
                        showInProductHelp);
            case Item.SHOP_IMAGE_WITH_GOOGLE_LENS:
                return addOrRemoveNewLabel(context, item,
                        ChromePreferenceKeys.CONTEXT_MENU_SHOP_IMAGE_WITH_GOOGLE_LENS_CLICKED,
                        showInProductHelp);
            default:
                return context.getString(getStringId(context, item));
        }
    }

    /**
     * Modify the menu title by applying span attributes or removing the 'New' label if the menu
     * has already been selected before.
     */
    private static CharSequence addOrRemoveNewLabel(
            Context context, @Item int item, @Nullable String prefKey, boolean showNewLabel) {
        String menuTitle = context.getString(getStringId(context, item));
        if (!showNewLabel
                || (prefKey != null
                        && SharedPreferencesManager.getInstance().readBoolean(prefKey, false))) {
            return SpanApplier.removeSpanText(menuTitle, new SpanInfo("<new>", "</new>"));
        }
        return SpanApplier.applySpans(menuTitle,
                new SpanInfo("<new>", "</new>", new SuperscriptSpan(), new RelativeSizeSpan(0.75f),
                        new ForegroundColorSpan(
                                SemanticColorUtils.getDefaultTextColorAccent1(context))));
    }
}
