/*******************************************************************************
 * Copyright (c) 2000, 2015 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.ui.internal;

import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ActionContributionItem;
import org.eclipse.jface.action.IAction;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IPluginContribution;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
import org.eclipse.ui.plugin.AbstractUIPlugin;

/**
 * When 'action' tag is found in the registry, an object of this
 * class is created. It creates the appropriate action object
 * and captures information that is later used to add this action
 * object into menu/tool bar. This class is reused for
 * global (workbench) menu/tool bar, popup menu actions,
 * as well as view's pulldown and local tool bar.
 */
public class ActionDescriptor implements IPluginContribution {
    private PluginAction action;

    private String toolbarId;

    private String menuPath;

    private String id;

    private String pluginId;

    private String menuGroup;

    private String toolbarGroupId;

	private int mode = 0;

    /**
     * Popup constant.  Value <code>0x1</code>.
     */
    public static final int T_POPUP = 0x1;

    /**
     * View constant.  Value <code>0x2</code>.
     */
    public static final int T_VIEW = 0x2;

    /**
     * Workbench constant.  Value <code>0x3</code>.
     */
    public static final int T_WORKBENCH = 0x3;

    /**
     * Editor constant.  Value <code>0x4</code>.
     */
    public static final int T_EDITOR = 0x4;

    /**
     * Workbench pulldown constant.  Value <code>0x5</code>.
     */
    public static final int T_WORKBENCH_PULLDOWN = 0x5;

    /**
     * Push style constant.  Value <code>push</code>.
     */
    public static final String STYLE_PUSH = "push"; //$NON-NLS-1$

    /**
     * Radio style constant.  Value <code>radio</code>.
     */
    public static final String STYLE_RADIO = "radio"; //$NON-NLS-1$

    /***
     * Toggle style constant.  Value <code>toggle</code>.
     */
    public static final String STYLE_TOGGLE = "toggle"; //$NON-NLS-1$

    /**
     * Pulldown style constant.  Value <code>pulldown</code>.
     */
    public static final String STYLE_PULLDOWN = "pulldown"; //$NON-NLS-1$

    /**
     * Creates a new descriptor with the specified target.
     *
     * @param actionElement the configuration element
     * @param targetType the type of action
     */
    public ActionDescriptor(IConfigurationElement actionElement, int targetType) {
        this(actionElement, targetType, null);
    }

