/*
Copyright 2008-2010 Gephi
Authors : Cezary Bartosiak
Website : http://www.gephi.org
This file is part of Gephi.
Gephi is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
Gephi is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Gephi. If not, see <http://www.gnu.org/licenses/>.
*/
package org.gephi.data.attributes.type;
import java.util.ArrayList;
import java.util.List;
import org.gephi.data.attributes.api.Estimator;
/**
* A special type which provides methods of getting/setting values of any time
* interval. It is internally implemented using Interval Tree for efficiency.
*
* @author Cezary Bartosiak
*
* @param <T> type of data
*/
public abstract class DynamicType<T> {
protected IntervalTree<T> intervalTree;
/**
* Constructs a new {@code DynamicType} instance with no intervals.
*/
public DynamicType() {
intervalTree = new IntervalTree<T>();
}
/**
* Constructs a new {@code DynamicType} instance that contains a given
* {@code Interval<T>} in.
*
* @param in interval to add (could be null)
*/
public DynamicType(Interval<T> in) {
this();
if (in != null)
intervalTree.insert(in);
}
/**
* Constructs a new {@code DynamicType} instance with intervals given by
* {@code List<Interval<T>>} in.
*
* @param in intervals to add (could be null)
*/
public DynamicType(List<Interval<T>> in) {
this();
if (in != null)
for (Interval<T> interval : in)
intervalTree.insert(interval);
}
/**
* Constructs a deep copy of {@code source}.
*
* @param source an object to copy from (could be null, then completely new
* instance is created)
*/
public DynamicType(DynamicType<T> source) {
if (source == null)
intervalTree = new IntervalTree<T>();
else intervalTree = new IntervalTree<T>(source.intervalTree);
}
/**
* Constructs a deep copy of {@code source} that contains a given
* {@code Interval<T>} in.
*
* @param source an object to copy from (could be null, then completely new
* instance is created)
* @param in interval to add (could be null)
*/
public DynamicType(DynamicType<T> source, Interval<T> in) {
this(source);
if (in != null)
intervalTree.insert(in);
}
/**
* Constructs a deep copy of {@code source} that contains a given
* {@code Interval<T>} in. Before add it removes from the newly created
* object all intervals that overlap with a given {@code Interval<T>} out.
*
* @param source an object to copy from (could be null, then completely new
* instance is created)
* @param in interval to add (could be null)
* @param out interval to remove (could be null)
*/
public DynamicType(DynamicType<T> source, Interval<T> in, Interval<T> out) {
this(source);
if (out != null)
intervalTree.delete(out);
if (in != null)
intervalTree.insert(in);
}
/**
* Constructs a deep copy of {@code source} with additional intervals
* given by {@code List<Interval<T>>} in.
*
* @param source an object to copy from (could be null, then completely new
* instance is created)
* @param in intervals to add (could be null)
*/
public DynamicType(DynamicType<T> source, List<Interval<T>> in) {
this(source);
if (in != null)
for (Interval<T> interval : in)
intervalTree.insert(interval);
}
/**
* Constructs a deep copy of {@code source} with additional intervals
* given by {@code List<Interval<T>>} in. Before add it removes from the
* newly created object all intervals that overlap with intervals given by
* {@code List<Interval<T>>} out.
*
* @param source an object to copy from (could be null, then completely new
* instance is created)
* @param in intervals to add (could be null)
* @param out intervals to remove (could be null)
*/
public DynamicType(DynamicType<T> source, List<Interval<T>> in, List<Interval<T>> out) {
this(source);
if (out != null)
for (Interval<T> interval : out)
intervalTree.delete(interval);
if (in != null)
for (Interval<T> interval : in)
intervalTree.insert(interval);
}
/**
* Returns the leftmost point or {@code Double.NEGATIVE_INFINITY} in case
* of no intervals.
*
* @return the leftmost point.
*/
public double getLow() {
return intervalTree.getLow();
}
/**
* Returns the rightmost point or {@code Double.POSITIVE_INFINITY} in case
* of no intervals.
*
* @return the rightmost point.
*/
public double getHigh() {
return intervalTree.getHigh();
}
/**
* Indicates if the leftmost point is excluded.
*
* @return {@code true} if the leftmost point is excluded,
* {@code false} otherwise.
*/
public boolean isLowExcluded() {
return intervalTree.isLowExcluded();
}
/**
* Indicates if the rightmost point is excluded.
*
* @return {@code true} if the rightmost point is excluded,
* {@code false} otherwise.
*/
public boolean isHighExcluded() {
return intervalTree.isHighExcluded();
}
/**
* Indicates if a given time interval overlaps with any interval of this instance.
*
* @param interval a given time interval
*
* @return {@code true} a given time interval overlaps with any interval of this
* instance, otherwise {@code false}.
*/
public boolean isInRange(Interval interval) {
return intervalTree.overlapsWith(interval);
}
/**
* Indicates if [{@code low}, {@code high}] interval overlaps with any interval of this instance.
*
* @param low the left endpoint
* @param high the right endpoint
*
* @return {@code true} a given time interval overlaps with any interval of this
* instance, otherwise {@code false}.
*
* @throws IllegalArgumentException if {@code low} > {@code high}.
*/
public boolean isInRange(double low, double high) {
if (low > high)
throw new IllegalArgumentException(
"The left endpoint of the interval must be less than " +
"the right endpoint.");
return intervalTree.overlapsWith(new Interval(low, high));
}
/**
* Returns the estimated value of a set of values whose time intervals
* overlap with a [{@code -inf}, {@code inf}] time interval.
* {@code Estimator.FIRST} is used.
*
* @return the estimated value of a set of values whose time intervals
* overlap with a [{@code -inf}, {@code inf}] time interval or
* {@code null} if there are no intervals.
*
* @see Estimator
*/
public T getValue() {
return getValue(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
}
/**
* Returns the estimated value of a set of values whose time intervals
* overlap with a given time interval.
* {@code Estimator.FIRST} is used.
*
* @param interval a given time interval
*
* @return the estimated value of a set of values whose time intervals
* overlap with a given time interval or
* {@code null} if there are no intervals.
*
* @see Estimator
*/
public T getValue(Interval interval) {
return getValue(interval, Estimator.FIRST);
}
/**
* Returns the estimated value of a set of values whose time intervals
* overlap with a [{@code low}, {@code high}] time interval.
* {@code Estimator.FIRST} is used.
*
* @param low the left endpoint
* @param high the right endpoint
*
* @return the estimated value of a set of values whose time intervals
* overlap with a [{@code low}, {@code high}] time interval or
* {@code null} if there are no intervals.
*
* @throws IllegalArgumentException if {@code low} > {@code high}.
*
* @see Estimator
*/
public T getValue(double low, double high) {
return getValue(low, high, Estimator.FIRST);
}
/**
* Returns the estimated value of a set of values whose time intervals
* overlap with a [{@code -inf}, {@code inf}] time interval.
*
* @param estimator used to estimate the result
*
* @return the estimated value of a set of values whose time intervals
* overlap with a [{@code -inf}, {@code inf}] time interval or
* {@code null} if there are no intervals.
*
* @throws UnsupportedOperationException if type {@code T} doesn't support
* the given {@code estimator}.
*
* @see Estimator
*/
public T getValue(Estimator estimator) {
return getValue(Double.NEGATIVE_INFINITY,
Double.POSITIVE_INFINITY,
estimator);
}
/**
* Returns the estimated value of a set of values whose time intervals
* overlap with a given time interval.
*
* @param interval a given time interval
* @param estimator used to estimate the result
*
* @return the estimated value of a set of values whose time intervals
* overlap with a given time interval or
* {@code null} if there are no intervals.
*
* @throws UnsupportedOperationException if type {@code T} doesn't support
* the given {@code estimator}.
*
* @see Estimator
*/
public abstract T getValue(Interval interval, Estimator estimator);
/**
* Returns the estimated value of a set of values whose time intervals
* overlap with a [{@code low}, {@code high}] time interval.
*
* @param low the left endpoint
* @param high the right endpoint
* @param estimator used to estimate the result
*
* @return the estimated value of a set of values whose time intervals
* overlap with a [{@code low}, {@code high}] time interval or
* {@code null} if there are no intervals.
*
* @throws IllegalArgumentException if {@code low} > {@code high}.
* @throws UnsupportedOperationException if type {@code T} doesn't support
* the given {@code estimator}.
*
* @see Estimator
*/
public T getValue(double low, double high, Estimator estimator) {
if (low > high)
throw new IllegalArgumentException(
"The left endpoint of the interval must be less than " +
"the right endpoint.");
return getValue(new Interval(low, high, false, false), estimator);
}
/**
* Returns a list of all values stored in this instance.
*
* @return a list of all values stored in this instance.
*/
public List<T> getValues() {
return getValues(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
}
/**
* Returns a list of values whose time intervals overlap with a
* [{@code low}, {@code high}] time interval.
*
* @param low the left endpoint
* @param high the right endpoint
*
* @return a list of values whose time intervals overlap with a
* [{@code low}, {@code high}] time interval.
*
* @throws IllegalArgumentException if {@code low} > {@code high}.
*/
public List<T> getValues(double low, double high) {
return getValues(new Interval(low, high));
}
/**
* Returns a list of values whose time intervals overlap with a
* given time interval.
*
* @param interval a given time interval
*
* @return a list of values whose time intervals overlap with a
* given time interval.
*/
public List<T> getValues(Interval interval) {
List<T> result = new ArrayList<T>();
for (Interval<T> i : intervalTree.search(interval))
result.add(i.getValue());
return result;
}
/**
* Returns a list of intervals which overlap with a given time interval.
*
* @param interval a given time interval
*
* @return a list of intervals which overlap with a given time interval.
*/
public List<Interval<T>> getIntervals(Interval interval) {
return intervalTree.search(interval);
}
/**
* Returns a list of intervals which overlap with a
* [{@code low}, {@code high}] time interval.
*
* @param low the left endpoint
* @param high the right endpoint
*
* @return a list of intervals which overlap with a
* [{@code low}, {@code high}] time interval.
*
* @throws IllegalArgumentException if {@code low} > {@code high}.
*/
public List<Interval<T>> getIntervals(double low, double high) {
return intervalTree.search(low, high);
}
/**
* Returns the underlying type {@code T}.
*
* @return the underlying type {@code T}.
*/
public abstract Class getUnderlyingType();
/**
* Compares this instance with the specified object for equality.
*
* <p>Note that two {@code DynamicType} instances are equal if they have got
* the same type {@code T} and their interval trees are equal.
*
* @param obj object to which this instance is to be compared
*
* @return {@code true} if and only if the specified {@code Object} is a
* {@code DynamicType} which has the same type {@code T} and an
* equal interval tree.
*
* @see #hashCode
*/
@Override
public boolean equals(Object obj) {
if (obj != null && obj.getClass().equals(this.getClass()) &&
((DynamicType<T>)obj).intervalTree.equals(intervalTree))
return true;
return false;
}
/**
* Returns a hashcode of this instance.
*
* @return a hashcode of this instance.
*/
@Override
public int hashCode() {
return intervalTree.hashCode();
}
/**
* Creates a string representation of all the intervals with their values.
*
* @param timesAsDoubles indicates if times should be shown as doubles or dates
*
* @return a string representation with times as doubles or dates.
*/
public String toString(boolean timesAsDoubles) {
return intervalTree.toString(timesAsDoubles);
}
/**
* Returns a string representation of this instance in a format
* {@code <[low, high, value], ..., [low, high, value]>}. Intervals are
* ordered by its left endpoint.
*
* @return a string representation of this instance.
*/
@Override
public String toString() {
return intervalTree.toString();
}
}