/*
CloudTrail Viewer, is a Java desktop application for reading AWS CloudTrail logs
files.
Copyright (C) 2017 Mark P. Haskins
This program is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software Foundation,
either version 3 of the License, or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.haskins.java.cloudtrailviewer.controller.widget;
import de.jensd.fx.glyphs.fontawesome.FontAwesomeIconView;
import io.haskins.java.cloudtrailviewer.controller.components.WidgetControlsController;
import io.haskins.java.cloudtrailviewer.controller.components.WidgetControlsControllerListener;
import io.haskins.java.cloudtrailviewer.model.DashboardWidget;
import io.haskins.java.cloudtrailviewer.model.DialogAction;
import io.haskins.java.cloudtrailviewer.model.observable.KeyIntegerValue;
import io.haskins.java.cloudtrailviewer.model.event.Event;
import io.haskins.java.cloudtrailviewer.service.DatabaseService;
import io.haskins.java.cloudtrailviewer.service.EventTableService;
import io.haskins.java.cloudtrailviewer.service.listener.EventServiceListener;
import io.haskins.java.cloudtrailviewer.utils.DragResizeWidget;
import io.haskins.java.cloudtrailviewer.utils.EventUtils;
import io.haskins.java.cloudtrailviewer.utils.OnDragResizeEventListener;
import io.haskins.java.cloudtrailviewer.utils.WidgetUtils;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.layout.BorderPane;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Abstract class that all Widget controllers should extend.
*
* Created by markhaskins on 13/01/2017.
*/
public abstract class AbstractBaseController
extends BorderPane
implements EventServiceListener, OnDragResizeEventListener, WidgetControlsControllerListener {
final static Logger LOGGER = Logger.getLogger("CloudTrail");
public final static String WIDGET_TYPE_TOP = "Top";
public final static String WIDGET_TYPE_ALL = "All";
private final List<Event> allEvents = new ArrayList<>();
final Map<String, List<Event>> keyValueMap = new HashMap<>();
final ObservableList<KeyIntegerValue> keyValueData = FXCollections.observableArrayList();
final Map<String, String> latlngs = new HashMap<>();
DashboardWidget widget;
EventTableService eventTableService;
DatabaseService databaseService;
BorderPane fxmlObject = null;
private final List<WidgetListener> listeners = new ArrayList<>();
@FXML private BorderPane widgetContainer;
@FXML WidgetControlsController widgetControlsController;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///// abstract methods
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public abstract BorderPane loadFXML();
abstract FontAwesomeIconView getWidgetIcon();
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///// public methods
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void configure(DashboardWidget widget, EventTableService eventTableService, DatabaseService databaseService) {
this.widget = widget;
this.widget.setIcon(getWidgetIcon());
this.eventTableService = eventTableService;
this.databaseService = databaseService;
widgetControlsController.init(this, widget);
widgetContainer.setLayoutX(widget.getXPos());
widgetContainer.setLayoutY(widget.getYPos());
widgetContainer.setPrefWidth(widget.getWidth());
widgetContainer.setPrefHeight(widget.getHeight());
DragResizeWidget.makeResizable(widgetContainer, this);
}
public DashboardWidget getWidget() {
return this.widget;
}
public BorderPane getFXMLObject() {
return this.fxmlObject;
}
public void addWidgetListener(WidgetListener l) {
listeners.add(l);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///// protected methods
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
List<Map.Entry<String,Integer>> getTopEvents() {
Map<String, Integer> eventsByOccurance = new HashMap<>();
for (Map.Entry<String, List<Event>> entry : keyValueMap.entrySet()) {
eventsByOccurance.put(entry.getKey(), entry.getValue().size());
}
if (!eventsByOccurance.isEmpty()) {
List<Map.Entry<String,Integer>> sorted = entriesSortedByValues(eventsByOccurance);
if (widget.getType().equalsIgnoreCase(WIDGET_TYPE_TOP) && widget.getTop() > 0) {
return getTopX(sorted, widget.getTop());
} else {
return sorted;
}
} else {
return new ArrayList<>();
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///// private methods
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private void addToKeyValueMap(Event event) {
try {
String propertyValue = EventUtils.getEventProperty(this.widget.getSeriesField(), event);
if (propertyValue != null) {
List<Event> events;
if (!keyValueMap.containsKey(propertyValue)) {
events = new ArrayList<>();
} else {
events = keyValueMap.get(propertyValue);
}
events.add(event);
keyValueMap.put(propertyValue, events);
}
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Exception caught trying to add Event to KeyValueMap");
}
}
private List<Map.Entry<String,Integer>> getTopX(List<Map.Entry<String,Integer>> sorted, int top) {
List<Map.Entry<String,Integer>> topEvents = new ArrayList<>();
int count = top;
if (sorted.size() < count) {
count = sorted.size();
}
for (int i=0; i<count; i++) {
topEvents.add(sorted.get(i));
}
return topEvents;
}
private <K,V extends Comparable<? super V>> List<Map.Entry<K, V>> entriesSortedByValues(Map<K,V> map) {
List<Map.Entry<K,V>> sortedEntries = new ArrayList<>(map.entrySet());
sortedEntries.sort((e1, e2) -> e2.getValue().compareTo(e1.getValue()));
return sortedEntries;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///// EventServiceListener methods
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void newEvent(Event event) {
allEvents.add(event);
try {
String latLng = event.getLatLng();
if (latLng!= null && !latlngs.containsKey(latLng)) {
String propertyValue = EventUtils.getEventProperty(this.widget.getSeriesField(), event);
latlngs.put(latLng, propertyValue);
}
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Exception caught trying to add Event to KeyValueMap");
}
addToKeyValueMap(event);
}
public abstract void finishedLoading(boolean reload);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///// EventServiceListener methods
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Override
public void onDrag(double x, double y) {
widgetContainer.setLayoutX(x);
widgetContainer.setLayoutY(y);
widget.setXPos(x);
widget.setYPos(y);
}
@Override
public void onResize(double h, double w) {
widgetContainer.setPrefWidth(w);
widgetContainer.setPrefHeight(h);
widget.setWidth(w);
widget.setHeight(h);
}
@Override
public void clearEvents() {
allEvents.clear();
keyValueMap.clear();
keyValueData.clear();
latlngs.clear();
finishedLoading(true);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///// FXML methods
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void removeWidget() {
for (WidgetListener l : listeners) {
l.removeWidget(this);
}
}
public void editWidget() {
DialogAction action = WidgetUtils.showWidgetDialog(widget, true);
if (action.getActionCode() != DialogAction.ACTION_CANCEL) {
widgetControlsController.setTitle(widget.getTitle());
keyValueMap.clear();
keyValueData.clear();
for (Event event : allEvents) {
addToKeyValueMap(event);
}
finishedLoading(true);
}
}
}