package com.joe.facelets.table;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
public class ListTableSource extends TableSource
{
private List<Row> allRows = new ArrayList<Row>();
private List<Row> visibleRows = new ArrayList<Row>();
private Comparator<Row> defaultSort = null;
public ListTableSource(List<Column> columns, List<Row> rows)
{
this(columns, rows, null);
}
public ListTableSource(List<Column> columns, List<Row> rows, Comparator<Row> defaultSort)
{
super(columns);
this.defaultSort = defaultSort;
setData(rows);
}
public Comparator<Row> getDefaultSort()
{
return defaultSort;
}
public void setDefaultSort(Comparator<Row> defaultSort)
{
this.defaultSort = defaultSort;
}
public void setData(List<Row> rows)
{
this.allRows = rows;
this.visibleRows = rows;
refresh();
}
@Override
public DataModel getDataModel()
{
if (hasSortChanged())
{
refresh();
}
if (hasFilterChanged())
{
filterRows();
}
return new ListDataModel(visibleRows);
}
public void refresh()
{
sortRows(allRows);
filterRows();
}
public void sortRows(List<Row> rows)
{
if (defaultSort != null && (sortKey == null || "".equals(sortKey)))
{
Collections.sort(rows, defaultSort);
}
else
{
CustomComparator sort = null;
Column sortColumn = getColumn(sortKey);
if (sortColumn != null)
{
sort = sortColumn.getSort();
}
if (sort != null)
{
sort.setDecending(sortDecending);
Collections.sort(rows, sort);
}
else
{
Collections.sort(rows, new RowComparator(sortKey, sortDecending));
}
}
oldKey = sortKey;
oldDecending = sortDecending;
}
public Column getColumn(String name)
{
for (Column c : columns)
{
if (c.getKey().equals(name))
{
return c;
}
}
return null;
}
public void filterRows()
{
visibleRows = new ArrayList<Row>();
for (Row row : allRows)
{
boolean match = true;
for (Column c : columns)
{
if (c.getFilter() != null)
{
Object o = row.get(c.getKey());
if (o == null)
o = "";
if (!c.getFilter().isMatch(o))
{
match = false;
break;
}
}
}
if (match)
{
visibleRows.add(row);
}
}
}
public static class RowComparator extends CustomComparator
{
String key;
public RowComparator(String key, boolean dec)
{
this.key = key;
this.setDecending(dec);
}
@SuppressWarnings("unchecked")
@Override
public int compare(Row o1, Row o2)
{
Comparable val1 = (Comparable) o1.get(key);
Comparable val2 = (Comparable) o2.get(key);
int direction = (isDecending()) ? 1 : -1;
if (val1 == null && val2 == null)
return 0;
if (val1 == null)
{
return direction * 1;
}
if (val2 == null)
{
return direction * -1;
}
return direction * val1.compareTo(val2);
}
}
public static class MultiKeyComparator extends CustomComparator
{
final LinkedHashMap<String, String> keys;
public MultiKeyComparator()
{
this.keys = new LinkedHashMap<String, String>();
}
public void addSortKey(final String key)
{
keys.put(key, "");
}
public void addSortKey(final String key, final String dateFormat)
{
keys.put(key, dateFormat);
}
@SuppressWarnings("unchecked")
@Override
public int compare(final Row o1, final Row o2)
{
boolean isFirstColumn = true;
for (final Map.Entry<String, String> entry : this.keys.entrySet())
{
final String key = entry.getKey();
final String dateFormat = entry.getValue();
final int direction;
if (isFirstColumn)
{
isFirstColumn = false;
direction = (super.decending ? 1 : -1);
}
else
{
// Secondary sort is always ascending (A-Z)
direction = 1;
}
final Comparable val1 = formatForSort(o1.get(key), dateFormat);
final Comparable val2 = formatForSort(o2.get(key), dateFormat);
if(val1 == null && val2 == null) continue;
if(val1 == null) {
return direction * -1;
}
if(val2 == null) {
return direction * 1;
}
final int compare = val1.compareTo(val2);
if (0 != compare)
{
return direction * compare;
}
}
return 0;
}
}
@SuppressWarnings("unchecked")
private static Comparable formatForSort(final Object obj, final String dateFormat)
{
final Comparable cmp;
if (obj == null) return null;
if (obj instanceof String)
{
if (null != dateFormat && 0 < dateFormat.length())
{
cmp = formatDateForSort((String) obj, dateFormat);
}
else
{
cmp = ((String) obj).toLowerCase().trim();
}
}
else
{
cmp = (Comparable) obj;
}
return (null != cmp ? cmp : "");
}
private static Date formatDateForSort(final String s, final String dateFormat)
{
Date d = null;
try
{
d = new SimpleDateFormat(dateFormat).parse(s);
}
catch (final ParseException ex)
{
// Do nothing.
}
return d;
}
public static abstract class CustomComparator implements Comparator<Row>
{
boolean decending = true;
public boolean isDecending()
{
return decending;
}
public void setDecending(boolean decending)
{
this.decending = decending;
}
}
@Override
public List<Row> getFilteredRows()
{
return visibleRows;
}
@Override
public List<Row> getRows()
{
return allRows;
}
}