package org.apache.slide.projector.processor.table;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.slide.projector.ConfigurationException;
import org.apache.slide.projector.Context;
import org.apache.slide.projector.ProcessException;
import org.apache.slide.projector.Result;
import org.apache.slide.projector.Store;
import org.apache.slide.projector.descriptor.ArrayValueDescriptor;
import org.apache.slide.projector.descriptor.MapValueDescriptor;
import org.apache.slide.projector.descriptor.NumberValueDescriptor;
import org.apache.slide.projector.descriptor.ParameterDescriptor;
import org.apache.slide.projector.descriptor.StringValueDescriptor;
import org.apache.slide.projector.i18n.ErrorMessage;
import org.apache.slide.projector.i18n.ParameterMessage;
import org.apache.slide.projector.processor.SimpleProcessor;
import org.apache.slide.projector.processor.TemplateMapRenderer;
import org.apache.slide.projector.util.StoreHelper;
import org.apache.slide.projector.value.ArrayValue;
import org.apache.slide.projector.value.MapValue;
import org.apache.slide.projector.value.NullValue;
import org.apache.slide.projector.value.NumberValue;
import org.apache.slide.projector.value.StreamableValue;
import org.apache.slide.projector.value.StringValue;
import org.apache.slide.projector.value.Value;
public class TableMapRenderer extends TemplateMapRenderer {
final protected static String HEADER_FRAGMENT = "header";
final protected static String FOOTER_FRAGMENT = "footer";
final protected static String FIRST_FRAGMENT = "first";
final protected static String LAST_FRAGMENT = "last";
final protected static String EVEN_FRAGMENT = "even";
final protected static String DEFAULT_FRAGMENT = "default";
final protected static String EMPTY_FRAGMENT = "empty";
final static String OFFSET = "offset";
final static String ITEMS_PER_PAGE = "itemsPerPage";
final static String LENGTH = "length";
protected Template headerTemplate;
protected Template footerTemplate;
protected Template firstTemplate;
protected Template lastTemplate;
protected Template evenTemplate;
protected Template defaultTemplate;
protected Template emptyTemplate;
private ParameterDescriptor []parameterDescriptors;
private String[] repeatedFragments;
public TableMapRenderer() {
setRequiredFragments(new String[] { DEFAULT_FRAGMENT });
setOptionalFragments(new String[] { EMPTY_FRAGMENT, HEADER_FRAGMENT, FOOTER_FRAGMENT, FIRST_FRAGMENT, LAST_FRAGMENT, EVEN_FRAGMENT });
setRepeatedFragments(new String[] { FIRST_FRAGMENT, LAST_FRAGMENT, DEFAULT_FRAGMENT, EVEN_FRAGMENT });
}
public void configure(StreamableValue config) throws ConfigurationException {
super.configure(config);
ParameterDescriptor []parentParameterDescriptors = super.getParameterDescriptors();
// remove fragment parameter
List parameterDescriptorList = new ArrayList();
for ( int i = 0; i < parentParameterDescriptors.length; i++ ) {
ParameterDescriptor descriptor = parentParameterDescriptors[i];
if ( descriptor.getName() != FRAGMENT ) {
if ( descriptor.getName().equals(SimpleProcessor.INPUT) ) {
// check if entry descriptor is caused by repeated fragments
List entryDescriptors = ((MapValueDescriptor)descriptor.getValueDescriptor()).getEntryDescriptors();
for ( Iterator j = entryDescriptors.iterator(); j.hasNext(); ) {
ParameterDescriptor entryDescriptor = (ParameterDescriptor)j.next();
if ( !repeatedParameterDescriptor(entryDescriptor) ) {
parameterDescriptorList.add(entryDescriptor);
j.remove();
}
}
parameterDescriptorList.add(new ParameterDescriptor(SimpleProcessor.INPUT, new ParameterMessage("tableMapRenderer/input"), new ArrayValueDescriptor(parentParameterDescriptors[i].getValueDescriptor())));
} else {
parameterDescriptorList.add(descriptor);
}
}
}
parameterDescriptorList.add(new ParameterDescriptor(OFFSET, new ParameterMessage("tableRenderer/offset"), new NumberValueDescriptor(), new NumberValue(new Integer(0))));
parameterDescriptorList.add(new ParameterDescriptor(ITEMS_PER_PAGE, new ParameterMessage("tableRenderer/length"), new NumberValueDescriptor(), new NumberValue(new Integer(-10))));
parameterDescriptorList.add(new ParameterDescriptor(TableHandler.ID, new ParameterMessage("tableRenderer/id"), new StringValueDescriptor(), new StringValue("table")));
parameterDescriptorList.add(new ParameterDescriptor(TableHandler.STORE, new ParameterMessage("tableRenderer/store"), new StringValueDescriptor(Store.stores), new StringValue(Store.stores[Store.SESSION])));
parameterDescriptorList.add(new ParameterDescriptor(TableHandler.SORTED_BY, new ParameterMessage("tableHandler/sortedBy"), new StringValueDescriptor(), NullValue.NULL));
parameterDescriptorList.add(new ParameterDescriptor(TableHandler.ORDER, new ParameterMessage("tableHandler/order"), new StringValueDescriptor(new String[] {TableHandler.ASCENDING, TableHandler.DESCENDING}), NullValue.NULL));
parameterDescriptors = (ParameterDescriptor[] )parameterDescriptorList.toArray(new ParameterDescriptor[parameterDescriptorList.size()]);
headerTemplate = getOptionalFragment(HEADER_FRAGMENT);
footerTemplate = getOptionalFragment(FOOTER_FRAGMENT);
firstTemplate = getOptionalFragment(FIRST_FRAGMENT);
lastTemplate = getOptionalFragment(LAST_FRAGMENT);
evenTemplate = getOptionalFragment(EVEN_FRAGMENT);
emptyTemplate = getOptionalFragment(EMPTY_FRAGMENT);
try {
defaultTemplate = getRequiredFragment(DEFAULT_FRAGMENT);
} catch ( ProcessException exception ) {
throw new ConfigurationException(new ErrorMessage("tableRenderer/fragmentsMissing"), exception);
}
}
public Result process(Map parameter, Context context) throws Exception {
StringBuffer buffer = new StringBuffer(1024);
ArrayValue input = (ArrayValue)parameter.get(SimpleProcessor.INPUT);
NumberValue offsetResource = (NumberValue)parameter.get(OFFSET);
NumberValue itemsPerPageResource = (NumberValue)parameter.get(ITEMS_PER_PAGE);
Value sortedByParameter = (Value)parameter.get(TableHandler.SORTED_BY);
Value orderParameter = (Value)parameter.get(TableHandler.ORDER);
String sortedBy = null, order = null;
if ( sortedByParameter != NullValue.NULL ) sortedBy = sortedByParameter.toString();
if ( orderParameter != NullValue.NULL ) order = orderParameter.toString();
String id = parameter.get(TableHandler.ID).toString();
Store store = context.getStore(StoreHelper.getStoreByName(parameter.get(TableHandler.STORE).toString()));
MapValue idResource = (MapValue)store.get(id);
Map tableMap;
if ( idResource == null) {
tableMap = new HashMap();
MapValue tableState = new MapValue(tableMap);
store.put(id, tableState);
} else {
tableMap = idResource.getMap();
NumberValue offset = (NumberValue)idResource.getMap().get(TableHandler.CURRENT_POSITION);
if ( offset != null ) offsetResource = offset;
NumberValue itemsPerPage = (NumberValue)idResource.getMap().get(ITEMS_PER_PAGE);
if ( itemsPerPage != null ) itemsPerPageResource = itemsPerPage;
Value sortedByValue = (Value)idResource.getMap().get(TableHandler.SORTED_BY);
if ( sortedByValue != null && sortedByValue != NullValue.NULL ) sortedBy = sortedByValue.toString();
Value orderValue = (Value)idResource.getMap().get(TableHandler.ORDER);
if ( orderValue != null && orderValue != NullValue.NULL ) order = orderValue.toString();
}
// sort table
if ( sortedBy != null && order != null ) {
Comparator comparator = new RowComparator(sortedBy, order);
Arrays.sort(input.getArray(), comparator);
}
tableMap.put(TableHandler.CURRENT_POSITION, offsetResource);
tableMap.put(ITEMS_PER_PAGE, itemsPerPageResource);
int offset = offsetResource.getNumber().intValue();
int length = itemsPerPageResource.getNumber().intValue();
parameter.remove(OFFSET);
parameter.remove(ITEMS_PER_PAGE);
int maxIndex = input.getArray().length;
tableMap.put(LENGTH, new NumberValue(new Integer(maxIndex)));
offset = Math.min(offset, maxIndex);
if ( length > 0 ) {
length = Math.min(length, maxIndex-offset);
} else {
length = maxIndex-offset;
}
if ( maxIndex == 0 ) {
if ( emptyTemplate != null ) emptyTemplate.evaluate(buffer, parameter);
} else {
if ( headerTemplate != null ) headerTemplate.evaluate(buffer, parameter);
for ( int i = 0; i < length; i++ ) {
// Enable the use of input parameters to provide default values for optional row parameters
Map rowParameter = new HashMap();
rowParameter.putAll(parameter);
Map repeatedParameter = ((MapValue)input.getArray()[i+offset]).getMap();
for ( Iterator j = repeatedParameter.entrySet().iterator(); j.hasNext(); ) {
Map.Entry entry = (Map.Entry)j.next();
if ( !(entry.getValue() instanceof NullValue) ) {
rowParameter.put(entry.getKey(), entry.getValue());
}
}
if ( i == 0 && firstTemplate != null ) {
firstTemplate.evaluate(buffer, rowParameter);
} else if ( i == length -1 && lastTemplate != null ) {
lastTemplate.evaluate(buffer, rowParameter);
} else if ( evenTemplate != null && i%2 == 0 ) {
evenTemplate.evaluate(buffer, rowParameter);
} else {
defaultTemplate.evaluate(buffer, rowParameter);
}
}
if ( footerTemplate != null ) footerTemplate.evaluate(buffer, parameter);
}
return new Result(OK, OUTPUT, new StringValue(buffer.toString(), defaultTemplate.getContentType(), false ));
}
public ParameterDescriptor[] getParameterDescriptors() {
return parameterDescriptors;
}
public void setRepeatedFragments(String[] repeatedFragments) {
this.repeatedFragments = repeatedFragments;
}
protected boolean repeatedParameterDescriptor(ParameterDescriptor entryDescriptor) {
List parameterDescriptors = getTemplateParameterDescriptor(repeatedFragments);
if ( parameterDescriptors.contains(entryDescriptor) ) {
return true;
}
return false;
}
protected class RowComparator implements Comparator {
private String sortBy, order;
public RowComparator(String sortBy, String order) {
this.sortBy = sortBy;
this.order = order;
}
public int compare(Object o1, Object o2) {
Map map1 = ((MapValue)o1).getMap();
Map map2 = ((MapValue)o2).getMap();
Object v1 = map1.get(sortBy);
Object v2 = map2.get(sortBy);
int comparison = 0;
if ( v1 instanceof Comparable ) {
comparison = ((Comparable)v1).compareTo(v2);
if ( order.equals(TableHandler.ASCENDING) ) {
comparison = -comparison;
}
}
return comparison;
}
}
}