/**
* Copyright (c) 2011-2014, OpenIoT
*
* This file is part of OpenIoT.
*
* OpenIoT is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* OpenIoT 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with OpenIoT. If not, see <http://www.gnu.org/licenses/>.
*
* Contact: OpenIoT mailto: info@openiot.eu
*/
package org.openiot.ui.request.definition.web.model.nodes.impl.sinks;
import java.io.Serializable;
import java.util.Iterator;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;
import org.openiot.ui.request.commons.annotations.Endpoint;
import org.openiot.ui.request.commons.annotations.Endpoints;
import org.openiot.ui.request.commons.annotations.GraphNodeClass;
import org.openiot.ui.request.commons.annotations.NodeProperties;
import org.openiot.ui.request.commons.annotations.NodeProperty;
import org.openiot.ui.request.commons.models.ObservableMap;
import org.openiot.ui.request.commons.nodes.base.DefaultGraphNode;
import org.openiot.ui.request.commons.nodes.base.DefaultGraphNodeEndpoint;
import org.openiot.ui.request.commons.nodes.base.DefaultGraphNodeProperty;
import org.openiot.ui.request.commons.nodes.enums.AnchorType;
import org.openiot.ui.request.commons.nodes.enums.ConnectorType;
import org.openiot.ui.request.commons.nodes.enums.EndpointType;
import org.openiot.ui.request.commons.nodes.enums.PropertyType;
import org.openiot.ui.request.commons.nodes.interfaces.GraphNodeEndpoint;
import org.openiot.ui.request.commons.nodes.interfaces.GraphNodeProperty;
/**
*
* @author Achilleas Anagnostopoulos (aanag) email: aanag@sensap.eu
*/
@GraphNodeClass(label = "LineChart", type = "SINK", scanProperties = true)
@NodeProperties({
@NodeProperty(type = PropertyType.Writable, javaType = java.lang.String.class, name = "TITLE", required = true),
@NodeProperty(type = PropertyType.Writable, javaType = java.lang.String.class, name = "SERIES", required = true, allowedValues = { "1", "2", "3", "4", "5" }),
@NodeProperty(type = PropertyType.Writable, javaType = java.lang.String.class, name = "X_AXIS_TYPE", required = true, allowedValues = { "Number", "Date (result set)", "Date (observation)" }),
@NodeProperty(type = PropertyType.Writable, javaType = java.lang.String.class, name = "X_AXIS_LABEL", required = true),
@NodeProperty(type = PropertyType.Writable, javaType = java.lang.String.class, name = "Y_AXIS_LABEL", required = true)
})
public class LineChart extends DefaultGraphNode implements Serializable, Observer {
private static final long serialVersionUID = 1L;
public LineChart() {
super();
// Setup some defaults
setProperty("TITLE", LineChart.class.getSimpleName());
setProperty("SERIES", "1");
setProperty("X_AXIS_TYPE", "Number");
setProperty("X_AXIS_LABEL", "x axis");
setProperty("Y_AXIS_LABEL", "y axis");
addPropertyChangeObserver(this);
validateSeries();
}
private void removeAllXAxisEndpoints() {
Iterator<GraphNodeEndpoint> endpointIt = this.getEndpointDefinitions().iterator();
while (endpointIt.hasNext()) {
GraphNodeEndpoint endpoint = endpointIt.next();
if (endpoint.getLabel().startsWith("x")) {
endpointIt.remove();
disconnectEndpoint(endpoint);
}
}
}
private void addMissingXAxii() {
String xAxisType = (String) getPropertyValueMap().get("X_AXIS_TYPE");
if ("Date (result set)".equals(xAxisType)) {
return;
}
int maxSeries = Integer.valueOf((String) getPropertyByName("SERIES").getAllowedValues()[getPropertyByName("SERIES").getAllowedValues().length - 1]);
for (int i = 0; i < maxSeries; i++) {
GraphNodeEndpoint yep = getEndpointByLabel("y" + (i + 1));
if( yep == null ){
return;
}
int insIndex = Math.max(0, getEndpointDefinitions().indexOf(yep));
GraphNodeEndpoint ep = getEndpointByLabel("x" + (i + 1));
if (ep == null) {
ep = new DefaultGraphNodeEndpoint();
ep.setType(EndpointType.Input);
ep.setAnchor(AnchorType.Left);
ep.setConnectorType(ConnectorType.Rectangle);
ep.setLabel("x" + (i + 1));
ep.setRequired(true);
// Setup scope and connection count depending on axis type
if ("Number".equals(xAxisType)) {
ep.setScope("agr_Number agr_Integer agr_Long, agr_Float agr_Double");
ep.setMaxConnections(1);
} else {
ep.setScope("grp_Date");
ep.setMaxConnections(-1); // allow connection of multiple attributes
}
getEndpointDefinitions().add(insIndex, ep);
} else {
// Check that scope is consistent with axis type
if ("Number".equals(xAxisType) && ep.getScope().contains("grp_")) {
disconnectEndpoint(ep);
ep.setScope("agr_Number agr_Integer agr_Long, agr_Float agr_Double");
} else if ("Date (observation)".equals(xAxisType) && ep.getScope().contains("agr_")) {
disconnectEndpoint(ep);
ep.setScope("grp_Date");
ep.setMaxConnections(-1); // allow connection of multiple attributes
}
}
}
}
public void validateSeries() {
int seriesCount = Integer.valueOf((String) getPropertyValueMap().get("SERIES"));
int i = 0;
for (; i < seriesCount; i++) {
// If we are missing the required endpoints and properties create
// them now
String epLabel = "y" + (i + 1);
GraphNodeEndpoint ep = getEndpointByLabel(epLabel);
if (ep == null) {
// Generate Y axis entry
ep = new DefaultGraphNodeEndpoint();
ep.setType(EndpointType.Input);
ep.setAnchor(AnchorType.Left);
ep.setConnectorType(ConnectorType.Rectangle);
ep.setScope("agr_Number agr_Integer agr_Long, agr_Float agr_Double");
ep.setLabel(epLabel);
ep.setRequired(true);
getEndpointDefinitions().add(ep);
// Generate series properties
GraphNodeProperty prop = new DefaultGraphNodeProperty();
String propKey = "SERIES_" + i + "_LABEL";
prop.setType(PropertyType.Writable);
prop.setName(propKey);
prop.setJavaType(java.lang.String.class);
prop.setRequired(true);
getPropertyDefinitions().add(prop);
((ObservableMap<String, Object>) getPropertyValueMap()).getWrappedMap().put(propKey, "Series " + (i + 1));
}
}
// If we reduced the number of series, get rid of the old series
int maxSeries = Integer.valueOf((String) getPropertyByName("SERIES").getAllowedValues()[getPropertyByName("SERIES").getAllowedValues().length - 1]);
for (; i < maxSeries; i++) {
String epLabel = "y" + (i + 1);
GraphNodeEndpoint ep = getEndpointByLabel(epLabel);
if (ep != null) {
// Check for an xAxis point
GraphNodeEndpoint xep = getEndpointByLabel("x" + (i + 1));
if (xep != null) {
disconnectEndpoint(xep);
getEndpointDefinitions().remove(xep);
}
// If we have a connection to this node, kill it
disconnectEndpoint(ep);
getEndpointDefinitions().remove(ep);
String propKey = "SERIES_" + i + "_LABEL";
GraphNodeProperty prop = getPropertyByName(propKey);
if (prop != null) {
getPropertyDefinitions().remove(prop);
((ObservableMap<String, Object>) getPropertyValueMap()).getWrappedMap().remove(propKey);
}
}
}
addMissingXAxii();
}
public void update(Observable o, Object modifiedKey) {
Map<String, Object> propertyMap = getPropertyValueMap();
// Check for X_AXIS_TYPE modifications
if ((modifiedKey != null) && ("X_AXIS_TYPE".equals((String) modifiedKey)) && (propertyMap.get("X_AXIS_TYPE") != null)) {
String newXAxisType = (String) propertyMap.get("X_AXIS_TYPE");
if ("Date (result set)".equals(newXAxisType)) {
removeAllXAxisEndpoints();
}
}
validateSeries();
}
}