/*******************************************************************************
* Mission Control Technologies, Copyright (c) 2009-2012, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* The MCT platform is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* MCT includes source code licensed under additional open source licenses. See
* the MCT Open Source Licenses file included with this distribution or the About
* MCT Licenses dialog available at runtime from the MCT Help menu for additional
* information.
*******************************************************************************/
package gov.nasa.arc.mct.fastplot.view;
import gov.nasa.arc.mct.components.AbstractComponent;
import gov.nasa.arc.mct.components.FeedProvider;
import gov.nasa.arc.mct.components.FeedProvider.FeedType;
import gov.nasa.arc.mct.fastplot.bridge.PlotConstants;
import gov.nasa.arc.mct.fastplot.bridge.PlotConstants.AxisOrientationSetting;
import gov.nasa.arc.mct.fastplot.bridge.PlotView;
import gov.nasa.arc.mct.fastplot.policy.PlotViewPolicy;
import gov.nasa.arc.mct.fastplot.view.legend.AbstractLegendEntry;
import gov.nasa.arc.mct.fastplot.view.legend.LegendEntryView;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Manages the adding and removing of data feeds for plots.
*/
public class PlotDataAssigner {
private final static Logger logger = LoggerFactory.getLogger(PlotDataAssigner.class);
private PlotViewManifestation plotViewManifestation;
private Map<FeedProvider, AbstractComponent> components = new HashMap<FeedProvider, AbstractComponent>();
private final AtomicReference<Collection<FeedProvider>> feedProvidersRef;
private Collection<Collection<FeedProvider>> feedsToPlot;
private Collection<FeedProvider> predictiveFeeds;
PlotDataAssigner(PlotViewManifestation supportedPlotViewManifestation) {
plotViewManifestation = supportedPlotViewManifestation;
feedProvidersRef = new AtomicReference<Collection<FeedProvider>>(new ArrayList<FeedProvider>());
feedsToPlot = new ArrayList<Collection<FeedProvider>>();
predictiveFeeds = new ArrayList<FeedProvider>();
}
String getTimeSystemDefaultChoice() {
if (getTimeSystemChoices() != null) {
if (getTimeSystemChoices().iterator().hasNext()) {
return getTimeSystemChoices().iterator().next();
}
}
return null;
}
Set<String> getTimeSystemChoices() {
AbstractComponent[][] matrix = PlotViewPolicy.getPlotComponents(
plotViewManifestation.getManifestedComponent(),
useOrdinalPosition());
logger.debug("Time System matrix length: {}", matrix.length);
return aggregateTimeSystemChoices(matrix);
}
static Set<String> aggregateTimeSystemChoices(final AbstractComponent[][] matrix) {
Set<String> choices = new LinkedHashSet<String>();
for (AbstractComponent[] row : matrix) {
int numberOfItemsOnSubPlot = 0;
for (AbstractComponent component : row) {
if (numberOfItemsOnSubPlot < PlotConstants.MAX_NUMBER_OF_DATA_ITEMS_ON_A_PLOT) {
// Alternate implementation is getCapabilities() from each component, then get time system ID from each of fp.
FeedProvider fp = component.getCapability(FeedProvider.class);
if (fp != null) {
String[] timeSystems = fp.getTimeService().getTimeSystems();
if (timeSystems != null) {
for (int i=0; i<timeSystems.length; i++) {
choices.add(timeSystems[i]);
}
}
numberOfItemsOnSubPlot++;
}
}
}
}
return choices;
}
Set<String> getTimeFormatChoices() {
AbstractComponent[][] matrix = PlotViewPolicy.getPlotComponents(
plotViewManifestation.getManifestedComponent(),
useOrdinalPosition());
logger.debug("Time Formats matrix length: ", matrix.length);
return aggregateTimeFormatChoices(matrix);
}
static Set<String> aggregateTimeFormatChoices(final AbstractComponent[][] matrix) {
Set<String> choices = new LinkedHashSet<String>();
for (AbstractComponent[] row : matrix) {
int numberOfItemsOnSubPlot = 0;
for (AbstractComponent component : row) {
if (numberOfItemsOnSubPlot < PlotConstants.MAX_NUMBER_OF_DATA_ITEMS_ON_A_PLOT) {
FeedProvider fp = component.getCapability(FeedProvider.class);
if (fp != null) {
String[] timeFormats = fp.getTimeService().getTimeFormats();
if (timeFormats != null) {
for (int i=0; i<timeFormats.length; i++) {
choices.add(timeFormats[i]);
}
numberOfItemsOnSubPlot++;
}
}
}
}
}
return choices;
}
Collection<FeedProvider> getVisibleFeedProviders() {
if (!hasFeeds()) {
updateFeedProviders();
}
return feedProvidersRef.get();
}
Collection<FeedProvider> getPredictiveFeedProviders() {
if (!hasFeeds()) {
updateFeedProviders();
}
return predictiveFeeds;
}
void informFeedProvidersHaveChanged() {
updateFeedProviders();
}
int returnNumberOfSubPlots() {
return feedsToPlot.size();
}
private void updateFeedProviders() {
AbstractComponent[][] matrix = PlotViewPolicy.getPlotComponents(
plotViewManifestation.getManifestedComponent(),
useOrdinalPosition());
updateFeedProviders(matrix);
}
private boolean useOrdinalPosition() {
String groupByAsString = plotViewManifestation.getViewProperties().getProperty(PlotConstants.GROUP_BY_ORDINAL_POSITION, String.class);
return (groupByAsString == null || groupByAsString.isEmpty()) ? true : Boolean.valueOf(groupByAsString);
}
private void updateFeedProviders(AbstractComponent[][] matrix) {
ArrayList<FeedProvider> feedProviders = new ArrayList<FeedProvider>();
feedsToPlot.clear();
predictiveFeeds.clear();
for (AbstractComponent[] row : matrix) {
Collection<FeedProvider> feedsForThisLevel = new ArrayList<FeedProvider>(); //this should be LMIT
int numberOfItemsOnSubPlot = 0;
for (AbstractComponent component : row) {
if (numberOfItemsOnSubPlot < PlotConstants.MAX_NUMBER_OF_DATA_ITEMS_ON_A_PLOT) {
FeedProvider fp = plotViewManifestation.getFeedProvider(component);
if (fp != null) {
if(fp.getFeedType() != FeedType.STRING){ //only add to feed providers if not a string feed
feedProviders.add(fp);
if (fp.isPrediction()) {
predictiveFeeds.add(fp);
}
feedsForThisLevel.add(fp);
components.put(fp, component);
}
}
numberOfItemsOnSubPlot++;
}
}
feedsToPlot.add(feedsForThisLevel);
}
feedProviders.trimToSize();
feedProvidersRef.set(feedProviders);
}
/**
* Return true if the plot has feeds, false otherwise.
* @return
*/
boolean hasFeeds() {
return !feedProvidersRef.get().isEmpty();
}
void assignFeedsToSubPlots() {
assert feedsToPlot !=null : "Feeds to plot must be defined";
PlotView plot = plotViewManifestation.getPlot();
if (plot.getAxisOrientationSetting() == AxisOrientationSetting.Z_AXIS_AS_TIME) {
int count = 0;
// If we are non-time non-time, supply independent variable first
for (Collection<FeedProvider> feedsForSubPlot : feedsToPlot) {
String independent = null;
for (FeedProvider fp : feedsForSubPlot) {
String id = fp.getSubscriptionId();
if (independent == null) {
independent = id;
} else {
id = independent + PlotConstants.NON_TIME_FEED_SEPARATOR + id;
}
if (count < PlotConstants.MAX_NUMBER_OF_DATA_ITEMS_ON_A_PLOT) {
AbstractComponent comp = components.get(fp);
AbstractLegendEntry legendEntry = (AbstractLegendEntry) LegendEntryView.VIEW_INFO.createView(comp);
plot.addDataSet(0, id, legendEntry);
count++;
}
}
}
} else {
// Add feeds to the plot.
int subPlotNumber = 0;
for (Collection<FeedProvider> feedsForSubPlot : feedsToPlot) {
assert feedsForSubPlot != null;
int numberOfItemsOnSubPlot = 0;
for (FeedProvider fp : feedsForSubPlot) {
if (numberOfItemsOnSubPlot < PlotConstants.MAX_NUMBER_OF_DATA_ITEMS_ON_A_PLOT) {
plot.addDataSet(subPlotNumber, fp.getSubscriptionId(),
fp.getLegendText());
numberOfItemsOnSubPlot++;
}
}
subPlotNumber++;
}
}
}
}