package org.bndtools.templating.jgit.ui;

import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;

import org.bndtools.templating.jgit.GitRepoPreferences;
import org.bndtools.utils.jface.BoldStyler;
import org.bndtools.utils.swt.AddRemoveButtonBarPart;
import org.bndtools.utils.swt.AddRemoveButtonBarPart.AddRemoveListener;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StyledCellLabelProvider;
import org.eclipse.jface.viewers.StyledString;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
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.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.osgi.framework.Bundle;
import org.osgi.framework.FrameworkUtil;

import aQute.bnd.header.Attrs;
import aQute.bnd.header.Parameters;
import aQute.libg.tuple.Pair;

public class EditableParametersPart {

	private static final Bundle			BUNDLE	= FrameworkUtil.getBundle(EditableParametersPart.class);

	private final String				title;
	private final NewEntryDialogFactory	dialogFactory;

	private List<Pair<String, Attrs>>	entries;

	private Composite					parent;
	private TableViewer					viewer;
	private final ImageDescriptor		imageDescriptor;

	public EditableParametersPart(String title, ImageDescriptor imageDescriptor, NewEntryDialogFactory dialogFactory) {
		this.title = title;
		this.imageDescriptor = imageDescriptor;
		this.dialogFactory = dialogFactory;
	}

	public void setParameters(Parameters params) {
		entries = new ArrayList<>(params.size());
		for (Entry<String, Attrs> entry : params.entrySet()) {
			entries.add(new Pair<>(GitRepoPreferences.removeDuplicateMarker(entry.getKey()), entry.getValue()));
		}
	}

	public Parameters getParameters() {
		Parameters params = new Parameters();
		for (Pair<String, Attrs> entry : entries) {
			params.add(entry.getFirst(), entry.getSecond());
		}
		return params;
	}

	public Control createControl(Composite parent) {
		this.parent = parent;
		Composite composite = new Composite(parent, SWT.NONE);
		GridLayout layout = new GridLayout(2, false);
		composite.setLayout(layout);

		Label titleLabel = new Label(composite, SWT.NONE);
		titleLabel.setText(title);
		titleLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 2, 1));

		Table table = new Table(composite, SWT.BORDER | SWT.MULTI);
		viewer = new TableViewer(table);
		viewer.setContentProvider(ArrayContentProvider.getInstance());
		final Image iconImg = imageDescriptor.createImage(parent.getDisplay());
		viewer.setLabelProvider(new StyledCellLabelProvider() {
			@Override
			public void update(ViewerCell cell) {
				@SuppressWarnings("unchecked")
				Pair<String, Attrs> entry = (Pair<String, Attrs>) cell.getElement();
				StyledString label = new StyledString(entry.getFirst(), BoldStyler.INSTANCE_DEFAULT);
				for (Entry<String, String> attribEntry : entry.getSecond()
					.entrySet()) {
					label.append("; " + attribEntry.getKey() + "=", StyledString.QUALIFIER_STYLER);
					label.append(attribEntry.getValue());
				}
				cell.setText(label.toString());
				cell.setStyleRanges(label.getStyleRanges());
				cell.setImage(iconImg);
			}
		});
		viewer.setInput(entries);
		GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false);
		gd.widthHint = 280;
		gd.heightHint = 80;
		table.setLayoutData(gd);

		final AddRemoveButtonBarPart buttonBarPart = new AddRemoveButtonBarPart();
		ToolBar buttonBar = buttonBarPart.createControl(composite, SWT.FLAT | SWT.VERTICAL);
		buttonBar.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
		final Image imgEdit = ImageDescriptor.createFromURL(BUNDLE.getEntry("icons/edit.gif"))
			.createImage(parent.getDisplay());
		final Image imgEditDisabled = ImageDescriptor.createFromURL(BUNDLE.getEntry("icons/edit-disabled.gif"))
			.createImage(parent.getDisplay());
		final ToolItem btnEdit = new ToolItem(buttonBar, SWT.PUSH);
		btnEdit.setImage(imgEdit);
		btnEdit.setDisabledImage(imgEditDisabled);

		buttonBarPart.setRemoveEnabled(false);
		btnEdit.setEnabled(false);
		buttonBarPart.addListener(new AddRemoveListener() {
			@Override
			public void addSelected() {
				doAdd();
			}

			@Override
			public void removeSelected() {
				doRemove();
			}
		});
		btnEdit.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				doEdit();
			}
		});
		viewer.addSelectionChangedListener(event -> {
			boolean enabled = !viewer.getSelection()
				.isEmpty();
			buttonBarPart.setRemoveEnabled(enabled);
			btnEdit.setEnabled(enabled);
		});
		viewer.addOpenListener(event -> doEdit());
		table.addKeyListener(new KeyAdapter() {
			@Override
			public void keyPressed(KeyEvent e) {
				if (e.keyCode == SWT.DEL && e.stateMask == 0)
					doRemove();
			}
		});
		composite.addDisposeListener(ev -> {
			iconImg.dispose();
			imgEdit.dispose();
			imgEditDisabled.dispose();
		});

		return composite;
	}

	void doAdd() {
		AbstractNewEntryDialog dialog = dialogFactory.create(parent.getShell());
		if (dialog.open() == Window.OK) {
			Pair<String, Attrs> entry = dialog.getEntry();
			entries.add(entry);
			viewer.add(entry);
		}
	}

	void doRemove() {
		int[] indices = viewer.getTable()
			.getSelectionIndices();
		if (indices == null)
			return;

		List<Object> selected = new ArrayList<>(indices.length);
		for (int index : indices)
			selected.add(entries.get(index));
		entries.removeAll(selected);
		viewer.remove(selected.toArray());
	}

	void doEdit() {
		@SuppressWarnings("unchecked")
		Pair<String, Attrs> selected = (Pair<String, Attrs>) ((IStructuredSelection) viewer.getSelection())
			.getFirstElement();
		AbstractNewEntryDialog dialog = dialogFactory.create(parent.getShell());
		dialog.setEntry(selected);
		if (dialog.open() == Window.OK) {
			Pair<String, Attrs> newEntry = dialog.getEntry();

			int index = entries.indexOf(selected);
			entries.set(index, newEntry);
			viewer.refresh();
		}
	}
}
