package holeg.ui.view.information; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.GridLayout; import java.awt.Insets; import java.util.HashMap; import java.util.List; import java.util.Optional; import java.util.function.Predicate; import java.util.logging.Logger; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.swing.BorderFactory; import javax.swing.JLabel; import javax.swing.JLayeredPane; import javax.swing.JPanel; import javax.swing.OverlayLayout; import javax.swing.border.EmptyBorder; import org.knowm.xchart.PieChart; import org.knowm.xchart.PieChartBuilder; import org.knowm.xchart.PieSeries.PieSeriesRenderStyle; import org.knowm.xchart.XChartPanel; import org.knowm.xchart.style.PieStyler; import org.knowm.xchart.style.PieStyler.LabelType; import holeg.model.Flexibility; import holeg.model.GroupNode; import holeg.model.HolonElement; import holeg.model.HolonObject; import holeg.model.HolonObject.HolonObjectState; import holeg.preferences.ColorPreference; import holeg.ui.controller.Control; import holeg.utility.math.decimal.Format; import holeg.ui.model.GuiSettings; //TODO(Tom2022-01-13): Fix; public class HolonInformationPanel extends JPanel { private static final Logger log = Logger.getLogger(JPanel.class.getName()); //private Predicate stateFilter = (object) -> true;// = (object) -> object.getState() == // HolonObjectState.PRODUCER; private Predicate priorityFilter = (ele) -> true; private final int defaultWidth = 50; private final int defaultHeight = 200; private static final Color[] supplyStateColors = new Color[] { ColorPreference.HolonObject.Producer, ColorPreference.HolonObject.OverSupplied, ColorPreference.HolonObject.Supplied, ColorPreference.HolonObject.PartiallySupplied, ColorPreference.HolonObject.NotSupplied, ColorPreference.HolonObject.NoEnergy }; private static final Color[] productionColors = new Color[] { ColorPreference.Energy.Production, ColorPreference.Energy.Consumption }; private static final Color[] activeColors = new Color[] { ColorPreference.Element.Active, ColorPreference.Element.Inactive }; private static final Color[] flexibilityColors = new Color[] { ColorPreference.Flexibility.Offered, ColorPreference.Flexibility.InUse, ColorPreference.Flexibility.OnCooldown, ColorPreference.Flexibility.NotOffered, ColorPreference.Flexibility.Unavailable, ColorPreference.Element.Priority.NoData }; private static final Color[] priorityColors = new Color[] { ColorPreference.Element.Priority.Essential, ColorPreference.Element.Priority.High, ColorPreference.Element.Priority.Medium, ColorPreference.Element.Priority.Low, ColorPreference.Element.Priority.NoData }; private PieChart supplyChart = createSupplyStateChart(); private PieChart priorityChart = createPriorityChart(); private PieChart flexibilityChart = createFlexibilityChart(); private PieChart energyChart = createProductionChart(); private PieChart activeChart = createActiveChart(); private XChartPanel panelHolonObject; private XChartPanel panelPriority; private XChartPanel panelFlexibility; private XChartPanel panelEnergy; private XChartPanel panelActive; private JPanel graphPanel = new JPanel(new GridLayout(0, 2)); private JPanel titlePanel = new JPanel(new BorderLayout(0, 0)); private Control control; private JLabel differenceEnergyLabelAmount = new JLabel(""); public HolonInformationPanel(Control control) { control.OnSelectionChanged.addListener(() -> updateCharts()); this.control = control; this.setLayout(new BorderLayout()); initGraphPanel(); initTitlePanel(); this.setBackground(ColorPreference.Panel.Background); this.add(titlePanel, BorderLayout.PAGE_START); this.add(graphPanel, BorderLayout.CENTER); } public void updateCharts() { if (GuiSettings.getSelectedObjects().isEmpty()) { return; } Optional filteredGroupNode = multiSelectionToFilterableGroupNode(); if(filteredGroupNode.isEmpty()) { return; } FilterableGroupNode decoratedGroupNode = filteredGroupNode.get(); // UPDATE SUPPLY STATE // int producerAmount = decoratedGroupNode.getAmountOfSupplier(stateFilter); // int overSuppliedAmount = decoratedGroupNode.getAmountOfConsumerWithState(stateFilter, // HolonObjectState.OVER_SUPPLIED); // int suppliedAmount = decoratedGroupNode.getAmountOfConsumerWithState(stateFilter, HolonObjectState.SUPPLIED); // int partiallySuppliedAmount = decoratedGroupNode.getAmountOfConsumerWithState(stateFilter, // HolonObjectState.PARTIALLY_SUPPLIED); // int notSuppliedAmount = decoratedGroupNode.getAmountOfConsumerWithState(stateFilter, // HolonObjectState.NOT_SUPPLIED); // int noEnergyAmount = decoratedGroupNode.getAmountOfPassiv(stateFilter); // // supplyChart.updatePieSeries("Producer", producerAmount); // supplyChart.updatePieSeries("Over supplied", overSuppliedAmount); // supplyChart.updatePieSeries("Supplied", suppliedAmount); // supplyChart.updatePieSeries("Partial supplied", partiallySuppliedAmount); // supplyChart.updatePieSeries("Not supplied", notSuppliedAmount); // supplyChart.updatePieSeries("No energy", noEnergyAmount); // UPDATE PRIORITYS // holeg.ui.view.information.FilterableGroupNode.PriorityCounts priorityCounts = decoratedGroupNode // .getPriorityCounts(stateFilter); // // priorityChart.updatePieSeries("Essential", priorityCounts.essential); // priorityChart.updatePieSeries("High", priorityCounts.high); // priorityChart.updatePieSeries("Medium", priorityCounts.medium); // priorityChart.updatePieSeries("Low", priorityCounts.low); // boolean hasPriority = priorityCounts.essential + priorityCounts.high + priorityCounts.medium // + priorityCounts.low > 0; // priorityChart.updatePieSeries("No Data", hasPriority ? 0 : 1); // updateToolTips(panelPriority); // UPDATE PRODUCTION // float production = decoratedGroupNode.getProduction(stateFilter, priorityFilter); // float consumption = decoratedGroupNode.getConsumption(stateFilter, priorityFilter); // log.info("production" + production + " consumption" + consumption); // float difference = Math.abs(production - consumption); // energyChart.updatePieSeries("Production", production); // energyChart.updatePieSeries("Consumption", consumption); // differenceEnergyLabelAmount.setText(Format.doubleFixedPlaces(1, difference)); // // // UPDATE FLEXIBILITIES // int inUse = 0; // int offered = 0; // int onCooldown = 0; // int notOffered = 0; // int unavailable = 0; // // Stream flexWrapperStream = decoratedGroupNode.getFlexibilitiesStream(stateFilter, priorityFilter); // List flexList = flexWrapperStream.collect(Collectors.toList()); // for (Flexibility flex : flexList) { // switch (flex.getState()) { // case IN_USE: // inUse++; // break; // case NOT_OFFERED: // notOffered++; // break; // case OFFERED: // offered++; // break; // case ON_COOLDOWN: // onCooldown++; // break; // case UNAVAILABLE: // unavailable++; // break; // default: // break; // // } // } // flexibilityChart.updatePieSeries("Offered", offered); // flexibilityChart.updatePieSeries("In use", inUse); // flexibilityChart.updatePieSeries("On cooldown", onCooldown); // flexibilityChart.updatePieSeries("Not offered", notOffered); // flexibilityChart.updatePieSeries("Unavailable", unavailable); // boolean hasFlex = offered + inUse + onCooldown + notOffered + unavailable > 0; // flexibilityChart.updatePieSeries("No Data", hasFlex ? 0 : 1); // // UPDATE ActiveInActive // int activeAmount = decoratedGroupNode.getAmountOfAktiveElementsFromHolonObjects(stateFilter, priorityFilter); // int inactiveAmounts = decoratedGroupNode.getAmountOfElementsFromHolonObjects(stateFilter, priorityFilter) // - activeAmount; // activeChart.updatePieSeries("Active", activeAmount); // activeChart.updatePieSeries("Inactive", inactiveAmounts); this.revalidate(); this.repaint(); } private Optional multiSelectionToFilterableGroupNode() { // FilterableGroupNode temp = new FilterableGroupNode(new GroupNode("Temp"), // control.getModel().getCurrentIteration()); // Optional visState = control.getSimManager().getActualVisualRepresentationalState(); // if(visState.isEmpty()) { // return Optional.empty(); // } // // // GroupNodes // HashMap accessMapGroupNode = visState.get().getCreatedGroupNodes(); // List groupNodeList = GuiSettings.getSelectedObjects().stream() // .filter(object -> object instanceof GroupNode).map(object -> accessMapGroupNode.get(object)) // .map(node -> new FilterableGroupNode(node, control.getModel().getCurrentIteration())) // .collect(Collectors.toList()); // // temp.getGroupNodeList().addAll(groupNodeList); // // // HolonObjects // HashMap accessMapHolonObject = visState.get().createdHolonObjects; // List holonObjectList = GuiSettings.getSelectedObjects().stream() // .filter(object -> object instanceof HolonObject).map(object -> accessMapHolonObject.get(object)) // .collect(Collectors.toList()); // // for (DecoratedHolonObject object : holonObjectList) { // switch (object.getState()) { // case NO_ENERGY: // temp.getPassivList().add((Passiv) object); // break; // case PRODUCER: // temp.getSupplierList().add((Supplier) object); // break; // default: // temp.getConsumerList().add((Consumer) object); // break; // } // } // return Optional.of(temp); return Optional.empty(); } public void initGraphPanel() { graphPanel.setBackground(ColorPreference.Panel.Background); panelHolonObject = new XChartPanel(supplyChart); panelHolonObject.setBackground(ColorPreference.Panel.Background); graphPanel.add(panelHolonObject); panelPriority = new XChartPanel(priorityChart); panelPriority.setBackground(ColorPreference.Panel.Background); graphPanel.add(panelPriority); panelFlexibility = new XChartPanel(flexibilityChart); panelFlexibility.setBackground(ColorPreference.Panel.Background); graphPanel.add(panelFlexibility); Component panel = initEnergyChart(); graphPanel.add(panel); panelActive = new XChartPanel(activeChart); panelActive.setBackground(ColorPreference.Panel.Background); panelActive.setLayout(new GridBagLayout()); graphPanel.add(panelActive); graphPanel.setBorder(BorderFactory.createLineBorder(Color.lightGray)); } private JLayeredPane initEnergyChart() { JLayeredPane panel = new JLayeredPane(); JPanel panelMiddle = new JPanel(new GridBagLayout()); panelEnergy = new XChartPanel(energyChart); panelEnergy.setBackground(ColorPreference.Panel.Background); GridBagConstraints c = new GridBagConstraints(); c.gridx = 0; c.gridy = 0; c.insets = new Insets(15, 0, 0, 0); // top padding JLabel difference = new JLabel("Difference:"); difference.setHorizontalAlignment(JLabel.CENTER); difference.setAlignmentX(Component.CENTER_ALIGNMENT); difference.setForeground(ColorPreference.Panel.Title); difference.setFont(new java.awt.Font("Arial", java.awt.Font.BOLD, 10)); panelMiddle.add(difference, c); differenceEnergyLabelAmount.setHorizontalAlignment(JLabel.CENTER); differenceEnergyLabelAmount.setForeground(Color.red); differenceEnergyLabelAmount.setAlignmentX(Component.CENTER_ALIGNMENT); differenceEnergyLabelAmount.setFont(new java.awt.Font("Arial", java.awt.Font.BOLD, 12)); c.insets = new Insets(0, 0, 0, 0); c.gridy = 1; panelMiddle.add(differenceEnergyLabelAmount, c); panel.setLayout(new OverlayLayout(panel)); panelEnergy.setOpaque(false); panelMiddle.setOpaque(false); panel.add(panelMiddle, Integer.valueOf(0)); panel.add(panelEnergy, Integer.valueOf(1)); return panel; } public void initTitlePanel() { titlePanel.setBackground(ColorPreference.Panel.Background); titlePanel.setBorder(new EmptyBorder(5, 5, 2, 0)); } public void setDefaultPieChartSettings(PieChart chart) { PieStyler styler = chart.getStyler(); styler.setChartTitleVisible(true); styler.setDefaultSeriesRenderStyle(PieSeriesRenderStyle.Donut); styler.setLabelsFont(new java.awt.Font("Arial", java.awt.Font.PLAIN, 14)); styler.setLabelType(LabelType.Percentage); styler.setLabelsFontColor(Color.black); styler.setLabelsFontColorAutomaticEnabled(false); styler.setLabelsDistance(0.8); styler.setChartFontColor(ColorPreference.Panel.Title); styler.setToolTipsEnabled(true); styler.setPlotContentSize(0.9); styler.setPlotBackgroundColor(ColorPreference.Panel.Transparent); styler.setPlotBorderColor(ColorPreference.Panel.Transparent); styler.setLegendVisible(false); styler.setChartBackgroundColor(ColorPreference.Panel.Transparent); } public PieChart createSupplyStateChart() { PieChart chart = new PieChartBuilder().width(defaultWidth).height(defaultHeight).title("Holon Objects").build(); setDefaultPieChartSettings(chart); chart.getStyler().setSeriesColors(supplyStateColors); // Series chart.addSeries("Producer", 0); chart.addSeries("Over supplied", 0); chart.addSeries("Supplied", 0); chart.addSeries("Partial supplied", 0); chart.addSeries("Not supplied", 0); chart.addSeries("No energy", 0); return chart; } public PieChart createPriorityChart() { PieChart chart = new PieChartBuilder().width(defaultWidth).height(defaultHeight).title("Priotities").build(); setDefaultPieChartSettings(chart); // Customize Chart chart.getStyler().setSeriesColors(priorityColors); // Series chart.addSeries("Essential", 0); chart.addSeries("High", 0); chart.addSeries("Medium", 0); chart.addSeries("Low", 0); chart.addSeries("No Data", 0); return chart; } public PieChart createFlexibilityChart() { PieChart chart = new PieChartBuilder().width(defaultWidth).height(defaultHeight).title("Flexibilities").build(); setDefaultPieChartSettings(chart); // Customize Chart chart.getStyler().setSeriesColors(flexibilityColors); // Series chart.addSeries("Offered", 0); chart.addSeries("In use", 0); chart.addSeries("On cooldown", 0); chart.addSeries("Not offered", 0); chart.addSeries("Unavailable", 0); chart.addSeries("No Data", 0); return chart; } public PieChart createProductionChart() { PieChart chart = new PieChartBuilder().width(defaultWidth).height(defaultHeight) .title("Production vs. Consumption").build(); setDefaultPieChartSettings(chart); // Customize Chart // Customize Chart chart.getStyler().setSeriesColors(productionColors); // Series chart.addSeries("Production", 0); chart.addSeries("Consumption", 0); return chart; } public PieChart createActiveChart() { PieChart chart = new PieChartBuilder().width(defaultWidth).height(defaultHeight).title("Active").build(); setDefaultPieChartSettings(chart); // Customize Chart // Customize Chart chart.getStyler().setSeriesColors(activeColors); // Series chart.addSeries("Active", 0); chart.addSeries("Inactive", 0); return chart; } }