package com.jdblabs.timestamper.core;

import java.text.SimpleDateFormat;

import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.TreeSet;

/**
 * A Timeline object represents a series of markers at specific points in time.
 * It represents on logical timeline. The markers have a name or symbol (the
 * 'mark') and notes associated with that mark.
 * @author Jonathan Bernard {@literal <jdbernard@gmail.com>}
 * @see com.jdbernard.timestamper.core.TimelineSource
 */
public class Timeline implements Iterable<TimelineMarker> {

    public static SimpleDateFormat shortFormat = new SimpleDateFormat("HH:mm:ss");
    public static SimpleDateFormat longFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy");
    protected TreeSet<TimelineMarker> timelineList;

    /**
     * Create a new, empty Timeline.
     */
    public Timeline() {
        timelineList = new TreeSet<TimelineMarker>();
    }

    /**
     * Add a marker to the timeline.
     * @param tm The TimelineMarker to add.
     * @return <code>true</code> if this Timeline was modified.
     */
    public boolean addMarker(TimelineMarker tm) { return timelineList.add(tm); }

    /**
     * Add a marker to the timeline.
     * @param timestamp The date and time of the marker.
     * @param name The name of the marker (activity, project, etc)
     * @param notes Additional notes about this marker.
     * @return <code>true</code> if this Timeline was modified.
     */
    public boolean addMarker(Date timestamp, String name, String notes) {
        return addMarker(new TimelineMarker(timestamp, name, notes));
    }

    /**
     * Get the last marker placed before or on the given timestamp. If you
     * think of the markers as demarcating time, then this is effectivly,
     * "get the current task."
     * @param timestamp The cut-off point for the query.
     * @return The latest TimelineMarker placed on or before the given
     * timestamp.
     */
    public TimelineMarker getLastMarker(Date timestamp) {
        TimelineMarker lastMarker = null;
        for (TimelineMarker tm : timelineList) {
            if (tm.getTimestamp().after(timestamp))
                break;
            lastMarker = tm;
        }

        return lastMarker;
    }

    /**
     * Remove a TimelineMarker from this Timelnie.
     * @param marker The marker to remove.
     * @return <code>true</code> if this Timeline was changed.
     */
    public boolean removeMarker(TimelineMarker marker) {
        return timelineList.remove(marker);
    }

    public Iterator<TimelineMarker> iterator() {
        return timelineList.iterator();
    }

    /**
     * Return the difference of the this timeline relative to another timeline.
     * More specifically, return the set of all
     * {@link jdbernard.timestamper.core.TimelineMarker}s that are present in
     * the <b>this</b> timeline but not present in the given timeline.
     * timeline.
     * @param t
     * @return A collection representing the TimelineMarkers present in
     * <b>this</b> timeline but not in the given timeline.
     */
    public Collection<TimelineMarker> difference(Timeline t) {
        TreeSet<TimelineMarker> difference = new TreeSet<TimelineMarker>();

        for (TimelineMarker tm : timelineList) {
            if (!t.timelineList.contains(tm))
                difference.add(tm);
        }

        return difference;
    }

    /**
     * Add all TimelineMarkers from <code>t</code> to <code>this</code>
     * Timeline, excluding markers already present in <code>this</code>.
     * @param t
     * @return <code>true</code> if this Timeline was modified.
     */
    public boolean addAll(Timeline t) {
        boolean modified = false;
        for (TimelineMarker tm : t) {
            modified = addMarker(tm) || modified; }

        return modified;
    }

    /**
     * Add all TimelineMarkers from <code>c</code> to <code>this</code>
     * Timeline, excluding markers already present in <code>this</code>.
     * @param c A Collection of TimelineMarkers
     * @return <code>true</code> if this TImeline was modified.
     */
    public boolean addAll(Collection<TimelineMarker> c) {
        return timelineList.addAll(c);
    }
}
