/*******************************************************************************
 * Copyright (c) 2014 TwelveTone LLC and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     Steven Spungin <steven@spungin.tv> - initial API and implementation
 *******************************************************************************/

package org.eclipse.e4.tools.emf.ui.internal.common;

import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Combo;

/**
 *
 * @author Steven Spungin
 *
 */
public class Autocomplete {

	public static void installOn(ComboViewer comboViewer) {
		final Combo combo = comboViewer.getCombo();

		combo.addKeyListener(new KeyAdapter() {
			@Override
			public void keyReleased(KeyEvent keyEvent) {
				setClosestMatch(combo);
			}

			@Override
			public void keyPressed(KeyEvent keyEvent) {
				if (keyEvent.keyCode == SWT.BS) {
					Point pt = combo.getSelection();
					combo.setSelection(new Point(Math.max(0, pt.x - 1), pt.y));
				}
			}
		});

		combo.addFocusListener(new FocusAdapter() {
			@Override
			public void focusLost(FocusEvent e) {
				combo.setSelection(new Point(0, combo.getText().length()));
			}

			@Override
			public void focusGained(FocusEvent e) {
				combo.setSelection(new Point(0, combo.getText().length()));
			}
		});

		combo.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseUp(MouseEvent e) {
				combo.setSelection(new Point(0, combo.getText().length()));
			}
		});
	}

	private static void setClosestMatch(Combo combo) {
		String[] items = combo.getItems();
		if (items.length == 0) {
			return;
		}

		// TODO this would be faster using binary search if we could insure that
		// the items are sorted in natural order.

		String str = combo.getText();
		Pattern pattern = Pattern.compile(str + ".*", Pattern.CASE_INSENSITIVE); //$NON-NLS-1$

		int index = -1;
		int length = 0;
		for (int i = 0; i < items.length; i++) {
			Matcher m = pattern.matcher(items[i]);
			if (m.matches()) {
				if (index == -1 || items[i].length() < length) {
					length = items[i].length();
					index = i;
				}
			}
		}
		if (index == -1) {
			index = 0;
		}
		Point pt = combo.getSelection();
		String selectedText = items[index];
		combo.select(index);
		combo.setText(selectedText);
		combo.setSelection(new Point(pt.x, selectedText.length()));
	}
}
