/*******************************************************************************
 * Copyright (c) 2012, 2018 Red Hat, Inc.
 * 
 * This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License 2.0
 * which is available at https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *    Red Hat initial API and implementation
 *******************************************************************************/
package org.eclipse.linuxtools.internal.profiling.launch.provider.launch;

import java.text.MessageFormat;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.cdt.core.model.IBinary;
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExecutableExtension;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationType;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.ui.ILaunchConfigurationDialog;
import org.eclipse.debug.ui.ILaunchConfigurationTab;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.linuxtools.internal.profiling.launch.provider.ProviderProfileConstants;
import org.eclipse.linuxtools.profiling.launch.ProfileLaunchConfigurationTabGroup;
import org.eclipse.linuxtools.profiling.launch.ProfileLaunchShortcut;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.MessageBox;

public class ProviderLaunchShortcut extends ProfileLaunchShortcut implements IExecutableExtension {

    // Profiling type.
    private String type;

    // Launch configuration type id.
    private String launchConfigId;

    @Override
    public void setInitializationData(IConfigurationElement config,
            String propertyName, Object data) {
        @SuppressWarnings("unchecked")
        Map<String, String> parameters = (Map<String, String>) data;
        String profilingType = parameters
                .get(ProviderProfileConstants.INIT_DATA_TYPE_KEY);
        String configId = parameters
                .get(ProviderProfileConstants.INIT_DATA_CONFIG_ID_KEY);

        if (profilingType == null) {
            profilingType = ""; //$NON-NLS-1$
        }
        if (configId == null) {
            configId = ""; //$NON-NLS-1$
        }

        setLaunchConfigID(configId);
        setProfilingType(profilingType);
    }

    @Override
    protected ILaunchConfigurationType getLaunchConfigType() {
        return getLaunchManager().getLaunchConfigurationType(getLaunchConfigID());
    }

    @Override
    protected ILaunchConfiguration findLaunchConfiguration(IBinary bin, String mode) {

        // create a default launch configuration based on the shortcut
        ILaunchConfiguration config = createConfiguration(bin, false);

        String providerId = null;
        try {
            providerId = ProviderFramework.getProviderIdToRun(config.getWorkingCopy(), type);
        } catch (CoreException e1) {
            e1.printStackTrace();
        }

        // check that there exists a provider for the given profiling type
        if (providerId == null) {
            handleFail(Messages.ProviderLaunchShortcut_0 + " " + type); //$NON-NLS-1$
            return null;
        }

        // true if a configuration exists for current project and program
        boolean existsConfigForProject = false;

        // true if a configuration exists for current project, program and
        // the default provider
        boolean existsConfigForTool = false;

        try {
            String projectName = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, ""); //$NON-NLS-1$
            String programName = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, ""); //$NON-NLS-1$
            ILaunchConfiguration[] configs = getLaunchManager().getLaunchConfigurations(getLaunchConfigType());

