001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-present, by David Gilbert and Contributors.
006 *
007 * Project Info:  http://www.jfree.org/jfreechart/index.html
008 *
009 * This library is free software; you can redistribute it and/or modify it
010 * under the terms of the GNU Lesser General Public License as published by
011 * the Free Software Foundation; either version 2.1 of the License, or
012 * (at your option) any later version.
013 *
014 * This library is distributed in the hope that it will be useful, but
015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
017 * License for more details.
018 *
019 * You should have received a copy of the GNU Lesser General Public
020 * License along with this library; if not, write to the Free Software
021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
022 * USA.
023 *
024 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 
025 * Other names may be trademarks of their respective owners.]
026 *
027 * ---------------------
028 * FlowDatasetUtils.java
029 * ---------------------
030 * (C) Copyright 2022-present, by David Gilbert and Contributors.
031 *
032 * Original Author:  David Gilbert;
033 * Contributor(s):   -;
034 *
035 */
036
037package org.jfree.data.flow;
038
039import java.util.List;
040import org.jfree.chart.util.Args;
041
042/**
043 * Utility methods related to {@link FlowDataset}.
044 * 
045 * @since 1.5.3
046 */
047public class FlowDatasetUtils {
048    
049    private FlowDatasetUtils() {
050        // no need for instantiation
051    }
052
053    /**
054     * Returns the total inflow for the specified node (a destination node for
055     * the specified stage).
056     * 
057     * @param <K> the type for the flow identifiers.
058     * @param dataset  the dataset ({@code null} not permitted).
059     * @param node  the node ({@code null} not permitted).
060     * @param stage  the stage.
061     * 
062     * @return The total inflow volume. 
063     */
064    public static <K extends Comparable<K>> double calculateInflow(FlowDataset<K> dataset, K node, int stage) {
065        Args.nullNotPermitted(dataset, "dataset");
066        Args.nullNotPermitted(node, "node");
067        Args.requireInRange(stage, "stage", 0, dataset.getStageCount());
068        if (stage == 0) {
069            return 0.0;  // there are no inflows for stage 0
070        }
071        double inflow = 0.0;
072        List<K> sourceKeys = dataset.getSources(stage - 1);
073        for (K key : sourceKeys) {
074            Number n = dataset.getFlow(stage - 1, key, node);
075            if (n != null) {
076                inflow = inflow + n.doubleValue();
077            }
078        }
079        return inflow;
080    }
081
082    /**
083     * Returns the total outflow for the specified node (a source node for the
084     * specified stage).
085     * 
086     * @param <K> the type for the flow identifiers.
087     * @param dataset  the dataset ({@code null} not permitted).
088     * @param source  the source node ({@code null} not permitted).
089     * @param stage  the stage.
090     * 
091     * @return The total outflow volume.
092     */
093    public static <K extends Comparable<K>> double calculateOutflow(FlowDataset<K> dataset, K source, int stage) {
094        Args.nullNotPermitted(dataset, "dataset");
095        Args.nullNotPermitted(source, "source");
096        Args.requireInRange(stage, "stage", 0, dataset.getStageCount());
097        if (stage == dataset.getStageCount()) {
098            return 0.0;  // there are no outflows for the last stage
099        }
100        double outflow = 0.0;
101        List<K> destinationKeys = dataset.getDestinations(stage);
102        for (K key : destinationKeys) {
103            Number n = dataset.getFlow(stage, source, key);
104            if (n != null) {
105                outflow = outflow + n.doubleValue();
106            }
107        }
108        return outflow;
109    }
110
111    /**
112     * Returns the total flow from all sources to all destinations at the 
113     * specified stage.
114     * 
115     * @param <K> the type for the flow identifiers.
116     * @param dataset  the dataset ({@code null} not permitted).
117     * @param stage  the stage.
118     * 
119     * @return The total flow.
120     */
121    public static <K extends Comparable<K>> double calculateTotalFlow(FlowDataset<K> dataset, int stage) {
122        Args.nullNotPermitted(dataset, "dataset");
123        double total = 0.0;
124        for (K source : dataset.getSources(stage)) {
125            for (K destination : dataset.getDestinations(stage)) {
126                Number flow = dataset.getFlow(stage, source, destination);
127                if (flow != null) {
128                    total = total + flow.doubleValue();
129                }
130            }
131        }
132        return total;
133    }
134    
135    /**
136     * Returns {@code true} if any of the nodes in the dataset have a property 
137     * 'selected' with the value {@code Boolean.TRUE}, and 
138     * {@code false} otherwise.
139     * 
140     * @param <K> the type for the node identifiers.
141     * @param dataset  the dataset ({@code null} not permitted).
142     * 
143     * @return A boolean. 
144     */
145    public static <K extends Comparable<K>> boolean hasNodeSelections(FlowDataset<K> dataset) {
146        Args.nullNotPermitted(dataset, "dataset");
147        for (int stage = 0; stage < dataset.getStageCount() + 1; stage++) { // '+1' to include final destination nodes 
148            for (K source : dataset.getSources(stage)) {
149                NodeKey<K> nodeKey = new NodeKey<>(stage, source);
150                if (Boolean.TRUE.equals(dataset.getNodeProperty(nodeKey, NodeKey.SELECTED_PROPERTY_KEY))) {
151                    return true;
152                }
153            }
154        }
155        return false;
156    }
157    
158    /**
159     * Returns the number of selected nodes.
160     * 
161     * @param <K> the type for the node keys.
162     * @param dataset  the dataset ({@code null} not permitted).
163     * 
164     * @return The number of selected nodes. 
165     */
166    public static <K extends Comparable<K>> int selectedNodeCount(FlowDataset<K> dataset) {
167        Args.nullNotPermitted(dataset, "dataset");
168        int result = 0;
169        for (int stage = 0; stage < dataset.getStageCount() + 1; stage++) { // '+1' to include final destination nodes 
170            for (K source : dataset.getSources(stage)) {
171                NodeKey<K> nodeKey = new NodeKey<>(stage, source);
172                if (Boolean.TRUE.equals(dataset.getNodeProperty(nodeKey, NodeKey.SELECTED_PROPERTY_KEY))) {
173                    result++;
174                }
175            }
176        }
177        return result;
178    }
179
180    /**
181     * Returns {@code true} if any of the flows in the dataset have a property 
182     * 'selected' with the value {@code Boolean.TRUE}, and 
183     * {@code false} otherwise.
184     * 
185     * @param <K> the type for the flow keys.
186     * @param dataset  the dataset ({@code null} not permitted).
187     * 
188     * @return A boolean. 
189     */
190    public static <K extends Comparable<K>> boolean hasFlowSelections(FlowDataset<K> dataset) {
191        Args.nullNotPermitted(dataset, "dataset");
192        for (int s = 0; s < dataset.getStageCount(); s++) { 
193            for (K source : dataset.getSources(s)) {
194                for (K destination : dataset.getDestinations(s)) {
195                    FlowKey<K> flowKey = new FlowKey<>(s, source, destination);
196                    if (Boolean.TRUE.equals(dataset.getFlowProperty(flowKey, FlowKey.SELECTED_PROPERTY_KEY))) {
197                        return true;
198                    }
199                }
200            }
201        }
202        return false;
203    }
204
205}
206