package de.ugoe.cs.swe.memos.search;

import java.util.Iterator;
import java.util.Vector;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Text;

import de.ugoe.cs.swe.memos.database.DBUtility;

class CompletionAdapter extends KeyAdapter {
	CompletableText parent = null;
	private int counter = 0;

	CompletionAdapter(CompletableText parent) {
		this.parent = parent;
	}

	public void keyPressed(KeyEvent e) {
		if (e.keyCode == ' ' && !this.parent.multiWords)
			e.doit = false;

		// else if (e.keyCode == SWT.TAB) {
		// counter++;
		// e.doit = false;
		// }
	}

	public void keyReleased(KeyEvent e) {
		String toComplete = getCompletableText();

		if (toComplete.length() >= 2) {

			switch (e.keyCode) {
			case SWT.DEL:
			case SWT.ESC:
				// delete completion suggestion
				// if (!this.parent.mustMatch) {
				deleteSelection();
				counter = 0;
				// }
				break;

			case SWT.CR:
				// autocomplete
				int caretPosition = this.parent.getTextField()
						.getCaretPosition();

				if (!this.parent.getTextField().getText().endsWith(" ")
						&& this.parent.multiWords == true) {
					this.parent.getTextField().setText(
							this.parent.getTextField().getText() + " ");
					this.parent.getTextField().setSelection(
							caretPosition,
							this.parent.getTextField().getText().indexOf(" ",
									caretPosition + 1));
				}

				this.parent.getTextField().clearSelection();
				counter = 0;
				break;

			case SWT.BS:
				// TODO: if mustMatch == true it should not be allowed to remove
				// characters and let the input field not match a suggestion!
//				if (this.parent.mustMatch)
//					autoComplete(e, toComplete);
				break;

			case SWT.ARROW_DOWN:
				// TODO: use tab
				deleteSelection();
				toComplete = getCompletableText();
				counter++;
				autoComplete(e, toComplete);
				break;

			case SWT.ARROW_UP:
				deleteSelection();
				toComplete = getCompletableText();
				counter--;
				autoComplete(e, toComplete);
				break;
			
			case SWT.ARROW_LEFT:
			case SWT.ARROW_RIGHT:
			case SWT.SHIFT:
			case SWT.CAPS_LOCK:
				break;

			default:
				autoComplete(e, toComplete);
			}
		}
	}

	private void autoComplete(KeyEvent e, String toComplete) {
		// if (e.keyCode >= 48 && e.keyCode <= 57 || e.keyCode >= 'A'
		// && e.keyCode <= 'Z' || e.keyCode >= 'a' && e.keyCode <= 'z'
		// || e.keyCode == SWT.ARROW_DOWN || e.keyCode == SWT.ARROW_UP) {
		//
		// complete(toComplete, 0);
		// }
		complete(toComplete, 0);
	}

	private String getCompletableText() {
		String[] words = this.parent.getTextField().getText().substring(0,
				this.parent.getTextField().getCaretPosition()).split(" ");
		String toComplete = words[words.length - 1];
		return toComplete;
	}

	public void complete(String toComplete, int start) {
		// trigger autocompletion
		Vector<String> completions = this.parent.getCompletionList(toComplete);

		if (completions.size() < 1 && this.parent.mustMatch) {
			forceMustMatch(this.parent.getTextField().getText());
			toComplete = getCompletableText();
			if (toComplete.isEmpty())
				return;
			completions = this.parent.getCompletionList(toComplete);
		}

		// if no suggestions exist stop completing
		if (completions.size() < 1)
			return;

		if (counter < 0)
			counter = completions.size() - 1;

		if (counter > completions.size() - 1)
			counter = 0;

		String completionText = completions.elementAt(counter).substring(
				toComplete.length());

		String firstPart = this.parent.getTextField().getText().substring(
				start, this.parent.getTextField().getCaretPosition());
		String secondPart = this.parent.getTextField().getText().substring(
				this.parent.getTextField().getCaretPosition());

		// if navigated via arrow keys remove the not matching part after the
		// cursor position
		if (!secondPart.startsWith(" ") && !secondPart.isEmpty()) {
			if (secondPart.contains(" ")) {
				secondPart = secondPart.substring(secondPart.indexOf(" "));
			}
			else
				secondPart = "";
		}

		this.parent.getTextField().setText(
				this.parent.getTextField().getText().substring(0, start)
						+ firstPart + completionText + secondPart);

		// mark the new part
		this.parent.getTextField().setSelection(
				this.parent.getTextField().getText().substring(0, start)
						.length()
						+ firstPart.length(),
				(this.parent.getTextField().getText().substring(0, start)
						+ firstPart + completionText).length());
	}

	private void forceMustMatch(String input) {
		// FIXME: change this to not allow only the last word to be completed
		Text textField = this.parent.getTextField();
		if (this.parent.getCompletionList(input).size() < 1
				&& textField.getText().length() > 0) {
			textField.setText(textField.getText().substring(0,
					textField.getText().length() - 1));
			forceMustMatch(textField.getText());
			// TODO: MAybe put this last line out of the if statement
			textField.setSelection(textField.getText().length());
		}
	}

	private void deleteSelection() {
		int selectionStart = this.parent.getTextField().getCaretPosition()
				- this.parent.getTextField().getSelectionCount();
		String firstPart = this.parent.getTextField().getText().substring(0,
				selectionStart);
		String secondPart = this.parent.getTextField().getText().substring(
				this.parent.getTextField().getCaretPosition());
		this.parent.getTextField().setText(firstPart + secondPart);
		this.parent.getTextField().setSelection(selectionStart, selectionStart);
	}
}

public abstract class CompletableText {
	protected final static DBUtility db = DBUtility.getInstance();
	protected Vector<String> itemList = new Vector<String>();
	protected Text textField;
	protected boolean multiWords = false, mustMatch = false;

	public void setEnabled(boolean flag){
		textField.setEnabled(flag);
	}
	
	public CompletableText(Composite parent, int style, boolean multiWords,
			boolean mustMatch) {
		this.textField = new Text(parent, style);
		this.textField.addKeyListener(new CompletionAdapter(this));
		this.multiWords = multiWords;
		this.mustMatch = mustMatch;
	}

	protected abstract Vector<String> refreshItemList();

	public Vector<String> getCompletionList(String word) {
		this.itemList = this.refreshItemList();
		String toTest = word.toUpperCase();
		Vector<String> result = new Vector<String>();

		Iterator<String> itemIt = itemList.iterator();
		while (itemIt.hasNext()) {
			String item = itemIt.next();
			if (word.length() <= item.length()) {
				if (item.toUpperCase().substring(0, word.length()).equals(
						toTest)
						&& !result.contains(item)) {
					result.add(item);
				}
			}
		}

		return result;
	}

	public Text getTextField() {
		return this.textField;
	}
}
