/*******************************************************************************
 * Copyright (c) 2012, 2018 IBM Corporation and others.
 * 
 * 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:
 *     IBM Corporation - initial API and implementation
 ******************************************************************************/

package org.eclipse.linuxtools.profiling.launch.ui;

import java.util.Iterator;
import java.util.LinkedList;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.linuxtools.internal.profiling.launch.ProfileLaunchPlugin;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;

/**
 * FileSystemSelectionArea is the area used to select the file system.
 *
 * @since 2.0
 *
 */
public class FileSystemSelectionArea {

    private Label fileSystemTitle;
    private ComboViewer fileSystems;

    private static final String EXTENSION_POINT_ID = "RemoteResourceSelectorProxy"; //$NON-NLS-1$
    private static final String RESOURCE_SELECTOR_PROXY_NAME = "resourceSelectorProxy"; //$NON-NLS-1$
    private static final String SCHEME_ID = "scheme"; //$NON-NLS-1$
    private static final String SCHEME_LABEL_ID = "schemeLabel"; //$NON-NLS-1$
    private static final String IS_DEFAULT_ID = "isDefault"; //$NON-NLS-1$
    private static final String EXT_ATTR_CLASS = "class"; //$NON-NLS-1$

    private LinkedList<FileSystemElement> fsElements;

    /**
     * Create a new instance of the receiver.
     */
    public FileSystemSelectionArea(){
    }

    private FileSystemElement[] getSchemes() {
        if (fsElements == null) {
            fsElements = new LinkedList<>();

            // Add all of the ones declared by the registry.
            IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(ProfileLaunchPlugin.PLUGIN_ID, EXTENSION_POINT_ID);
            IConfigurationElement[] infos = extensionPoint.getConfigurationElements();
            for (int i = 0; i < infos.length; i++) {
                IConfigurationElement configurationElement = infos[i];
                if (configurationElement.getName().equals(RESOURCE_SELECTOR_PROXY_NAME)) {
                    IRemoteResourceSelectorProxy remoteSelector = null;
                    try {
                        Object obj = configurationElement.createExecutableExtension(EXT_ATTR_CLASS);
                        if (obj instanceof IRemoteResourceSelectorProxy) {
                            remoteSelector = (IRemoteResourceSelectorProxy)obj;
                        }
                    } catch (CoreException e) {
                        ProfileLaunchPlugin.log(IStatus.ERROR, ResourceSelectorWidgetMessages.FileSystemSelectionArea_exception_while_creating_runnable_class + configurationElement.getAttribute(EXT_ATTR_CLASS), e);
                    }
                    FileSystemElement element = new FileSystemElement(
                            configurationElement.getAttribute(SCHEME_ID),
                            configurationElement.getAttribute(SCHEME_LABEL_ID),
                            Boolean.valueOf(configurationElement.getAttribute(IS_DEFAULT_ID)),
                            remoteSelector);
                    fsElements.addLast(element);
                }
            }
        }
        return fsElements.toArray(new FileSystemElement[fsElements.size()]);
    }

    /**
     * Create the contents of the receiver in composite.
     * @param composite Parent composite for created components.
     */
    public void createContents(Composite composite) {

        fileSystemTitle = new Label(composite, SWT.NONE);
        fileSystemTitle.setText(ResourceSelectorWidgetMessages.fileSystemSelectionText);
        fileSystemTitle.setFont(composite.getFont());

        fileSystems = new ComboViewer(composite, SWT.READ_ONLY);
        fileSystems.getControl().setFont(composite.getFont());

        fileSystems.setLabelProvider(new LabelProvider() {
            @Override
            public String getText(Object element) {
                return ((FileSystemElement)element).getSchemeLabel();
            }
        });

        fileSystems.setContentProvider(new IStructuredContentProvider() {

            @Override
            public void dispose() {
                // Nothing to do
            }

            @Override
            public Object[] getElements(Object inputElement) {
                return getSchemes();
            }

            @Override
            public void inputChanged(org.eclipse.jface.viewers.Viewer viewer,
                    Object oldInput, Object newInput) {
                // Nothing to do
            }
        });

        fileSystems.setInput(this);
        Iterator<FileSystemElement> fsEltItr = fsElements.iterator();
        boolean foundDefault = false;
        while (fsEltItr.hasNext()) {
            FileSystemElement fsElt = fsEltItr.next();
            if (fsElt.getIsDefault()) {
                if (foundDefault) {
                    ProfileLaunchPlugin.log(IStatus.WARNING, ResourceSelectorWidgetMessages.FileSystemSelectionArea_found_multiple_default_extensions + fsElt.getScheme());
                    // use only the first one we found marked as default
                    continue;
                }
                fileSystems.setSelection(new StructuredSelection(fsElt));
                foundDefault = true;
            }
        }
    }

    /**
     * Return the selected file system.
     * @return FileSystemElement or <code>null</code> if nothing
     * is selected.
     */
	public FileSystemElement getSelectedFileSystem() {
		IStructuredSelection selection = fileSystems.getStructuredSelection();

		if (selection.size() == 1) {
			return ((FileSystemElement) selection.getFirstElement());
		}
		return null;
	}

    /**
     * Set the filesystem selection combo box to the specified scheme.
     *
     * @param scheme name of scheme, e.g. "rse"
     * @throws CoreException If scheme is illegal.
     */
    public void setSelectedFileSystem(String scheme) throws CoreException {
        Iterator<FileSystemElement> fsEltItr = fsElements.iterator();
        boolean foundMatch = false;
        while (fsEltItr.hasNext()) {
            FileSystemElement fsElt = fsEltItr.next();
            if (fsElt.getScheme().equalsIgnoreCase(scheme)) {
                foundMatch = true;
                fileSystems.setSelection(new StructuredSelection(fsElt));
                break;
            }
        }
        if (!foundMatch) {
            throw new CoreException(new Status(IStatus.ERROR, ProfileLaunchPlugin.PLUGIN_ID, IStatus.OK,
                    ResourceSelectorWidgetMessages.FileSystemSelectionArea_unrecognized_scheme + scheme, null));
        }
    }


    /**
     * Set the enablement state of the widget.
     * @param enabled The new state to be set.
     */
    public void setEnabled(boolean enabled) {
        fileSystemTitle.setEnabled(enabled);
        fileSystems.getControl().setEnabled(enabled);
    }
}
