package com.excelsior.xds.core.todotask;

import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;

import com.excelsior.xds.core.text.TextPosition;

/**
 * This class manages creation and registration of 'to-do' tasks' markers.
 *   
 * @noextend This class is not intended to be subclassed by clients.
 */
public final class TodoTaskMarkerManager
{
    private TodoTaskMarkerManager() {
	}

	/**
     * Creates and returns the "to do" task marker with the specified position 
     * on the given resource. 
     * 
     * @param project a project to operate on, must not be <tt>null</tt>
     * @param file a source file in which the task takes place or <tt>null</tt>
     * @param task instance of discovered task.
     * @param message text of the task
     * @param position a start position of the task
     * @param endOffset a end offset of the task
     * 
     * @return the handle of the new marker. 
     */
    public static IMarker createMarker( IResource resource
                                      , TextPosition position, int endOffset 
                                      , TodoTask task, String message
                                      ) throws CoreException
    {
        IMarker marker = resource.createMarker(IMarker.TASK);
        marker.setAttribute(IMarker.MESSAGE,     createMessage(task, message));
        marker.setAttribute(IMarker.PRIORITY,    task.priority.markerPriority);
        marker.setAttribute(IMarker.LINE_NUMBER, position.getLine());
        marker.setAttribute(IMarker.CHAR_START,  position.getOffset());
        marker.setAttribute(IMarker.CHAR_END,    endOffset);
        marker.setAttribute(IMarker.USER_EDITABLE, Boolean.FALSE);
        
        return marker;
    }

    /**
     * Creates and returns the "to do" task marker with the specified position 
     * on the given file. All previous markers with position up to the given will
     * be removed. 
     * 
     * @param project a project to operate on, must not be <tt>null</tt>
     * @param file a source file in which the task takes place or <tt>null</tt>
     * @param task instance of discovered task.
     * @param message text of the task
     * @param position a start position of the task
     * @param endOffset a end offset of the task
     * @param oldMarkers markers from the previous parsing to be reused or removed.
     * 
     * @return the handle of the new marker, or <tt>null</tt> if marker wasn't created. 
     */
    public static IMarker updateMarkers( IResource resource
                                       , TextPosition position, int endOffset 
                                       , TodoTask task, String message
                                       , IMarker[] oldMarkers
                                       ) throws CoreException 
    {
        int startOffs = position.getOffset();
        IMarker newMarker = null;
        String newMessage = createMessage(task, message);
        
        // Remove or reuse 'to-do' markers from previous parsing
        for (int i = 0; i < oldMarkers.length; ++i) {
            IMarker marker = oldMarkers[i];
            if (marker != null) {
                int markerOffs = marker.getAttribute(IMarker.CHAR_START, 0);
                if (markerOffs <= startOffs) {
                	// to remove all editable markers
                	boolean isMarkerNotEditable = Boolean.FALSE.equals(marker.getAttribute(IMarker.USER_EDITABLE));
                    boolean isMarkerEqual = (markerOffs == startOffs)
                                         && newMessage.equals(marker.getAttribute(IMarker.MESSAGE, null))
                                         && isMarkerNotEditable;
                    if (isMarkerEqual) {
                        newMarker = marker;  // reuse the marker from previous parsing
                    } else {
                        marker.delete();
                    }
                    oldMarkers[i] = null;
                }
            }
        }
        
        if (newMarker == null) {          
            newMarker = createMarker(resource, position, endOffset, task, message);
        }

        return newMarker;
    }

    /**
     * Returns all markers of the specified type on this resource, and on its 
     * children. Returns an empty array if there are no matching markers.
     * 
     * @param resource a resource to operate on, must not be <tt>null</tt>
     * @throws CoreException 
     */    
    public static IMarker[] findMarkers(IResource resource) throws CoreException 
    {
        return resource.findMarkers(IMarker.TASK, true, IResource.DEPTH_INFINITE);
    }
    
    private static String createMessage(TodoTask task, String message) {
        return task.tag + " " + message;     //$NON-NLS-1$
    }
}