001package net.kreatious.pianoleopard.midi.event;
002
003/**
004 * Represents an immutable pair of on/off events
005 *
006 * @author Jay-R Studer
007 * @param <T>
008 *            the subtype of Event held by this pair
009 */
010public class EventPair<T extends Event> {
011    private final T on;
012    private final T off;
013
014    /**
015     * Constructs a new {@link EventPair} with the specified pair of events
016     *
017     * @param on
018     *            the on event
019     * @param off
020     *            the off event
021     * @throws IllegalArgumentException
022     *             if events do not represent a correct bounded pair
023     */
024    public EventPair(T on, T off) {
025        if (!on.isOn()) {
026            throw new IllegalArgumentException("on (" + on + ") was off");
027        } else if (off.isOn()) {
028            throw new IllegalArgumentException("off (" + off + ") was on");
029        } else if (on.getChannel() != off.getChannel()) {
030            throw new IllegalArgumentException("on (" + on + ") is not on the same channel as off (" + off + ")");
031        } else if (!on.getSlot().equals(off.getSlot())) {
032            throw new IllegalArgumentException("on (" + on + ") is not on the same slot as off (" + off + ")");
033        } else if (on.getTime() > off.getTime()) {
034            this.on = on;
035            this.off = on.createOff(on.getTime());
036            return;
037        }
038
039        this.on = on;
040        this.off = off;
041    }
042
043    /**
044     * @return the off event
045     */
046    public T getOff() {
047        return off;
048    }
049
050    /**
051     * @return the on event
052     */
053    public T getOn() {
054        return on;
055    }
056
057    /**
058     * @return the on time in microseconds
059     */
060    public long getOnTime() {
061        return on.getTime();
062    }
063
064    /**
065     * @return the off time in microseconds
066     */
067    public long getOffTime() {
068        return off.getTime();
069    }
070
071    /**
072     * @return the nonnegative duration of this event pair in microseconds
073     */
074    public long getDuration() {
075        return off.getTime() - on.getTime();
076    }
077
078    /**
079     * @return the slot of this event pair
080     */
081    public Object getSlot() {
082        return on.getSlot();
083    }
084
085    /**
086     * @return the channel of this event pair
087     */
088    public int getChannel() {
089        return on.getChannel();
090    }
091
092    /**
093     * Creates a new off event pair of the same type and slot with the specified
094     * off timestamp.
095     *
096     * @param offTime
097     *            the new off time measured in microseconds, value must be after
098     *            the on time.
099     * @return a new event pair with the specified timestamp
100     */
101    public EventPair<T> withOffTime(long offTime) {
102        if (offTime < on.getTime()) {
103            throw new IllegalArgumentException("The offtime must be on or after the on time");
104        }
105        return new EventPair<>(on, on.createOff(offTime));
106    }
107
108    @Override
109    public String toString() {
110        return on + ", " + off;
111    }
112}