/*
* 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.dynamic;
import org.gephi.data.attributes.api.Estimator;
import org.gephi.data.attributes.type.DynamicType;
import org.gephi.data.attributes.type.Interval;
import org.gephi.data.attributes.type.TimeInterval;
import org.gephi.dynamic.api.DynamicGraph;
import org.gephi.dynamic.api.DynamicModel;
import org.gephi.graph.api.Attributes;
import org.gephi.graph.api.Edge;
import org.gephi.graph.api.Graph;
import org.gephi.graph.api.GraphModel;
import org.gephi.graph.api.GraphView;
import org.gephi.graph.api.Node;
/**
* The wrapper for graph and time interval.
*
* @author Cezary Bartosiak
*/
public final class DynamicGraphImpl implements DynamicGraph {
private GraphModel model;
private GraphView sourceView;
private GraphView currentView;
private double low;
private double high;
/**
* Constructs a new {@code DynamicGraph} that wraps a given {@code Graph}.
* The time interval is [{@code -infinity}, {@code +infinity}].
*
* @param graph wrapped {@code Graph}
*/
public DynamicGraphImpl(Graph graph) {
this(graph, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
}
/**
* Constructs a new {@code DynamicGraph} that wraps a given {@code Graph}
* and a time interval [{@code low}, {@code high}].
*
* @param graph wrapped {@code Graph}
* @param low the left endpoint of the interval
* @param high the right endpoint of the interval
*
* @throws NullPointerException if {@code graph} is null.
* @throws IllegalArgumentException if {@code low} > {@code high}.
*/
public DynamicGraphImpl(Graph graph, double low, double high) {
if (graph == null)
throw new NullPointerException("The graph cannot be null.");
if (low > high)
throw new IllegalArgumentException(
"The left endpoint of the interval must be less than "
+ "the right endpoint.");
model = graph.getGraphModel();
sourceView = graph.getView();
currentView = model.copyView(sourceView);
this.low = low;
this.high = high;
if (low != Double.NEGATIVE_INFINITY || high != Double.POSITIVE_INFINITY) {
Graph vgraph = model.getGraph(currentView);
for (Node n : vgraph.getNodes().toArray()) {
TimeInterval ti = (TimeInterval)n.getNodeData().getAttributes().getValue(
DynamicModel.TIMEINTERVAL_COLUMN);
if (!ti.isInRange(low, high))
vgraph.removeNode(n);
}
for (Edge e : vgraph.getEdges().toArray()) {
TimeInterval ti = (TimeInterval)e.getEdgeData().getAttributes().getValue(
DynamicModel.TIMEINTERVAL_COLUMN);
if (!ti.isInRange(low, high))
vgraph.removeEdge(e);
}
}
}
@Override
public Object[] getAttributesValues(Node node, double point) {
int count = node.getNodeData().getAttributes().countValues();
Estimator[] estimators = new Estimator[count];
for (int i = 0; i < count; ++i)
estimators[i] = Estimator.FIRST;
return getAttributesValues(node, point, estimators);
}
@Override
public Object[] getAttributesValues(Node node, double point, Estimator[] estimators) {
checkPoint(point);
return getAttributesValues(node, point, point, estimators);
}
@Override
public Object[] getAttributesValues(Node node, double low, double high) {
checkLowHigh(low, high);
return getAttributesValues(node, new Interval(low, high));
}
@Override
public Object[] getAttributesValues(Node node, Interval interval) {
int count = node.getNodeData().getAttributes().countValues();
Estimator[] estimators = new Estimator[count];
for (int i = 0; i < count; ++i)
estimators[i] = Estimator.FIRST;
return getAttributesValues(node, interval, estimators);
}
@Override
public Object[] getAttributesValues(Node node, double low, double high, Estimator[] estimators) {
checkLowHigh(low, high);
return getAttributesValues(node, new Interval(low, high), estimators);
}
@Override
public Object[] getAttributesValues(Node node, Interval interval, Estimator[] estimators) {
checkEstimators(node, estimators);
Attributes attributes = node.getNodeData().getAttributes();
Object[] values = new Object[attributes.countValues()];
for (int i = 0; i < attributes.countValues(); ++i) {
values[i] = attributes.getValue(i);
if (values[i] instanceof DynamicType)
values[i] = ((DynamicType)values[i]).getValue(estimators[i]);
}
return values;
}
@Override
public Object[] getAttributesValues(Edge edge, double point) {
int count = edge.getEdgeData().getAttributes().countValues();
Estimator[] estimators = new Estimator[count];
for (int i = 0; i < count; ++i)
estimators[i] = Estimator.FIRST;
return getAttributesValues(edge, point, estimators);
}
@Override
public Object[] getAttributesValues(Edge edge, double point, Estimator[] estimators) {
checkPoint(point);
return getAttributesValues(edge, point, point, estimators);
}
@Override
public Object[] getAttributesValues(Edge edge, double low, double high) {
checkLowHigh(low, high);
return getAttributesValues(edge, new Interval(low, high));
}
@Override
public Object[] getAttributesValues(Edge edge, Interval interval) {
int count = edge.getEdgeData().getAttributes().countValues();
Estimator[] estimators = new Estimator[count];
for (int i = 0; i < count; ++i)
estimators[i] = Estimator.FIRST;
return getAttributesValues(edge, interval, estimators);
}
@Override
public Object[] getAttributesValues(Edge edge, double low, double high, Estimator[] estimators) {
checkLowHigh(low, high);
return getAttributesValues(edge, new Interval(low, high), estimators);
}
@Override
public Object[] getAttributesValues(Edge edge, Interval interval, Estimator[] estimators) {
checkEstimators(edge, estimators);
Attributes attributes = edge.getEdgeData().getAttributes();
Object[] values = new Object[attributes.countValues()];
for (int i = 0; i < attributes.countValues(); ++i) {
values[i] = attributes.getValue(i);
if (values[i] instanceof DynamicType)
values[i] = ((DynamicType)values[i]).getValue(estimators[i]);
}
return values;
}
@Override
public double getLow() {
return low;
}
@Override
public double getHigh() {
return high;
}
@Override
public Graph getSnapshotGraph(double point) {
return getSnapshotGraph(point, Estimator.FIRST);
}
@Override
public Graph getSnapshotGraph(double point, Estimator estimator) {
checkPoint(point);
return getSnapshotGraph(point, point, estimator);
}
@Override
public Graph getSnapshotGraph(double low, double high) {
return getSnapshotGraph(low, high, Estimator.FIRST);
}
@Override
public Graph getSnapshotGraph(Interval interval) {
return getSnapshotGraph(interval, Estimator.FIRST);
}
@Override
public Graph getSnapshotGraph(double low, double high, Estimator estimator) {
checkLowHigh(low, high);
return getSnapshotGraph(new Interval(low, high), Estimator.FIRST);
}
@Override
public Graph getSnapshotGraph(Interval interval, Estimator estimator) {
Graph graph = model.getGraph(sourceView);
Graph vgraph = model.getGraph(currentView);
for (Node n : graph.getNodes().toArray()) {
TimeInterval ti = (TimeInterval)n.getNodeData().getAttributes().getValue(DynamicModel.TIMEINTERVAL_COLUMN);
if(ti == null && !vgraph.contains(n))
vgraph.addNode(n);
else if(ti != null && ti.getValue(interval, estimator) == null && vgraph.contains(n))
vgraph.removeNode(n);
else if (ti != null && ti.getValue(interval, estimator) != null && !vgraph.contains(n))
vgraph.addNode(n);
}
for (Edge e : graph.getEdges().toArray()) {
TimeInterval ti = (TimeInterval)e.getEdgeData().getAttributes().getValue(DynamicModel.TIMEINTERVAL_COLUMN);
if(ti == null && !vgraph.contains(e) &&
vgraph.contains(e.getSource()) && vgraph.contains(e.getTarget()))
vgraph.addEdge(e);
else if(ti != null && ti.getValue(interval, estimator) == null && vgraph.contains(e))
vgraph.removeEdge(e);
else if (ti != null && ti.getValue(interval, estimator) != null && !vgraph.contains(e) &&
vgraph.contains(e.getSource()) && vgraph.contains(e.getTarget()))
vgraph.addEdge(e);
}
return vgraph;
}
@Override
public Graph getStrongSnapshotGraph(double point) {
checkPoint(point);
return getStrongSnapshotGraph(point, point);
}
@Override
public Graph getStrongSnapshotGraph(double low, double high) {
checkLowHigh(low, high);
return getStrongSnapshotGraph(new Interval(low, high));
}
@Override
public Graph getStrongSnapshotGraph(Interval interval) {
Graph graph = model.getGraph(sourceView);
Graph vgraph = model.getGraph(currentView);
for (Node n : graph.getNodes().toArray()) {
TimeInterval ti = (TimeInterval)n.getNodeData().getAttributes().getValue(DynamicModel.TIMEINTERVAL_COLUMN);
if (ti.getValues(interval).size() < ti.getValues().size() && vgraph.contains(n))
vgraph.removeNode(n);
else if (ti.getValues(interval).size() == ti.getValues().size() && !vgraph.contains(n))
vgraph.addNode(n);
}
for (Edge e : graph.getEdges().toArray()) {
TimeInterval ti = (TimeInterval)e.getEdgeData().getAttributes().getValue(DynamicModel.TIMEINTERVAL_COLUMN);
if (ti.getValues(interval).size() < ti.getValues().size() && vgraph.contains(e))
vgraph.removeEdge(e);
else if (ti.getValues(interval).size() == ti.getValues().size() && !vgraph.contains(e) &&
vgraph.contains(e.getSource()) && vgraph.contains(e.getTarget()))
vgraph.addEdge(e);
}
return vgraph;
}
@Override
public Graph getUnderlyingGraph() {
return model.getGraph();
}
@Override
public TimeInterval getInterval() {
return new TimeInterval(low, high);
}
@Override
public void setInterval(TimeInterval interval) {
setInterval(interval.getLow(), interval.getHigh());
}
@Override
public void setInterval(double low, double high) {
if (low > high)
throw new IllegalArgumentException(
"The left endpoint of the interval must be less than "
+ "the right endpoint.");
this.low = low;
this.high = high;
}
private void checkPoint(double point) {
if (point < low || point > high)
throw new IllegalArgumentException(
"The point cannot be out of range "
+ "wrapped by this DynamicGraph");
}
private void checkLowHigh(double low, double high) {
if (low > high)
throw new IllegalArgumentException(
"The left endpoint of the interval must be less than "
+ "the right endpoint.");
if (high < this.low || low > this.high)
throw new IllegalArgumentException(
"The time interval [low, high] cannot be out of range "
+ "wrapped by this DynamicGraph");
}
private void checkEstimators(Node node, Estimator[] estimators) {
int count = node.getNodeData().getAttributes().countValues();
if (count != estimators.length)
throw new IllegalArgumentException(
"The length of the estimators table must be the same as "
+ "the count of attributes.");
}
private void checkEstimators(Edge edge, Estimator[] estimators) {
int count = edge.getEdgeData().getAttributes().countValues();
if (count != estimators.length)
throw new IllegalArgumentException(
"The length of the estimators table must be the same as "
+ "the count of attributes.");
}
/**
* Compares this instance with the specified object for equality.
*
* @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 DynamicGraph} which has the 'equal' graph.
*
* @see #hashCode
*/
@Override
public boolean equals(Object obj) {
if (obj != null && obj.getClass().equals(this.getClass())
&& ((DynamicGraphImpl) obj).model.getGraph().equals(model.getGraph()))
return true;
return false;
}
/**
* Returns a hashcode of this instance.
*
* @return a hashcode of this instance.
*/
@Override
public int hashCode() {
return model.getGraph().hashCode();
}
/**
* Returns a string representation of this instance in a format
* provided by the underlying graph.
*
* @return a string representation of this instance.
*/
@Override
public String toString() {
return model.getGraph().toString();
}
}