/*******************************************************************************
 * Copyright (c) 2016 Movidius Inc. and others
 *
 * All rights reserved. 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:
 *   Robert Kiss - Initial API and implementation
 *   Mikael Ferland - Enable resizing of symbol provider dialogs
 *
 *******************************************************************************/

package org.eclipse.tracecompass.tmf.ui.symbols;

import java.lang.reflect.InvocationTargetException;

import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.preference.IPreferencePageContainer;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.tracecompass.internal.tmf.ui.symbols.Messages;
import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;

/**
 * This class shall be used to configure one or more {@link ISymbolProvider}. It
 * receives an array of {@link ISymbolProviderPreferencePage} and creates a
 * dialog that can be used to configure the corresponding providers. If the
 * {@link #open()} method exits with {@link IDialogConstants#OK_ID} the caller
 * shall assume that the corresponding {@link ISymbolProvider}'s have a new
 * configuration.
 *
 *
 * @author Robert Kiss
 * @since 2.0
 */
public class SymbolProviderConfigDialog extends TitleAreaDialog implements IPreferencePageContainer {

    private ISymbolProviderPreferencePage[] fPreferencePages;
    private CTabItem[] fPageTabs;
    private CTabFolder fTabFolder;

    private IRunnableWithProgress configJob = (monitor) -> {
        // saving the configuration is fast and need UI access
        SymbolProviderConfigDialog.this.getContents().getDisplay().syncExec(() -> {
            for (int i = 0; i < fPreferencePages.length; i++) {
                ISymbolProviderPreferencePage page = fPreferencePages[i];
                page.saveConfiguration();
            }
        });
        monitor.beginTask(Messages.SymbolProviderConfigDialog_loadingConfigurations, fPreferencePages.length * 100);
        try {
            for (int i = 0; i < fPreferencePages.length; i++) {
                ISymbolProviderPreferencePage page = fPreferencePages[i];
                page.getSymbolProvider().loadConfiguration(monitor);
                monitor.worked(100);
            }
        } finally {
            monitor.done();
        }
    };

    /**
     * Create a new dialog that will use the given shall and preference pages.
     *
     * @param parentShell
     *            The parent shell
     * @param pages
     *            the pages that provides the configuration UI for
     *            {@link ISymbolProvider}'s. The array shall not be empty and
     *            shall not contain null elements.
     *
     */
    public SymbolProviderConfigDialog(Shell parentShell, ISymbolProviderPreferencePage... pages) {
        super(parentShell);
        fPreferencePages = pages;
    }

    @Override
    protected Control createDialogArea(Composite parent) {
        getShell().setText(Messages.SymbolProviderConfigDialog_title);
        setTitle(Messages.SymbolProviderConfigDialog_title);
        setMessage(Messages.SymbolProviderConfigDialog_message);

        Composite composite = (Composite) super.createDialogArea(parent);
        composite.setLayout(new GridLayout());

        // if we have one single provider that we don't need a tab
        if (fPreferencePages.length == 1) {
            attachPreference(composite, fPreferencePages[0]);
            updateMessage(0);
        } else {
            fTabFolder = new CTabFolder(composite, SWT.NONE);
            fTabFolder.setLayoutData(new GridData(GridData.FILL_BOTH));
            fPageTabs = new CTabItem[fPreferencePages.length];
            for (int i = 0; i < fPreferencePages.length; i++) {
                ISymbolProviderPreferencePage page = fPreferencePages[i];
                fPageTabs[i] = new CTabItem(fTabFolder, SWT.NONE);
                fPageTabs[i].setText(page.getTitle());
                Composite child = new Composite(fTabFolder, SWT.NONE);
                child.setLayout(new GridLayout());
                child.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, true));
                fPageTabs[i].setControl(child);
                attachPreference(child, page);
                updateMessage(i);
            }
            fTabFolder.addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(SelectionEvent e) {
                    updateMessage(fTabFolder.indexOf((CTabItem) e.item));
                }
            });
        }
        return composite;
    }

    @Override
    protected boolean isResizable() {
        return true;
    }

    @Override
    public boolean isHelpAvailable() {
        return false;
    }

    private void attachPreference(Composite composite, ISymbolProviderPreferencePage page) {
        page.setContainer(this);
        page.createControl(composite);
        page.getControl().setLayoutData(new GridData(GridData.FILL_BOTH));
    }

    @Override
    public IPreferenceStore getPreferenceStore() {
        // not used
        return null;
    }

    @Override
    public void updateTitle() {
        // not used
    }

    @Override
    public void updateButtons() {
        // nothing to do
    }

    @Override
    protected void okPressed() {
        boolean cancel = false;
        try {
            new ProgressMonitorDialog(getShell()).run(true, false, configJob);
        } catch (InvocationTargetException e) {
            setMessage(e.getMessage(), IMessageProvider.ERROR);
            cancel = true;
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        if (!cancel) {
            super.okPressed();
        }
        TmfSignalManager.dispatchSignal(new TmfSymbolProviderUpdatedSignal(this));
    }

    @Override
    public void updateMessage() {
        if (fTabFolder == null) {
            updateMessage(0);
            return;
        }
        int curSelectionIndex = fTabFolder.getSelectionIndex();
        if (curSelectionIndex >= 0) {
            updateMessage(curSelectionIndex);
        }
    }

    private void updateMessage(int pageIndex) {
        ISymbolProviderPreferencePage currentPage = fPreferencePages[pageIndex];
        String message = currentPage.getMessage();
        String errorMessage = currentPage.getErrorMessage();
        int messageType = IMessageProvider.NONE;

        if (errorMessage != null) {
            message = errorMessage;
            messageType = IMessageProvider.ERROR;
        }
        setMessage(message, messageType);

        if (fPreferencePages.length > 1) {
            // update the corresponding tab icon
            if (messageType == IMessageProvider.ERROR) {
                fPageTabs[pageIndex].setImage(PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJS_ERROR_TSK));
            } else {
                fPageTabs[pageIndex].setImage(null);
            }
        }
    }

}
