/*******************************************************************************
* Copyright 2014 Miami-Dade County
*
* 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.
******************************************************************************/
package cirmlive;
import java.text.DateFormat;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.TreeSet;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.chart.PieChart;
import javafx.scene.control.ButtonBar;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.input.MouseEvent;
import org.sharegov.cirm.stats.CirmStatistics;
import org.sharegov.cirm.utils.JsonUtil;
/**
* Manages a FX piechart for CirmStats data display.
*
* @author Thomas Hilpold
*/
public class CirmPieChart {
enum SHOW_DATA {TOTAL, SUCCESS, FAILURE};
private ObservableList<PieChart.Data> pieChartData = FXCollections.observableArrayList();
private String title;
private PieChart chart;
private Map<String, CirmStatistics.StatsValue> pieChartDataDetail = new HashMap<>();
public CirmPieChart() {
chart = new PieChart(pieChartData);
chart.setTitle("Please select data");
pieChartData.add(new PieChart.Data("Zero results", 100));
chart.setStartAngle(90);
}
public PieChart getChart() {
return chart;
}
/**
* Updates pieChartData for the piechart, piechart will draw itself.
* @param statsKeyValMap
* @param componentFilter
* @param actionFilter
* @param dataFilter
* @param showData
*/
public void updateData(TreeMap<CirmStatistics.StatsKey, CirmStatistics.StatsValue> statsKeyValMap, String componentFilter, String actionFilter, SHOW_DATA showData){
long totalCount = 0;
long successCount = 0;
long failedCount = 0;
Date earlierst = new Date();
TreeSet<PieChart.Data> newData = new TreeSet<>(new CirmPieDataComparator());
pieChartDataDetail.clear();
for (Map.Entry<CirmStatistics.StatsKey, CirmStatistics.StatsValue> keyVal : statsKeyValMap.entrySet()) {
CirmStatistics.StatsKey key = keyVal.getKey();
CirmStatistics.StatsValue val = keyVal.getValue();
String type = key.gettype();
if (earlierst.after(val.getFirstEntryTime())) earlierst = val.getFirstEntryTime();
if (type.startsWith("legacy:")) type = type.substring("legacy:".length());
if (componentFilter.equals(key.getComponent()) && actionFilter.equals(key.getAction())
|| componentFilter.equals(CirmStatistics.ALL) && actionFilter.equals(key.getAction())
|| componentFilter.equals(key.getComponent()) && actionFilter.equals(CirmStatistics.ALL)
|| componentFilter.equals(CirmStatistics.ALL) && actionFilter.equals(CirmStatistics.ALL)) {
long value = 0;
if (showData.equals(SHOW_DATA.TOTAL)) {
value = val.getSuccessCount() + val.getFailureCount();
} else if (showData.equals(SHOW_DATA.SUCCESS)) {
value = val.getSuccessCount();
} else if (showData.equals(SHOW_DATA.FAILURE)) {
value = val.getFailureCount();
} else {
throw new IllegalArgumentException("SHOW_DATA was " + showData);
}
totalCount += (val.getSuccessCount() + val.getFailureCount());
successCount += val.getSuccessCount();
failedCount += val.getFailureCount();
if(value > 0) {
String chartKey = value + "-" + type;
newData.add(new PieChart.Data(chartKey, value));
pieChartDataDetail.put(chartKey, val);
}
} else {
//action does not match dataFilter
}
} // for
double failedPercent = totalCount == 0? 0 : ((failedCount * 100 * 100) / totalCount)/ 100.0;
String failed = "Failed: " + failedCount + " (" + failedPercent + "%)";
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM);
String titleSuffix;
if (showData.equals(SHOW_DATA.TOTAL)) {
titleSuffix = "\r\n Total : " + totalCount + " / " + failed + " since " + df.format(earlierst);
} else if (showData.equals(SHOW_DATA.SUCCESS)) {
titleSuffix = "\r\n Success : " + successCount + " / " + failed + " since " + df.format(earlierst);
} else {
titleSuffix = "\r\n " + failed + " since " + df.format(earlierst);
}
chart.setTitle(chart.getTitle() + titleSuffix);
//sort newdata desc
pieChartData.clear();
if (newData.isEmpty()) {
pieChartData.add(new PieChart.Data("No data to display", 1));
} else {
pieChartData.addAll(newData);
// for (PieChart.Data d : newData) {
// pieChartData.add(d);
// }
}
setInteraction();
}
public void setTitle(String title, Date d) {
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM);
String dateInTitle = "\r\n(" + df.format(d) + ")";
chart.setTitle(title + dateInTitle);
}
/**
* use if data is diff
* @param title
* @param from
* @param to
*/
public void setTitle(String title, Date from, Date to) {
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM);
String dateInTitle = "\r\n(" + df.format(from) + " to " + df.format(to) + ")";
chart.setTitle(title + dateInTitle);
}
/**
* To display the data ordered large pie to small pie.
*/
public static class CirmPieDataComparator implements Comparator<PieChart.Data> {
@Override
public int compare(PieChart.Data o1, PieChart.Data o2) {
int result = -Double.compare(o1.getPieValue(), o2.getPieValue());
if (result == 0) {
result = o1.getName().compareTo(o2.getName());
}
if (result == 0) {
result = Long.compare(o1.hashCode(), o2.hashCode());
}
return result;
}
}
/**
* Just a test for piechart clicks.
*/
public void setInteraction() {
// caption.setTextFill(Color.DARKORANGE);
// caption.setStyle("-fx-font: 24 arial;");
for (final PieChart.Data data : chart.getData()) {
data.getNode().addEventHandler(MouseEvent.MOUSE_PRESSED,
new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent e) {
Dialog dataDlg = new Dialog();
dataDlg.setTitle(data.getName());
String contentText;
if (pieChartDataDetail.containsKey(data.getName())) {
contentText = JsonUtil.format(pieChartDataDetail.get(data.getName()).toJson());
} else {
contentText = "No Data to display";
}
dataDlg.getDialogPane().setContentText(contentText);
ButtonType okButtonType = new ButtonType("Ok", ButtonBar.ButtonData.OK_DONE);
dataDlg.getDialogPane().getButtonTypes().add(okButtonType);
dataDlg.setResizable(true);
dataDlg.show();
//data.setName("Selected");
}
});
}
}
}