package com.sequenceiq.cloudbreak.shell.support;
import static java.util.Collections.singletonList;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.shell.support.table.Table;
import org.springframework.shell.support.table.TableHeader;
import org.springframework.stereotype.Component;
/**
* Utility class used to render tables.
*/
@Component
public class TableRenderer {
public static final int THREE = 3;
/**
* Renders a 2 columns wide table with the given headers and rows. If headers are provided it should match with the
* number of columns.
*
* @param rows rows of the table
* @param headers headers of the table
* @return the formatted table
*/
public <E> String renderSingleMapWithSortedColumn(Map<E, String> rows, String... headers) {
return renderMultiValueMap(convert(rows), true, headers);
}
/**
* Renders a 2 columns wide table with the given headers and rows. If headers are provided it should match with the
* number of columns.
*
* @param rows rows of the table, each value will be added as a new row with the same key
* @param sortByFirstColumn sortByFirstColumn rows by the first column
* @param headers headers of the table
* @return formatted table
*/
public String renderMultiValueMap(Map<String, List<String>> rows, boolean sortByFirstColumn, String... headers) {
Table table = createTable(headers);
if (rows != null) {
List<Map.Entry<String, List<String>>> entries = new ArrayList<>(rows.entrySet());
if (sortByFirstColumn) {
Collections.sort(entries, new Comparator<Map.Entry<String, List<String>>>() {
@Override
public int compare(Map.Entry<String, List<String>> a, Map.Entry<String, List<String>> b) {
if (isEmpty(a) || isEmpty(b)) {
return compareKeys(a, b);
}
int comp = a.getValue().get(0).compareToIgnoreCase(b.getValue().get(0));
return comp == 0 ? compareKeys(a, b) : comp;
}
private int compareKeys(Map.Entry<String, List<String>> a, Map.Entry<String, List<String>> b) {
return a.getKey().compareToIgnoreCase(b.getKey());
}
private boolean isEmpty(Map.Entry<String, List<String>> input) {
return input.getValue() == null || input.getValue().isEmpty() || input.getValue().get(0) == null;
}
});
} else {
Collections.sort(entries, (a, b) -> a.getKey().compareToIgnoreCase(b.getKey()));
}
for (Map.Entry<String, List<String>> entry : entries) {
if (entry.getValue() != null) {
for (String value : entry.getValue()) {
table.addRow(entry.getKey(), value);
}
}
}
}
return format(table);
}
public <E> String renderObjectValueMap(Map<String, E> rows, String mainHeader) {
Table table = new Table();
List<String> mainHeaders = new ArrayList<>();
if (rows != null) {
int index = 0;
for (String key1 : rows.keySet()) {
Object value = rows.get(key1);
if (value != null) {
Field[] fields = value.getClass().getDeclaredFields();
if (index == 0) {
List<String> headers = new ArrayList<>();
headers.add(mainHeader);
for (Field classField : fields) {
if (!classField.getName().equals(mainHeader)) {
headers.add(classField.getName());
mainHeaders.add(classField.getName());
}
}
table = createTable(headers.toArray(new String[headers.size()]));
}
List<String> rowValues = new ArrayList<>();
rowValues.add(key1);
for (Field classField : fields) {
if (mainHeaders.contains(classField.getName())) {
classField.setAccessible(true);
Object o = runGetter(classField, value);
if (o != null) {
rowValues.add(o.toString());
}
}
}
table.addRow(rowValues.toArray(new String[rowValues.size()]));
index++;
}
}
}
return format(table);
}
private Object runGetter(Field field, Object o) {
for (Method method : o.getClass().getMethods()) {
if ((method.getName().startsWith("get")) && (method.getName().length() == (field.getName().length() + THREE))) {
if (method.getName().toLowerCase().endsWith(field.getName().toLowerCase())) {
try {
return method.invoke(o);
} catch (Exception e) {
return null;
}
}
}
}
return null;
}
private static Table createTable(String... headers) {
Table table = new Table();
if (headers != null) {
int column = 1;
for (String header : headers) {
table.addHeader(column++, new TableHeader(header));
}
}
return table;
}
private static <E> Map<String, List<String>> convert(Map<E, String> map) {
Map<String, List<String>> result = new HashMap<>();
if (map != null) {
for (E key : map.keySet()) {
if (map.get(key) != null) {
result.put(key.toString(), singletonList(map.get(key)));
}
}
}
return result;
}
private static <E> Map<String, List<String>> convertObjectMap(Map<String, E> map) {
Map<String, List<String>> result = new HashMap<>();
if (map != null) {
for (String key : map.keySet()) {
if (map.get(key) != null) {
result.put(key, singletonList(map.get(key).toString()));
}
}
}
return result;
}
private static String format(Table table) {
table.calculateColumnWidths();
return table.toString();
}
}