package com.srbenoit.filter.items;

import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;

/**
 * A class that stores data relating to a trajectory.
 */
public class Trajectory {

    /** the time point of each point in the trajectory */
    public final List<Integer> timePoints;

    /** the planes of each point in the trajectory */
    public final List<Integer> planes;

    /** the position, velocity, and ambient velocity of the point */
    public final List<ImagePoint> points;

    /** the relative motion (first point is always (0,0)) */
    public final List<Point> relative;

    /**
     * Constructs a new <code>Trajectory</code> with no points.
     */
    public Trajectory() {

        this.timePoints = new ArrayList<Integer>(10);
        this.planes = new ArrayList<Integer>(10);
        this.points = new ArrayList<ImagePoint>(10);
        this.relative = new ArrayList<Point>(10);
    }

    /**
     * Gets the number of points in the trajectory.
     *
     * @return  the number of points
     */
    public int numPoints() {

        return this.points.size();
    }

    /**
     * Gets the time point for a given index.
     *
     * @param   index  the index of the point to retrieve
     * @return  the time point
     */
    public int getTimePoint(final int index) {

        return this.timePoints.get(index).intValue();
    }

    /**
     * Gets the Z plane for a given index.
     *
     * @param   index  the index of the point to retrieve
     * @return  the Z plane
     */
    public int getPlane(final int index) {

        return this.planes.get(index).intValue();
    }

    /**
     * Gets the absolute position of the trajectory point for given index.
     *
     * @param   index  the index of the point to retrieve
     * @return  the point
     */
    public ImagePoint getPoint(final int index) {

        return this.points.get(index);
    }

    /**
     * Gets the relative position, compensated for ambient drift. The first point is always (0, 0).
     *
     * @param   index  the index of the point to retrieve
     * @return  the relative point
     */
    public Point getRelative(final int index) {

        return this.relative.get(index);
    }

    /**
     * Gets the sum of the x position and x velocity of the last point in the trajectory.
     *
     * @return  the X coordinate
     */
    public int getCurrentX() {

        ImagePoint last;

        last = this.points.get(this.points.size() - 1);

        return last.getXPos() + last.getXVel();
    }

    /**
     * Gets the sum of the y position and y velocity of the last point in the trajectory.
     *
     * @return  the Y coordinate
     */
    public int getCurrentY() {

        ImagePoint last;

        last = this.points.get(this.points.size() - 1);

        return last.getYPos() + last.getYVel();
    }

    /**
     * Gets the plane where the last image point was recorded.
     *
     * @return  the plane of the last image point
     */
    public int getCurrentPlane() {

        return this.planes.get(this.planes.size() - 1);
    }

    /**
     * Adds a new point to the trajectory, adjusting the thumbnail size as needed.
     *
     * @param  timePoint  the time point when the trajectory passed through the point
     * @param  plane      the Z plane of the trajectory when it passed through the point
     * @param  point      the point to add to the trajectory
     */
    public void addPoint(final int timePoint, final int plane, final ImagePoint point) {

        int distX;
        int distY;
        Point prior;

        if (this.points.isEmpty()) {
            this.relative.add(new Point(0, 0));
        } else {
            prior = this.relative.get(this.points.size() - 1);
            distX = point.getXVel() - point.getXAmbientVel();
            distY = point.getYVel() - point.getYAmbientVel();
            this.relative.add(new Point(prior.x + distX, prior.y + distY));
        }

        this.timePoints.add(Integer.valueOf(timePoint));
        this.planes.add(Integer.valueOf(plane));
        this.points.add(point);
    }

    /**
     * Gets the extends of the point's relative motion over the trajectory.
     *
     * @return  the extents
     */
    public Rectangle extents() {

        Rectangle rect;

        rect = new Rectangle();

        for (Point pt : this.relative) {
            rect.add(pt);
        }

        return rect;
    }
}
