package com.caseystella.output;
import com.caseystella.summarize.Summary;
import com.caseystella.summarize.TotalSummary;
import com.google.common.base.Function;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import com.googlecode.lanterna.TerminalSize;
import com.googlecode.lanterna.TextCharacter;
import com.googlecode.lanterna.TextColor;
import com.googlecode.lanterna.gui2.*;
import com.googlecode.lanterna.gui2.dialogs.ActionListDialogBuilder;
import com.googlecode.lanterna.gui2.table.Table;
import com.googlecode.lanterna.screen.Screen;
import com.googlecode.lanterna.screen.TerminalScreen;
import com.googlecode.lanterna.terminal.DefaultTerminalFactory;
import com.googlecode.lanterna.terminal.Terminal;
import scala.Tuple2;
import javax.annotation.Nullable;
import java.io.IOException;
import java.text.NumberFormat;
import java.util.*;
public class CursesVisualize {
public void display(final TotalSummary totalSummary) throws IOException {
// Setup terminal and screen layers
Terminal terminal = new DefaultTerminalFactory().createTerminal();
Screen screen = new TerminalScreen(terminal);
screen.startScreen();
Table<String> connectedColumns = new Table<>("Col 1", "Col 2");
connectedColumns.setVisibleRows(10);
for(Map<String, Object> columnConn : totalSummary.getConnectedColumns()) {
String col1 = (String)columnConn.get("column 1");
String col2 = (String)columnConn.get("column 2");
connectedColumns.getTableModel().addRow(col1 + " ", col2);
}
// Create gui and start gui
final MultiWindowTextGUI gui = new MultiWindowTextGUI(screen, new DefaultWindowManager(), new EmptySpace(TextColor.ANSI.BLUE));
final BasicWindow window = new BasicWindow();
window.setHints(Arrays.asList(Window.Hint.CENTERED));
window.setCloseWindowWithEscape(true);
Panel panel = new Panel();
panel.setLayoutManager(new GridLayout(1).setVerticalSpacing(1).setHorizontalSpacing(0));
/*
Panel panel = new Panel();
final ComboBox<String> comboBox = new ComboBox<String>().setReadOnly(false);
for(Map.Entry<String, Summary> kv : totalSummary.getColumnSummaries().entrySet()) {
comboBox.addItem(kv.getKey());
}
Button button = new Button("Show", new Runnable() {
@Override
public void run() {
String column = comboBox.getSelectedItem();
Summary summary = totalSummary.getColumnSummaries().get(column);
new ColumnDisplayer(gui, summary, column).run();
}
});
panel.addComponent(new Label("Column Statistical Details"));
panel.addComponent(new EmptySpace(new TerminalSize(0, 0))); // Empty space underneath labels
panel.addComponent(comboBox);
panel.addComponent(button);
panel.addComponent(new Label("Interesting Connections\nBased on Loglikelihood"));
panel.addComponent(new EmptySpace(new TerminalSize(0,0))); // Empty space underneath labels
panel.addComponent(connectedColumns);
*/
ActionListBox actionListBox = new ActionListBox();
NumberFormat percentFormatter;
percentFormatter = NumberFormat.getPercentInstance();
for(Map.Entry<String, Summary> kv : totalSummary.getColumnSummaries().entrySet()) {
double percentMissing = kv.getValue().getNumInvalid().doubleValue() / kv.getValue().getTotalCount();
String actionName = kv.getKey() + " (" +percentFormatter.format(percentMissing) + " Missing)";
actionListBox.addItem(actionName, new ColumnDisplayer(gui, kv.getValue(), kv.getKey()));
}
panel.addComponent(new Label("Column Statistical Details"));
panel.addComponent(actionListBox);
window.setComponent(panel);
gui.addWindowAndWait(window);
}
public static class ColumnDisplayer implements Runnable {
Summary columnSummary;
MultiWindowTextGUI gui;
String column;
public ColumnDisplayer(MultiWindowTextGUI gui, Summary columnSummary, String column) {
this.columnSummary = columnSummary;
this.gui = gui;
this.column = column;
}
public Table<String> getCountTable() {
Table<String> table = new Table<>("Type", "Modifier", "Count", "Distinct Count");
table.setVisibleRows(5);
Map<Tuple2<String, String>, Tuple2<String, String>> aggregateMap = new HashMap<>();
for(Map<String, Object> map : columnSummary.getCountByType()) {
String typeMod = map.get("type").toString();
Iterable<String> it = Splitter.on(":").split(typeMod);
String type = Iterables.getFirst(it, null);
String modifier = Iterables.getLast(it, null);
String count = map.get("count").toString();
aggregateMap.put(new Tuple2<>(type, modifier), new Tuple2<>(count , "0"));
}
for(Map<String, Object> map : columnSummary.getCountDistinctByType()) {
String typeMod = map.get("type").toString();
Iterable<String> it = Splitter.on(":").split(typeMod);
String type = Iterables.getFirst(it, null);
String modifier = Iterables.getLast(it, null);
String count = map.get("count").toString();
Tuple2<String, String> key = new Tuple2<>(type, modifier);
Tuple2<String, String> val = aggregateMap.get(key);
aggregateMap.put(key, new Tuple2<>(val._1, count));
}
for(Map.Entry<Tuple2<String, String>, Tuple2<String, String>> kv : aggregateMap.entrySet()) {
table.getTableModel().addRow(kv.getKey()._1, kv.getKey()._2, kv.getValue()._1, kv.getValue()._2);
}
return table;
}
public Table<String> getSimilarityTable(Map<String, String> entries) {
Table<String> t = new Table<>("word", "synonym");
t.setVisibleRows(5);
for(Map.Entry<String, String> synonyms : entries.entrySet()) {
t.getTableModel().addRow(trim(synonyms.getKey(), 20), trim(synonyms.getValue(), 20));
}
return t;
}
public static String trim(String s, int numChars) {
if(s.length() > numChars) {
return s.substring(0, numChars) + "...";
}
return s;
}
public Map<String, Table<String>> getValueTable() {
Map<String, Table<String>> ret = new HashMap<>();
for(Map<String, Object> kv : columnSummary.getNonNumericValueSummary()) {
String typeMod = kv.get("type").toString();
Iterable<String> it = Splitter.on(":").split(typeMod);
String type = Iterables.getFirst(it, null);
String modifier = Iterables.getLast(it, null);
Map<String, Double> valueMap = (Map<String, Double>) kv.get("summary");
Table<String> t = new Table<>("Canonical Value", "Count");
t.setVisibleRows(5);
for(Map.Entry<String, Double> summarykv : valueMap.entrySet()) {
t.getTableModel().addRow(summarykv.getKey(), summarykv.getValue().longValue() + "");
}
ret.put("Canonical Representation Count\n" + modifier + " " + type , t );
}
for(Map<String, Object> kv : columnSummary.getNumericValueSummary()) {
String typeMod = kv.get("type").toString();
Iterable<String> it = Splitter.on(":").split(typeMod);
String type = Iterables.getFirst(it, null);
String modifier = Iterables.getLast(it, null);
Map<String, Double> valueMap = new TreeMap<>((Map<String, Double>) kv.get("summary"));
Table<String> t = new Table<>("Statistic", "Value");
t.setVisibleRows(5);
for(Map.Entry<String, Double> summarykv : valueMap.entrySet()) {
t.getTableModel().addRow(summarykv.getKey(), summarykv.getValue().longValue() + "");
}
ret.put("Distributional Summary\n" + modifier + " " + type, t );
}
return ret;
}
@Override
public void run() {
// Create panel to hold components
final BasicWindow window = new BasicWindow();
window.setHints(Arrays.asList(Window.Hint.FULL_SCREEN));
Panel panel = new Panel();
panel.setLayoutManager(new GridLayout(2).setHorizontalSpacing(2).setVerticalSpacing(2));
panel.addComponent(new Label("Summary for " + column));
panel.addComponent(new EmptySpace(new TerminalSize(0, 0))); // Empty space underneath labels
panel.addComponent(new Label("Count Statistics"));
panel.addComponent(getCountTable());
for(Map.Entry<String, Table<String>> labelTable : getValueTable().entrySet()) {
panel.addComponent(new Label(labelTable.getKey()));
panel.addComponent(labelTable.getValue());
}
panel.addComponent(new Label("Possible Value Synonymns"));
panel.addComponent(getSimilarityTable(columnSummary.getSynonyms()));
window.setCloseWindowWithEscape(true);
// Create window to hold the panel
window.setComponent(panel);
gui.addWindow(window);
gui.waitForWindowToClose(window);
gui.addWindowAndWait(gui.getWindows().iterator().next());
}
}
}