/*******************************************************************************
 * Copyright (c) 2015-2020 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.vcs;

import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;

import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.hawk.core.IVcsManager;
import org.eclipse.hawk.osgiserver.HModel;
import org.eclipse.hawk.ui2.dialog.HVCSDialog;
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.DirectoryDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;

/**
 * Fallback implementation of {@link IVcsConfigurationBlock} in case there is no
 * dedicated implementation for a certain type of {@link IVcsManager}.
 */
public class DefaultVcsConfigurationBlock implements IVcsConfigurationBlock {

	private HVCSDialog dialog;
	private Text txtVCSLocation;
	private Button btnVCSBrowse;
	private Text txtUser;
	private Text txtPass;

	@Override
	public boolean isApplicableTo(IVcsManager manager) {
		return true;
	}

	@Override
	public void createBlock(Composite container, HVCSDialog dialog) {
		this.dialog = dialog;
		final IVcsManager managerToEdit = dialog.getManagerToEdit();

		final GridLayout containerLayout = new GridLayout();
		containerLayout.numColumns = 3;
		container.setLayout(containerLayout);

		// Location + browse
		final Label lblLocation = new Label(container, SWT.NONE);
		lblLocation.setText("Location:");
		txtVCSLocation = new Text(container, SWT.BORDER);
		final GridData txtVCSLocationLayoutData = new GridData(SWT.FILL, SWT.CENTER, true, false);
		txtVCSLocationLayoutData.widthHint = 300;
		txtVCSLocation.setLayoutData(txtVCSLocationLayoutData);
		if (managerToEdit != null) {
			txtVCSLocation.setText(managerToEdit.getLocation());
			txtVCSLocation.setEnabled(false);
		} else {
			txtVCSLocation.setText(dialog.getSelectedVCSManager().getDefaultLocation());
		}
		txtVCSLocation.addModifyListener(e -> updateDialog());

		btnVCSBrowse = new Button(container, SWT.PUSH);
		GridData gridDataB = new GridData();
		btnVCSBrowse.setLayoutData(gridDataB);
		btnVCSBrowse.setText("Browse...");
		btnVCSBrowse.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				DirectoryDialog dd = new DirectoryDialog(container.getShell(), SWT.OPEN);

				dd.setFilterPath(ResourcesPlugin.getWorkspace().getRoot().getLocation().toFile().toString());
				dd.setMessage("Select a folder to add to the indexer");
				dd.setText("Select a directory");
				String result = dd.open();
				if (result != null) {
					txtVCSLocation.setText(result);
				}
			}
		});
		btnVCSBrowse.setEnabled(false);

		String usernameToEdit = null;
		String passwordToEdit = null;
		if (managerToEdit != null) {
			usernameToEdit = managerToEdit.getUsername();
			passwordToEdit = managerToEdit.getPassword();
		}

		if (isAuthSupported()) {
			final Label lblUser = new Label(container, SWT.NONE);
			lblUser.setText("User (optional):");
			txtUser = new Text(container, SWT.BORDER | SWT.SINGLE);
			final GridData txtUserLayoutData = new GridData(SWT.FILL, SWT.CENTER, true, false);
			txtUserLayoutData.horizontalSpan = 2;
			txtUser.setLayoutData(txtUserLayoutData);
			if (usernameToEdit != null) {
				txtUser.setText(usernameToEdit);
			}
			txtUser.addModifyListener(e -> updateDialog());

			final Label lblPass = new Label(container, SWT.NONE);
			lblPass.setText("Pass (optional):");
			txtPass = new Text(container, SWT.BORDER | SWT.SINGLE | SWT.PASSWORD);
			final GridData txtPassLayoutData = new GridData(SWT.FILL, SWT.CENTER, true, false);
			txtPassLayoutData.horizontalSpan = 2;
			txtPass.setLayoutData(txtPassLayoutData);
			if (passwordToEdit != null) {
				txtPass.setText(passwordToEdit);
			}
			txtPass.addModifyListener(e -> updateDialog());
		}

		updateDialog();
	}

	@Override
	public void okPressed(HModel hawkModel, boolean isFrozen) {
		final String vcsType = dialog.getSelectedVCSManager().getClass().getName();
		final String location = txtVCSLocation.getText();
		final String user = txtUser == null ? "" : txtUser.getText();
		final String pass = txtPass == null ? "" : txtPass.getText();

		final IVcsManager managerToEdit = dialog.getManagerToEdit();
		if (managerToEdit == null) {
			hawkModel.addVCS(location, vcsType, user, pass, isFrozen);
		} else {
			if (managerToEdit.isAuthSupported()) {
				managerToEdit.setCredentials(user, pass, hawkModel.getManager().getCredentialsStore());
			}
			managerToEdit.setFrozen(isFrozen);
		}
	}

	private void updateDialog() {
		if (isAuthSupported()) {
			final boolean authEnabled = isLocationValid();
			txtUser.setEnabled(authEnabled);
			txtPass.setEnabled(authEnabled);

			if ("".equals(txtUser.getText()) != "".equals(txtPass.getText())) {
				dialog.setErrorMessage("The username and password must be empty or not empty at the same time");
			}
		}

		if (dialog.getManagerToEdit() == null) {
			final IVcsManager vcsManager = dialog.getSelectedVCSManager();
			btnVCSBrowse.setEnabled(vcsManager != null && vcsManager.isPathLocationAccepted());
		}

		if (!isLocationValid()) {
			dialog.setErrorMessage("The location is not valid");
		} else if (dialog.getSelectedVCSManager() == null) {
			dialog.setErrorMessage("No VCS manager type has been selected");
		} else {
			dialog.setErrorMessage(null);
		}
	}

	private boolean isLocationValidPath() {
		File dir = new File(txtVCSLocation.getText());
		if (dir.exists() && dir.isDirectory() && dir.canRead())
			return true;
		return false;
	}

	private boolean isAuthSupported() {
		final IVcsManager vcsManager = dialog.getSelectedVCSManager();
		return vcsManager != null && vcsManager.isAuthSupported();
	}

	private boolean isLocationValid() {
		IVcsManager vcsManager = dialog.getSelectedVCSManager();
		return vcsManager.isPathLocationAccepted() && isLocationValidPath()
				|| vcsManager.isURLLocationAccepted() && isLocationValidURI();
	}

	private boolean isLocationValidURI() {
		try {
			URI uri = new URI(txtVCSLocation.getText());
			return uri.getScheme() != null && uri.getPath() != null;
		} catch (URISyntaxException e) {
			return false;
		}
	}

}
