/*******************************************************************************
 * Copyright (c) 2015-2020 The University of York, Aston University.
 * 
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the Eclipse
 * Public License, v. 2.0 are satisfied: GNU General Public License, version 3.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-3.0
 *
 * Contributors:
 *     Antonio Garcia-Dominguez - initial API and implementation
 ******************************************************************************/
package org.eclipse.hawk.ui2.dialog;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.Platform;
import org.eclipse.hawk.core.IVcsManager;
import org.eclipse.hawk.osgiserver.HModel;
import org.eclipse.hawk.ui2.Activator;
import org.eclipse.hawk.ui2.dialog.HConfigDialog.VCSLabelProvider;
import org.eclipse.hawk.ui2.vcs.DefaultVcsConfigurationBlock;
import org.eclipse.hawk.ui2.vcs.IVcsConfigurationBlock;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.SWT;
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.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;

public class HVCSDialog extends TitleAreaDialog {

	private final IVcsManager managerToEdit;
	private final HModel hawkModel;

	private Button freeze;
	private ComboViewer cmbVCSType;
	private List<IVcsManager> availableVCS;

	private Composite cmpConfiguration;
	private IVcsConfigurationBlock configBlock;

	public HVCSDialog(Shell parentShell, HModel hawkModel, IVcsManager managerToEdit) {
		super(parentShell);
		this.hawkModel = hawkModel;
		this.managerToEdit = managerToEdit;

		this.availableVCS = hawkModel.getVCSInstances();
		Collections.sort(availableVCS, new Comparator<IVcsManager>() {
			@Override
			public int compare(IVcsManager o1, IVcsManager o2) {
				return o1.getHumanReadableName().compareTo(o2.getHumanReadableName());
			}
		});
	}

	@Override
	public void create() {
		super.create();
		if (managerToEdit == null) {
			setTitle("Add repository");
			setMessage("Select the repository type and configure its options.");
		} else {
			setTitle("Edit repository");
			setMessage("Change the authentication credentials.");
		}
	}

	@Override
	protected Control createDialogArea(Composite parent) {
		final Composite area = (Composite) super.createDialogArea(parent);
		final Composite container = new Composite(area, SWT.NONE);
		container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
		final GridLayout containerLayout = new GridLayout();
		containerLayout.numColumns = 3;
		container.setLayout(containerLayout);

		// Type
		final Label lblType = new Label(container, SWT.NONE);
		lblType.setText("Type:");
		cmbVCSType = new ComboViewer(container, SWT.READ_ONLY);
		cmbVCSType.setLabelProvider(new VCSLabelProvider());
		cmbVCSType.setContentProvider(new ArrayContentProvider());
		
		cmbVCSType.setInput(availableVCS.toArray());

		final GridData cmbVCSTypeLayoutData = new GridData(SWT.FILL, SWT.CENTER, true, false);
		cmbVCSTypeLayoutData.horizontalSpan = 2;
		cmbVCSType.getCombo().setLayoutData(cmbVCSTypeLayoutData);
		cmbVCSType.getCombo().addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				updateConfigurationBlock();
			}
		});

		final Label lblFreeze = new Label(container, SWT.NONE);
		lblFreeze.setText("Freeze repo:");
		freeze = new Button(container, SWT.CHECK);
		boolean isFrozen = managerToEdit == null ? false : managerToEdit.isFrozen();
		freeze.setSelection(isFrozen);
		if (managerToEdit == null) {
			freeze.setEnabled(false);
		}

		// Placeholder container for the VCS configuration block
		cmpConfiguration = new Composite(container, SWT.FILL | SWT.BORDER);
		final GridData cmpConfigurationLD = new GridData(SWT.FILL, SWT.CENTER, true, false);
		cmpConfigurationLD.horizontalSpan = 3;
		cmpConfiguration.setLayoutData(cmpConfigurationLD);

		if (managerToEdit != null) {
			final String managerType = managerToEdit.getType();
			int i = 0;
			for (IVcsManager kind : availableVCS) {
				final String availableType = kind.getType();
				if (availableType.equals(managerType)) {
					cmbVCSType.getCombo().select(i);
					break;
				}
				i++;
			}
			cmbVCSType.getCombo().setEnabled(false);
		} else {
			cmbVCSType.getCombo().select(0);
		}
		updateConfigurationBlock();

		return container;
	}

	public IVcsManager getManagerToEdit() {
		return managerToEdit;
	}

	private void updateConfigurationBlock() {
		for (Control child : cmpConfiguration.getChildren()) {
			child.dispose();
		}
		setErrorMessage(null);

		configBlock = getConfigurationBlockFor(getSelectedVCSManager());
		configBlock.createBlock(cmpConfiguration, HVCSDialog.this);
		cmpConfiguration.requestLayout();
	}

	@Override
	public void setErrorMessage(String newErrorMessage) {
		Button okButton = getButton(IDialogConstants.OK_ID);
		if (okButton != null)
			okButton.setEnabled(newErrorMessage == null);
		super.setErrorMessage(newErrorMessage);
	}

	public IVcsManager getSelectedVCSManager() {
		final IStructuredSelection selection = (IStructuredSelection) cmbVCSType.getSelection();
		return (IVcsManager) selection.getFirstElement();
	}

	@Override
	protected void okPressed() {
		configBlock.okPressed(hawkModel, freeze.getSelection());
		super.okPressed();
	}

	private IVcsConfigurationBlock getConfigurationBlockFor(IVcsManager manager) {
		for (IConfigurationElement e : Platform.getExtensionRegistry().getConfigurationElementsFor(IVcsConfigurationBlock.EXT_ID)) {
			try {
				IVcsConfigurationBlock selector = (IVcsConfigurationBlock) e.createExecutableExtension(IVcsConfigurationBlock.EXT_ATTR_CLASS);
				if (selector.isApplicableTo(manager)) {
					return selector;
				}
			} catch (CoreException ex) {
				Activator.logError("Could not create the config block for " + manager.getHumanReadableName(), ex);
			}
		}

		return new DefaultVcsConfigurationBlock();
	}

}