package bndtools.editor.project;

import java.util.List;

import org.bndtools.api.ILogger;
import org.bndtools.api.Logger;
import org.bndtools.api.ResolveMode;
import org.bndtools.core.resolve.ResolveJob;
import org.bndtools.core.ui.icons.Icons;
import org.bndtools.utils.swt.SWTConcurrencyUtil;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
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.ui.forms.editor.IFormPage;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Section;
import org.osgi.resource.Requirement;

import bndtools.BndConstants;
import bndtools.editor.BndEditor;

public class RunRequirementsPart extends AbstractRequirementListPart {

	@SuppressWarnings("deprecation")
	private static final String		RUNREQUIRE		= BndConstants.RUNREQUIRE;
	private static final ILogger	logger			= Logger.getLogger(RunRequirementsPart.class);

	private static final String[]	SUBSCRIBE_PROPS	= new String[] {
		RUNREQUIRE, BndConstants.RUNREQUIRES, BndConstants.RESOLVE_MODE
	};

	private Button					btnAutoResolve;
	private ResolveMode				resolveMode;

	private final Image				resolveIcon		= Icons.desc("resolve")
		.createImage();
	private Button					btnResolveNow;
	private JobChangeAdapter		resolveJobListener;

	public RunRequirementsPart(Composite parent, FormToolkit toolkit, int style) {
		super(parent, toolkit, style);
		createSection(getSection(), toolkit);
	}

	@Override
	protected String[] getProperties() {
		return SUBSCRIBE_PROPS;
	}

	private void createSection(Section section, FormToolkit tk) {
		section.setText("Run Requirements");
		section.setDescription(
			"The specified requirements will be used to resolve a set of runtime bundles from available repositories.");

		// Create toolbar
		createToolBar(section);

		// Create main panel
		Composite composite = tk.createComposite(section);
		section.setClient(composite);

		// Create table
		TableViewer viewer = createViewer(composite, tk);

		// Create resolve and auto-resolve controls
		btnAutoResolve = tk.createButton(composite, "Auto-resolve on save", SWT.CHECK);
		btnResolveNow = tk.createButton(composite, "Resolve", SWT.PUSH);
		btnResolveNow.setImage(resolveIcon);

		// Listeners
		btnAutoResolve.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				ResolveMode old = resolveMode;
				resolveMode = btnAutoResolve.getSelection() ? ResolveMode.auto : ResolveMode.manual;
				if (old != resolveMode)
					markDirty();
			}
		});
		btnResolveNow.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				doResolve();
			}
		});
		resolveJobListener = new JobChangeAdapter() {
			@Override
			public void running(IJobChangeEvent event) {
				if (event.getJob() instanceof ResolveJob) {
					SWTConcurrencyUtil.execForControl(btnResolveNow, true, () -> btnResolveNow.setEnabled(false));
				}
			}

			@Override
			public void done(IJobChangeEvent event) {
				if (event.getJob() instanceof ResolveJob) {
					SWTConcurrencyUtil.execForControl(btnResolveNow, true, () -> btnResolveNow.setEnabled(true));
				}
			}
		};
		Job.getJobManager()
			.addJobChangeListener(resolveJobListener);

		// Layout
		GridLayout layout;
		GridData gd;

		layout = new GridLayout(2, false);
		layout.horizontalSpacing = 0;
		layout.verticalSpacing = 5;
		layout.marginHeight = 0;
		layout.marginWidth = 0;
		composite.setLayout(layout);

		gd = new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1);
		gd.widthHint = 50;
		gd.heightHint = 50;
		viewer.getControl()
			.setLayoutData(gd);

		gd = new GridData(SWT.RIGHT, SWT.CENTER, true, false);
		btnResolveNow.setLayoutData(gd);
	}

	@Override
	public void dispose() {
		super.dispose();
		Job.getJobManager()
			.removeJobChangeListener(resolveJobListener);
		resolveIcon.dispose();
	}

	private void doResolve() {
		IFormPage formPage = (IFormPage) getManagedForm().getContainer();
		BndEditor editor = (BndEditor) formPage.getEditor();
		editor.resolveRunBundles(new NullProgressMonitor(), false);
	}

	@Override
	protected void doCommitToModel(List<Requirement> requires) {
		model.setRunRequires(requires);
		setResolveMode();
	}

	@Override
	public List<Requirement> doRefreshFromModel() {
		resolveMode = getResolveMode();
		btnAutoResolve.setSelection(resolveMode == ResolveMode.auto);

		return model.getRunRequires();
	}

	@Override
	protected String getAddButtonLabel() {
		return "Add Bundle Requirement";
	}

	private void setResolveMode() {
		String formatted;
		if (resolveMode == ResolveMode.manual || resolveMode == null)
			formatted = null;
		else
			formatted = resolveMode.toString();
		model.genericSet(BndConstants.RESOLVE_MODE, formatted);
	}

	private ResolveMode getResolveMode() {
		ResolveMode resolveMode = ResolveMode.manual;
		try {
			String str = (String) model.genericGet(BndConstants.RESOLVE_MODE);
			if (str != null)
				resolveMode = Enum.valueOf(ResolveMode.class, str);
		} catch (Exception e) {
			logger.logError("Error parsing '-resolve' header.", e);
		}
		return resolveMode;
	}

}
