package org.lamport.tla.toolbox.editor.basic.tla;

import java.util.ArrayList;
import java.util.Iterator;

import org.eclipse.core.resources.IMarker;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.IAnnotationHover;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.ui.texteditor.MarkerAnnotation;

/**
 * @author Simon Zambrovski
 * @version $Id$
 */
public class TLAAnnotationHover implements IAnnotationHover {
    /**
     * {@inheritDoc}
     */
	public String getHoverInfo(final ISourceViewer sourceViewer, final int lineNumber) {
		final String[] messages = getMessagesForLine(sourceViewer, lineNumber);

		if (messages.length == 0) {
			return null;
		}

		final StringBuilder sb = new StringBuilder();
		final String lineSeparator = System.getProperty("line.separator");
		for (int i = 0; i < messages.length; i++) {
			sb.append(messages[i]);
			if (i < (messages.length - 1)) {
				sb.append(lineSeparator);
			}
		}
		
		return sb.toString();
	}

	private String[] getMessagesForLine(final ISourceViewer viewer, final int line) {
		final IAnnotationModel model = viewer.getAnnotationModel();

		if (model == null) {
			return new String[0];
		}

		final Iterator<Annotation> it = model.getAnnotationIterator();
		final IDocument document = viewer.getDocument();
		final ArrayList<String> messages = new ArrayList<>();
		while (it.hasNext()) {
			final Annotation annotation = it.next();
			if (annotation instanceof MarkerAnnotation) {
				final MarkerAnnotation ma = (MarkerAnnotation) annotation;
				if (compareRulerLine(model.getPosition(ma), document, line)) {
					final IMarker marker = ma.getMarker();
					final String message = marker.getAttribute(IMarker.MESSAGE, null);
					if ((message != null) && (message.trim().length() > 0)) {
						messages.add(message);
					}
				}
			}
		}
		return (String[]) messages.toArray(new String[messages.size()]);
	}

	private boolean compareRulerLine(final Position position, final IDocument document, final int line) {
		try {
			if ((position.getOffset() > -1) && (position.getLength() > -1)) {
				return (document.getLineOfOffset(position.getOffset()) == line);
			}
		} catch (final BadLocationException e) { }
		return false;
	}
}

@@ -92,24 +92,101 @@
 va.util.
-Iterator
+HashMap;%0D%0Aimport java.util.HashSet;%0D%0Aimport java.util.Iterator;%0D%0Aimport java.util.Set
 ;%0D%0A%0D%0Aimp
@@ -1699,16 +1699,92 @@
 t%3C%3E();%0D%0A
+%09%09final HashMap%3CPosition, Set%3CString%3E%3E placeMessagesMap = new HashMap%3C%3E();%0D%0A
 %09%09while 
@@ -1801,16 +1801,16 @@
 t()) %7B%0D%0A
-
 %09%09%09final
@@ -1968,50 +1968,77 @@
 %09%09%09%09
-if (compareRulerLine(model.getPosition(ma)
+final Position p = model.getPosition(ma);%0D%0A%09%09%09%09if (compareRulerLine(p
 , do
@@ -2247,30 +2247,325 @@
 %09%09%09%09
-messages.add(message);
+Set%3CString%3E priorMessages = placeMessagesMap.get(p);%0D%0A%09%09%09%09%09%09if (priorMessages == null) %7B%0D%0A%09%09%09%09%09%09%09priorMessages = new HashSet%3C%3E();%0D%0A%09%09%09%09%09%09%09placeMessagesMap.put(p, priorMessages);%0D%0A%09%09%09%09%09%09%7D%0D%0A%09%09%09%09%09%09%0D%0A%09%09%09%09%09%09if (!priorMessages.contains(message)) %7B%0D%0A%09%09%09%09%09%09%09messages.add(message);%0D%0A%09%09%09%09%09%09%09priorMessages.add(message);%0D%0A%09%09%09%09%09%09%7D
 %0D%0A%09%09

Support marker tooltips