package netflix.adminresources.tableview;
import com.google.common.collect.Lists;
import com.google.gson.JsonArray;
import com.google.gson.JsonPrimitive;
import netflix.adminresources.resources.PropertiesHelper;
import netflix.adminresources.resources.model.Property;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class PropsTableView implements TableViewResource {
private static final Logger LOG = LoggerFactory.getLogger(PropsTableView.class);
private final Map<String, Column> columnMap = new LinkedHashMap<String, Column>();
public static final String KEY = "Key";
public static final String VALUE = "Value";
private static class Column {
String name;
String searchTerm;
boolean enableSort;
boolean isDescendingSort;
}
private static class PageInfo {
int startIndex;
int count;
}
public PropsTableView() {
LOG.debug("Creating a new propsTableViewResource ");
Column keyCol = new Column();
keyCol.name = KEY;
Column valCol = new Column();
valCol.name = VALUE;
columnMap.put(KEY, keyCol);
columnMap.put(VALUE, valCol);
}
private String allColumnSearchTerm;
private PageInfo currentPage;
private int totalRecords;
private int numFilteredRecords;
@Override
public List<String> getColumns() {
return new ArrayList<String>(columnMap.keySet());
}
@Override
public TableViewResource setColumnSearchTerm(String column, String term) {
if (columnMap.containsKey(column)) {
columnMap.get(column).searchTerm = term;
}
return this;
}
@Override
public TableViewResource setAllColumnsSearchTerm(String term) {
allColumnSearchTerm = term;
return this;
}
@Override
public TableViewResource enableColumnSort(String column, boolean isDescending) {
if (columnMap.containsKey(column)) {
columnMap.get(column).isDescendingSort = isDescending;
columnMap.get(column).enableSort = true;
}
return this;
}
@Override
public JsonArray getData() {
JsonArray props = new JsonArray();
List<Property> properties = PropertiesHelper.getAllProperties();
totalRecords = properties.size();
numFilteredRecords = totalRecords;
List<Property> propsFiltered = applyFilter(properties);
List<Property> propsSorted = applySorting(propsFiltered);
List<Property> propsCurrentPage = applyPagination(propsSorted);
for (Property property : propsCurrentPage) {
JsonArray propArr = new JsonArray();
JsonPrimitive propName = new JsonPrimitive(property.getName());
JsonPrimitive propValue = new JsonPrimitive(property.getValue());
propArr.add(propName);
propArr.add(propValue);
props.add(propArr);
}
return props;
}
@Override
public int getTotalNumOfRecords() {
return totalRecords;
}
@Override
public int getFilteredNumOfRecords() {
return numFilteredRecords;
}
@Override
public TableViewResource setCurrentPageInfo(int startIndex, int count) {
PageInfo pageInfo = new PageInfo();
pageInfo.count = count;
pageInfo.startIndex = startIndex;
currentPage = pageInfo;
return this;
}
private List<Property> applyPagination(List<Property> properties) {
if (!isPaginated()) {
return properties;
}
List<Property> propertyList = Lists.newArrayList();
int index = 0;
int endIndex = currentPage.startIndex + currentPage.count;
for (Property property : properties) {
if (index >= currentPage.startIndex && index < endIndex) {
propertyList.add(property);
}
if (index >= endIndex) {
// no need to scan further elements
break;
}
index++;
}
return propertyList;
}
private boolean isPaginated() {
return currentPage != null;
}
private List<Property> applyFilter(List<Property> propsCurrentPage) {
if (allColumnSearchTerm != null && !allColumnSearchTerm.isEmpty()) {
return applyAllColumnsFilter(propsCurrentPage);
} else if (columnSearchTermExists()) {
return applyColumnFilters(propsCurrentPage);
}
return propsCurrentPage;
}
private List<Property> applyColumnFilters(List<Property> propsCurrentPage) {
final String propKeySearchTerm = getPropKeySearchTerm();
final String propValueSearchTerm = getPropValueSearchTerm();
List<Property> filteredList = Lists.newArrayList();
int index = 0;
for (Property property : propsCurrentPage) {
String propName = property.getName().toLowerCase();
String propValue = property.getValue().toLowerCase();
boolean matched = true;
if (propKeySearchTerm != null) {
matched = propName.contains(propKeySearchTerm);
}
if (propValueSearchTerm != null) {
matched = matched && (propValue.contains(propValueSearchTerm));
}
if (matched) {
filteredList.add(property);
index++;
}
}
numFilteredRecords = index;
return filteredList;
}
private List<Property> applyAllColumnsFilter(List<Property> propsCurrentPage) {
final String searchTermLowerCase = allColumnSearchTerm.toLowerCase();
List<Property> filteredList = Lists.newArrayList();
int index = 0;
for (Property property : propsCurrentPage) {
String propName = property.getName().toLowerCase();
String propValue = property.getValue().toLowerCase();
if (propName.contains(searchTermLowerCase) || propValue.contains(searchTermLowerCase)) {
filteredList.add(property);
index++;
}
}
numFilteredRecords = index;
return filteredList;
}
private boolean columnSearchTermExists() {
for (Map.Entry<String, Column> columnEntry : columnMap.entrySet()) {
final Column col = columnEntry.getValue();
if (col.searchTerm != null) {
return true;
}
}
return false;
}
private String getPropKeySearchTerm() {
return columnMap.get(KEY).searchTerm;
}
private String getPropValueSearchTerm() {
return columnMap.get(VALUE).searchTerm;
}
private List<Property> applySorting(List<Property> propsFiltered) {
Column sortOnColumn = null;
for (Column column : columnMap.values()) {
if (column.enableSort) {
sortOnColumn = column;
break;
}
}
if (sortOnColumn != null) {
final boolean sortOnKey = sortOnColumn.name.equals(KEY);
final boolean isDescending = sortOnColumn.isDescendingSort;
Collections.sort(propsFiltered, new Comparator<Property>() {
@Override
public int compare(Property property, Property property2) {
if (sortOnKey) {
if (isDescending) {
return property2.getName().compareTo(property.getName());
}
return property.getName().compareTo(property2.getName());
} else {
// sort on value
if (isDescending) {
return property2.getValue().compareTo(property.getValue());
}
return property.getValue().compareTo(property2.getValue());
}
}
});
}
return propsFiltered;
}
}