    /**
     * Creates a new descriptor with the target and destination workbench part
     * it will go into.
     *
     * @param actionElement the configuration element
     * @param targetType the type of action
     * @param target the target object
     */
    public ActionDescriptor(IConfigurationElement actionElement,
            int targetType, Object target) {
        // Load attributes.
        id = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
		pluginId = actionElement.getContributor().getName();
        String label = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_LABEL);
        String tooltip = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_TOOLTIP);
        String helpContextId = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_HELP_CONTEXT_ID);
        String mpath = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_MENUBAR_PATH);
        String tpath = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_TOOLBAR_PATH);
        String style = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_STYLE);
        String icon = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_ICON);
        String hoverIcon = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_HOVERICON);
        String disabledIcon = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_DISABLEDICON);
        String description = actionElement.getAttribute(IWorkbenchRegistryConstants.TAG_DESCRIPTION);
        String accelerator = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_ACCELERATOR);
        if ("FORCE_TEXT".equals(actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_MODE))) { //$NON-NLS-1$
        	mode  = ActionContributionItem.MODE_FORCE_TEXT;
        }

        // Verify input.
        if (label == null) {
            WorkbenchPlugin
                    .log("Invalid action declaration (label == null): " + id); //$NON-NLS-1$
            label = WorkbenchMessages.ActionDescriptor_invalidLabel;
        }

        // Calculate menu and toolbar paths.
        String mgroup = null;
        String tgroup = null;
        if (mpath != null) {
            int loc = mpath.lastIndexOf('/');
            if (loc != -1) {
                mgroup = mpath.substring(loc + 1);
                mpath = mpath.substring(0, loc);
            } else {
                mgroup = mpath;
                mpath = null;
            }
        }
        if (targetType == T_POPUP && mgroup == null) {
			mgroup = IWorkbenchActionConstants.MB_ADDITIONS;
		}
        if (tpath != null) {
            int loc = tpath.lastIndexOf('/');
            if (loc != -1) {
                tgroup = tpath.substring(loc + 1);
                tpath = tpath.substring(0, loc);
            } else {
                tgroup = tpath;
                tpath = null;
            }
        }
        menuPath = mpath;
        menuGroup = mgroup;
        if ((tpath != null) && tpath.equals("Normal")) { //$NON-NLS-1$
			tpath = ""; //$NON-NLS-1$
		}
        toolbarId = tpath;
        toolbarGroupId = tgroup;

        // Create action.
        action = createAction(targetType, actionElement, target, style);
        if (action.getText() == null) {
			action.setText(label);
		}
        if (action.getToolTipText() == null && tooltip != null) {
			action.setToolTipText(tooltip);
		}
        if (helpContextId != null) {
            String fullID = helpContextId;
            if (helpContextId.indexOf('.') == -1) {
				// For backward compatibility we auto qualify the id if it is not
                // qualified)
				fullID = actionElement.getContributor().getName()
                        + "." + helpContextId;//$NON-NLS-1$
			}
            PlatformUI.getWorkbench().getHelpSystem().setHelp(action, fullID);
        }
        if (description != null) {
			action.setDescription(description);
		}

        if (style != null) {
            // Since 2.1, the "state" and "pulldown" attributes means something different
            // when the new "style" attribute has been set. See doc for more info.
            String state = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_STATE);
            if (state != null) {
                if (style.equals(STYLE_RADIO) || style.equals(STYLE_TOGGLE)) {
					action.setChecked(state.equals("true"));//$NON-NLS-1$
				}
            }
        } else {
            // Keep for backward compatibility for actions not using the
            // new style attribute.
            String state = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_STATE);
            if (state != null) {
                action.setChecked(state.equals("true"));//$NON-NLS-1$
            }
        }

        String extendingPluginId = actionElement.getDeclaringExtension()
				.getContributor().getName();

        if (icon != null) {
            action.setImageDescriptor(AbstractUIPlugin
                    .imageDescriptorFromPlugin(extendingPluginId, icon));
        }
        if (hoverIcon != null) {
            action.setHoverImageDescriptor(AbstractUIPlugin
                    .imageDescriptorFromPlugin(extendingPluginId, hoverIcon));
        }
        if (disabledIcon != null) {
            action
                    .setDisabledImageDescriptor(AbstractUIPlugin
                            .imageDescriptorFromPlugin(extendingPluginId,
                                    disabledIcon));
        }

        if (accelerator != null) {
			processAccelerator(action, accelerator);
		}
    }

    /**
     * Creates an instance of PluginAction. Depending on the target part,
     * subclasses of this class may be created.
     */
    private PluginAction createAction(int targetType,
            IConfigurationElement actionElement, Object target, String style) {
        int actionStyle = IAction.AS_UNSPECIFIED;
        if (style != null) {
            if (style.equals(STYLE_RADIO)) {
                actionStyle = IAction.AS_RADIO_BUTTON;
            } else if (style.equals(STYLE_TOGGLE)) {
                actionStyle = IAction.AS_CHECK_BOX;
            } else if (style.equals(STYLE_PULLDOWN)) {
                actionStyle = IAction.AS_DROP_DOWN_MENU;
            } else if (style.equals(STYLE_PUSH)) {
                actionStyle = IAction.AS_PUSH_BUTTON;
            }
        }

        switch (targetType) {
        case T_VIEW:
            return new ViewPluginAction(actionElement, (IViewPart) target, id,
                    actionStyle);
        case T_EDITOR:
            return new EditorPluginAction(actionElement, (IEditorPart) target,
                    id, actionStyle);
        case T_WORKBENCH:
            return new WWinPluginAction(actionElement,
                    (IWorkbenchWindow) target, id, actionStyle);
        case T_WORKBENCH_PULLDOWN:
            actionStyle = IAction.AS_DROP_DOWN_MENU;
            return new WWinPluginPulldown(actionElement,
                    (IWorkbenchWindow) target, id, actionStyle);
        case T_POPUP:
            return new ObjectPluginAction(actionElement, id, actionStyle);
        default:
            WorkbenchPlugin.log("Unknown Action Type: " + targetType);//$NON-NLS-1$
            return null;
        }
    }

    /**
     * Returns the action object held in this descriptor.
     *
     * @return the action
     */
    public PluginAction getAction() {
        return action;
    }

    /**
     * Returns action's id as defined in the registry.
     *
     * @return the id
     */
    public String getId() {
        return id;
    }

    /**
     * Returns named slot (group) in the menu where this action
     * should be added.
     *
     * @return the menu group
     */
    public String getMenuGroup() {
        return menuGroup;
    }

    /**
     * Returns menu path where this action should be added. If null,
     * the action will not be added into the menu.
     *
     * @return the menubar path
     */
    public String getMenuPath() {
        return menuPath;
    }

    /**
     * Returns the named slot (group) in the tool bar where this
     * action should be added.
     *
     * @return the toolbar group id
     */
    public String getToolbarGroupId() {
        return toolbarGroupId;
    }

    /**
     * Returns id of the tool bar where this action should be added.
     * If null, action will not be added to the tool bar.
     *
     * @return the toolbar id
     */
    public String getToolbarId() {
        return toolbarId;
    }

    /**
     * For debugging only.
     */
    @Override
	public String toString() {
        return "ActionDescriptor(" + id + ")";//$NON-NLS-2$//$NON-NLS-1$
    }

    /**
     * Process the accelerator definition. If it is a number
     * then process the code directly - if not then parse it
     * and create the code
     */
    private void processAccelerator(IAction action, String acceleratorText) {

        if (acceleratorText.length() == 0) {
			return;
		}

        //Is it a numeric definition?
        if (Character.isDigit(acceleratorText.charAt(0))) {
            try {
                action.setAccelerator(Integer.valueOf(acceleratorText)
                        .intValue());
            } catch (NumberFormatException e) {
                WorkbenchPlugin.log("Invalid accelerator declaration for action: " + id, e); //$NON-NLS-1$
            }
        } else {
			action.setAccelerator(Action.convertAccelerator(acceleratorText));
		}
    }

    @Override
	public String getLocalId() {
        return getId();
    }

    @Override
	public String getPluginId() {
        return pluginId;
    }

    public int getMode() {
    	return mode;
    }
}