            for(ILaunchConfiguration currConfig : configs){
                String curProjectName = currConfig.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, ""); //$NON-NLS-1$
                String curProgramName = currConfig.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, ""); //$NON-NLS-1$

                // check that current configuration belongs to the current project/program
                if(curProjectName.equals(projectName) && curProgramName.equals(programName)){
                    existsConfigForProject = true;
                    String curProviderId = currConfig.getAttribute(ProviderProfileConstants.PROVIDER_CONFIG_ATT, ""); //$NON-NLS-1$

                    // check that current configuration has the same provider as the provider to run.
                    if(curProviderId.equals(providerId)){
                        existsConfigForTool = true;
                        break;
                    }
                }
            }
        } catch (CoreException e) {
            // a configuration might be corrupted, skip prompting logic
            // and fall back to default behavior
            existsConfigForProject = true;
            existsConfigForTool = true;
        }

        // automatically create a configuration if there are none available for
        // the current project/program
        if (!existsConfigForProject) {
            createConfiguration(bin);
        } else if (!existsConfigForTool) {
            String provider = ProviderFramework
                    .getProviderToolNameFromId(providerId);

            String profileType = Character.toUpperCase(type.charAt(0))
                    + type.substring(1);

            // prompt message
			String promptMsg = MessageFormat.format(Messages.ProviderLaunchConfigurationPrompt_0, profileType,
					provider);

            MessageBox prompt = new MessageBox(getActiveWorkbenchShell(),
                    SWT.ICON_QUESTION | SWT.YES | SWT.NO);
            prompt.setMessage(promptMsg);

            // prompt user for configuration creation
            if (prompt.open() == SWT.YES) {
                return createConfiguration(bin);
            }
        }
        return super.findLaunchConfiguration(bin, mode);
    }

    @Override
    protected void setDefaultProfileAttributes(ILaunchConfigurationWorkingCopy wc) {

        // acquire a provider id to run.
        final String providerId = ProviderFramework.getProviderIdToRun(wc, getProfilingType());

        // get tool name from id.
        final String providerToolName = ProviderFramework.getProviderToolNameFromId(providerId);

        // get tab group associated with provider id.
        final ProfileLaunchConfigurationTabGroup tabgroup = ProviderFramework.getTabGroupProviderFromId(providerId);

        /**
         * Certain tabs' setDefaults(ILaunchConfigurationWorkingCopy) may
         * require a launch configuration dialog. Eg. CMainTab generates
         * a name for the configuration based on generateName in setDefaults()
         * so we can create a temporary launch configuration dialog here. With
         * the exception of generateName(String), the other methods do not
         * get called.
         */
        ILaunchConfigurationDialog dialog  = new ILaunchConfigurationDialog() {

            @Override
            public void run(boolean fork, boolean cancelable,
                    IRunnableWithProgress runnable) {
                throw new UnsupportedOperationException ();
            }

            @Override
            public void updateMessage() {
                throw new UnsupportedOperationException ();
            }

            @Override
            public void updateButtons() {
                throw new UnsupportedOperationException ();
            }

            @Override
            public void setName(String name) {
                throw new UnsupportedOperationException ();
            }

            @Override
            public void setActiveTab(int index) {
                throw new UnsupportedOperationException ();
            }

            @Override
            public void setActiveTab(ILaunchConfigurationTab tab) {
                throw new UnsupportedOperationException ();
            }

            @Override
            public ILaunchConfigurationTab[] getTabs() {
                return null;
            }

            @Override
            public String getMode() {
                return null;
            }

            @Override
            public ILaunchConfigurationTab getActiveTab() {
                return null;
            }

            @Override
            public String generateName(String name) {
                if (name == null) {
                    name = ""; //$NON-NLS-1$
                }
                String providerConfigutationName = generateProviderConfigurationName(name, providerToolName);
                return getLaunchManager().generateLaunchConfigurationName(providerConfigutationName);
            }
        };

        tabgroup.createTabs(dialog , "profile"); //$NON-NLS-1$

        // set configuration to match default attributes for all tabs.
        for (ILaunchConfigurationTab tab : tabgroup.getTabs()) {
            tab.setLaunchConfigurationDialog(dialog);
            tab.setDefaults(wc);
        }

        // get configuration shortcut associated with provider id.
        ProfileLaunchShortcut shortcut= ProviderFramework.getLaunchShortcutProviderFromId(providerId);
        // set attributes related to the specific profiling shortcut configuration.
        shortcut.setDefaultProfileLaunchShortcutAttributes(wc);

        wc.setAttribute(ProviderProfileConstants.PROVIDER_CONFIG_ATT,
                providerId);

        // set tool name in configuration.
        wc.setAttribute(ProviderProfileConstants.PROVIDER_CONFIG_TOOLNAME_ATT, providerToolName);

        /**
         * To avoid renaming an already renamed launch configuration, we can
         * check the expected format of the name using regular expressions and
         * skip on matches.
         */
        String curConfigName = wc.getName();
        Pattern configNamePattern = Pattern.compile(".+\\s\\[.+\\](\\s\\(\\d+\\))?$"); //$NON-NLS-1$
        Matcher match = configNamePattern.matcher(curConfigName);
        if (!match.find()) {
            wc.rename(dialog.generateName(curConfigName));
        }
    }

    /**
     * Get name of profiling type that used for this tab.
     *
     * @param profilingType The type of profiling.
     */
    private void setProfilingType(String profilingType) {
        type = profilingType;
    }
    /**
     * Set launch configuration type id.
     *
     * @param configId String configuration type id.
     */
    private void setLaunchConfigID(String configId) {
        launchConfigId = configId;
    }

    /**
     * Get profiling type of this plug-in.
     *
     * @return String profiling type this plug-in supports.
     */
    private String getLaunchConfigID() {
        return launchConfigId;
    }

    public String getProfilingType() {
        return type;
    }

    /**
     * Generate a string that can be used as a name for a provider launch configuration.
     * It combines <code>configName</code> and <code>toolName</code> into a String of
     * consistent format: <configuration name> [<tool name>].
     *
     * @param configName The configuration name.
     * @param toolName The tool name.
     * @return String Tool name appended to original configuration name.
     * @since 1.2
     */
    public static String generateProviderConfigurationName(String configName, String toolName){
        return configName + " " + "[" + toolName + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    }

}
