/*******************************************************************************
 * Copyright (c) 2015, 2018 Red Hat.
 * 
 * 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:
 *     Red Hat - Initial Contribution
 *******************************************************************************/
package org.eclipse.linuxtools.internal.vagrant.ui.wizards;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Map;

import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.forms.events.ExpansionAdapter;
import org.eclipse.ui.forms.events.ExpansionEvent;
import org.eclipse.ui.forms.widgets.ExpandableComposite;

public class CreateVMAdvancedComposite extends ExpandableComposite {
	private CreateVMPageModel model;
	private final TableViewer tv;
	private static final String KEY = WizardMessages
			.getString("CreateVMAdvancedComposite.Key"); //$NON-NLS-1$
	private static final String VALUE = WizardMessages
			.getString("CreateVMAdvancedComposite.Value"); //$NON-NLS-1$

	private static final String DEFAULT_KEY = WizardMessages
			.getString("CreateVMAdvancedComposite.DefaultKey"); //$NON-NLS-1$
	private static final String DEFAULT_VALUE = WizardMessages
			.getString("CreateVMAdvancedComposite.DefaultValue"); //$NON-NLS-1$

	private String[] KEY_VALUE = new String[] { KEY, VALUE };

	public CreateVMAdvancedComposite(Composite parent,
			ScrolledComposite scrollTop,
			CreateVMPageModel model) {
		super(parent, ExpandableComposite.COMPACT | ExpandableComposite.TWISTIE
				| ExpandableComposite.EXPANDED | SWT.BORDER);
		this.model = model;

		setText(WizardMessages
				.getString("CreateVMAdvancedComposite.EnvironmentVariables")); //$NON-NLS-1$

		final Composite advancedComposite = new Composite(this, SWT.NONE);
		setClient(advancedComposite);
		addExpansionListener(new ExpansionAdapter() {
			@Override
			public void expansionStateChanged(ExpansionEvent e) {
				Shell shell = parent.getShell();
				Point minSize = shell.getMinimumSize();
				shell.setMinimumSize(shell.getSize().x, minSize.y);
				Point point = parent.computeSize(SWT.DEFAULT, SWT.DEFAULT);
				scrollTop.setSize(point);
				scrollTop.setMinSize(point);
				shell.pack();
				parent.layout();
				shell.setMinimumSize(minSize);
			}
		});

		advancedComposite.setLayout(new GridLayout());

		tv = new TableViewer(advancedComposite,
				SWT.FULL_SELECTION | SWT.BORDER);
		tv.setContentProvider(new EnvironmentContentProvider());
		tv.setLabelProvider(new EnvironmentLabelProvider());

		// Set up the table
		Table table = tv.getTable();
		GridData gd = new GridData(GridData.FILL_BOTH);
		gd.heightHint = 150;
		table.setLayoutData(gd);

		TableColumn tc1 = new TableColumn(table, SWT.CENTER);
		TableColumn tc2 = new TableColumn(table, SWT.CENTER);

		tc1.setText(KEY);
		tc2.setText(VALUE);

		tc1.setWidth(250);
		tc2.setWidth(150);

		table.setHeaderVisible(true);
		table.setLinesVisible(true);

		// Create the cell editors
		CellEditor[] editors = new CellEditor[2];
		editors[0] = new TextCellEditor(table);
		editors[1] = new TextCellEditor(table);

		// Set the editors, cell modifier, and column properties
		tv.setColumnProperties(KEY_VALUE);
		tv.setCellModifier(new EnvironmentCellModifier());
		tv.setCellEditors(editors);

		tv.setInput(ResourcesPlugin.getWorkspace());

		table.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseDoubleClick(MouseEvent e) {
				String varToAdd = DEFAULT_KEY;
				int i = 1;
				if (model.getEnvironment().containsKey(varToAdd)) {
					boolean done = false;
					while (!done) {
						String toTest = varToAdd + " (" + i++ + ")"; //$NON-NLS-1$ //$NON-NLS-2$
						if (!model.getEnvironment().containsKey(toTest)) {
							model.getEnvironment().put(toTest, DEFAULT_VALUE);
							done = true;
						}
					}
				} else {
					model.getEnvironment().put(varToAdd, DEFAULT_VALUE);
				}

				tv.refresh();
			}
		});

	}

	public void refresh() {
		if (tv != null && !tv.getTable().isDisposed())
			tv.refresh();
	}

	private class EnvironmentContentProvider
			implements IStructuredContentProvider {
		@Override
		public void dispose() {
		}

		@Override
		public void inputChanged(Viewer viewer, Object oldInput,
				Object newInput) {
		}

		@Override
		public Object[] getElements(Object inputElement) {
			final Map<String, String> env = model.getEnvironment();
			if (env != null) {
				ArrayList<String> keys = new ArrayList<>(env.keySet());
				Collections.sort(keys, new Comparator<String>() {
					@Override
					public int compare(String o1, String o2) {
						// anything with default value should sit at the bottom
						boolean o1IsDefaultValue = env.get(o1)
								.equals(DEFAULT_VALUE);
						boolean o2IsDefaultValue = env.get(o2)
								.equals(DEFAULT_VALUE);
						if (o1IsDefaultValue) {
							if (o2IsDefaultValue)
								return o1.compareTo(o2);
							return 1;
						}
						if (o2IsDefaultValue)
							return -1;
						if (o1.startsWith(DEFAULT_KEY)) {
							if (o2.startsWith(DEFAULT_KEY))
								return env.get(o1).compareTo(env.get(o2));
							return 1;
						}
						if (o2.startsWith(DEFAULT_KEY))
							return -1;
						return o1.compareTo(o2);
					}
				});
				return keys.toArray(new String[keys.size()]);
			}
			return new String[0];
		}
	}

	private class EnvironmentLabelProvider extends LabelProvider
			implements ITableLabelProvider {
		@Override
		public String getColumnText(Object element, int columnIndex) {
			if (columnIndex == 0)
				return (String) element;
			if (columnIndex == 1)
				return model.getEnvironment().get(element);
			return null;
		}

		@Override
		public Image getColumnImage(Object element, int columnIndex) {
			// TODO Auto-generated method stub
			return null;
		}
	}

	private class EnvironmentCellModifier implements ICellModifier {
		@Override
		public boolean canModify(Object element, String property) {
			return true;
		}

		@Override
		public Object getValue(Object element, String property) {
			if (property == KEY)
				return element;
			if (property == VALUE) {
				return model.getEnvironment().get(element);
			}
			return ""; //$NON-NLS-1$
		}

		@Override
		public void modify(Object element, String property, Object value) {
			String data = (String) ((TableItem) element).getData();
			if (property == KEY) {
				String v = (String) value;
				if (v == null || v.isEmpty()) {
					model.getEnvironment().remove(data);
				} else {
					String currentVal = model.getEnvironment().get(data);
					model.getEnvironment().remove(data);
					model.getEnvironment().put((String) value, currentVal);
				}
			} else if (property == VALUE) {
				String v = (String) value;
				if (v == null || v.isEmpty()) {
					model.getEnvironment().remove(data);
				} else {
					model.getEnvironment().put(data, (String) value);
				}
			}
			tv.refresh();
		}
	}
}
