/**
*
* Copyright
* 2009-2015 Jayway Products AB
* 2016-2017 Föreningen Sambruk
*
* Licensed under AGPL, Version 3.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.gnu.org/licenses/agpl.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package se.streamsource.dci.value.table;
import org.qi4j.api.util.DateFunctions;
import org.qi4j.api.util.Function;
import org.qi4j.api.value.ValueBuilder;
import org.qi4j.api.value.ValueBuilderFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import se.streamsource.dci.value.table.gdq.OrderByDirection;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import static java.util.Collections.reverseOrder;
/**
* JAVADOC
*/
public class TableBuilder
{
private static final Logger LOGGER = LoggerFactory.getLogger( TableBuilder.class );
protected ValueBuilderFactory vbf;
private Map<String, TableBuilderFactory.Column> columns;
private TableQuery tableQuery;
protected ValueBuilder<TableValue> tableBuilder;
protected ValueBuilder<RowValue> rowBuilder;
public TableBuilder(ValueBuilderFactory vbf)
{
this.vbf = vbf;
tableBuilder = vbf.newValueBuilder(TableValue.class);
}
public TableBuilder(ValueBuilderFactory vbf, Map<String, TableBuilderFactory.Column> columns, TableQuery tableQuery)
{
this.vbf = vbf;
this.columns = columns;
this.tableQuery = tableQuery;
tableBuilder = vbf.newValueBuilder(TableValue.class);
if (tableQuery.select().size()==1 && "*".equals(tableQuery.select().get(0)))
{
for (TableBuilderFactory.Column column : columns.values())
{
column(column.getId(), column.getLabel(), column.getType());
}
} else
{
for (String columnName : tableQuery.select())
{
TableBuilderFactory.Column column = columns.get(columnName.trim());
if (column != null)
column(column.getId(), column.getLabel(), column.getType());
}
}
}
public TableBuilder column(String id, String label, String type)
{
ValueBuilder<ColumnValue> builder = vbf.newValueBuilder(ColumnValue.class);
builder.prototype().id().set(id);
builder.prototype().label().set(label);
builder.prototype().columnType().set(type);
tableBuilder.prototype().cols().get().add(builder.newInstance());
return this;
}
public TableBuilder rows(Iterable<?> rowObjects)
{
boolean no_format = false;
boolean no_values = false;
if (tableQuery != null && tableQuery.options() != null)
{
if (tableQuery.options().contains("no_format"))
no_format = true;
if (tableQuery != null && tableQuery.options().contains("no_values"))
no_values = true;
}
for (Object rowObject : rowObjects)
{
if( rowObject == null )
{
LOGGER.warn( "Encountered null object while building row.");
continue;
}
row();
for (ColumnValue columnValue : tableBuilder.prototype().cols().get())
{
Object v = null;
String f = null;
Function valueFunction = columns.get(columnValue.id().get()).getValueFunction();
if (!no_values && valueFunction != null)
v = valueFunction.map(rowObject);
Function formattedFunction = columns.get(columnValue.id().get()).getFormattedFunction();
if (!no_format && formattedFunction != null)
f = (String) formattedFunction.map(rowObject);
else if (v != null)
{
if (columnValue.columnType().get().equals(TableValue.DATETIME))
f = DateFunctions.toUtcString((Date) v);
else if (columnValue.columnType().get().equals(TableValue.DATE))
f = new SimpleDateFormat( "yyyy-MM-dd").format((Date) v);
else if (columnValue.columnType().get().equals(TableValue.TIME_OF_DAY))
f = new SimpleDateFormat( "HH:mm:ss").format((Date) v);
else
f = v.toString();
}
cell(v, f);
}
endRow();
}
return this;
}
public TableBuilder row()
{
if (rowBuilder != null)
endRow();
rowBuilder = vbf.newValueBuilder(RowValue.class);
return this;
}
public TableBuilder endRow()
{
tableBuilder.prototype().rows().get().add(rowBuilder.newInstance());
rowBuilder = null;
return this;
}
public TableBuilder cell(Object v, String f)
{
ValueBuilder<CellValue> cellBuilder = vbf.newValueBuilder(CellValue.class);
cellBuilder.prototype().v().set(v);
cellBuilder.prototype().f().set(f);
rowBuilder.prototype().c().get().add(cellBuilder.newInstance());
return this;
}
public TableBuilder orderBy()
{
// TODO support multiple order by
if (tableQuery.orderBy() != null && tableQuery.orderBy().size() == 1)
{
// Sort table
// Find sort column index
String orderByName = tableQuery.orderBy().get(0).name;
boolean descending = tableQuery.orderBy().get(0).direction == OrderByDirection.DESCENDING;
int sortIndex = -1;
List<ColumnValue> columnValues = tableBuilder.prototype().cols().get();
for (int i = 0; i < columnValues.size(); i++)
{
ColumnValue columnValue = columnValues.get(i);
if (columnValue.id().get().equals(orderByName))
{
sortIndex = i;
break;
}
}
if (sortIndex != -1)
{
final int idx = sortIndex;
Comparator<RowValue> comparator = new Comparator<RowValue>()
{
public int compare(RowValue o1, RowValue o2)
{
Object o = o1.c().get().get(idx).v().get();
if (o != null && o instanceof Comparable)
{
Comparable c1 = (Comparable) o;
Comparable c2 = (Comparable) o2.c().get().get(idx).v().get();
return c1.compareTo(c2);
} else
{
String f1 = o1.c().get().get(idx).f().get();
String f2 = o2.c().get().get(idx).f().get();
return f1.compareTo(f2);
}
}
};
if (descending)
{
// Flip it
comparator = reverseOrder(comparator);
}
Collections.sort(tableBuilder.prototype().rows().get(), comparator);
}
}
return this;
}
// public TableBuilder orderBy()
// {
// if (tableQuery.orderBy() != null)
// {
// // Sort table
// // Find sort column index
// int sortIndex = -1;
// List<ColumnValue> columnValues = tableBuilder.prototype().cols().get();
// for (int i = 0; i < columnValues.size(); i++)
// {
// ColumnValue columnValue = columnValues.get(i);
// if (columnValue.id().equals(tableQuery.orderBy()))
// {
// sortIndex = i;
// break;
// }
//
// }
//
// if (sortIndex != -1)
// {
// final int idx = sortIndex;
// Comparator<RowValue> comparator = new Comparator<RowValue>()
// {
// public int compare(RowValue o1, RowValue o2)
// {
// Object o = o1.c().get().get(idx).v().get();
//
// if (o != null && o instanceof Comparable)
// {
// Comparable c1 = (Comparable) o;
// Comparable c2 = (Comparable) o2.c().get().get(idx).v().get();
// return c1.compareTo(c2);
// } else
// {
// String f1 = o1.c().get().get(idx).f().get();
// String f2 = o2.c().get().get(idx).f().get();
// return f1.compareTo(f2);
// }
// }
// };
//
// Collections.sort(tableBuilder.prototype().rows().get(), comparator);
// }
// }
//
// return this;
// }
public TableBuilder paging()
{
// Paging
int start = 0;
int end = tableBuilder.prototype().rows().get().size();
if (tableQuery.offset() != null)
start = tableQuery.offset();
if (tableQuery.limit() != null)
end = Math.min(end, start + tableQuery.limit());
if (!(start == 0 && end == tableBuilder.prototype().rows().get().size()))
tableBuilder.prototype().rows().set(tableBuilder.prototype().rows().get().subList(start, end));
return this;
}
public TableValue newTable()
{
if (rowBuilder != null)
endRow();
return tableBuilder.newInstance();
}
public void abortRow()
{
rowBuilder = null;
}
}