package er.extensions.components;
import java.util.Enumeration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.webobjects.appserver.WOComponent;
import com.webobjects.appserver.WOContext;
import com.webobjects.appserver.WORequest;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSMutableArray;
import er.extensions.eof.ERXConstant;
/**
* Table that can handle cell with row and colspans. Very useful with D2W to make more advance layouts.
*
* @binding col
* @binding index
* @binding list
* @binding maxColumns
* @binding row
* @binding item
* @binding border
* @binding cellpadding
* @binding cellspacing
* @binding rowBackgroundColor
* @binding cellColSpan
* @binding cellRowSpan
* @binding cellBackgroundColor
* @binding cellAlign
* @binding cellVAlign
* @binding cellWidth
* @binding tableBackgroundColor
* @binding tableWidth
* @binding otherTagString
*/
public class ERXLayoutTable extends WOComponent {
/**
* Do I need to update serialVersionUID?
* See section 5.6 <cite>Type Changes Affecting Serialization</cite> on page 51 of the
* <a href="http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf">Java Object Serialization Spec</a>
*/
private static final long serialVersionUID = 1L;
private static final Logger log = LoggerFactory.getLogger(ERXLayoutTable.class);
NSArray _list;
NSArray _colCounts;
int _maxColumns;
public int currentRow;
public int currentCol;
public int currentItemIndex;
public ERXLayoutTable(WOContext aContext) {
super(aContext);
_resetInternalCaches();
}
@Override
public boolean isStateless() {
return true;
}
protected int intForBinding(String name, int defaultValue) {
Object valueStr = valueForBinding(name);
if (valueStr != null) {
try {
int value = Integer.parseInt(valueStr.toString());
return value;
} catch (NumberFormatException e) {
throw new IllegalStateException("Problem parsing int from " + name + " binding "+e);
}
}
return defaultValue;
}
public int cellRowSpan() {
return intForBinding("cellRowSpan", 1);
}
public int cellColSpan() {
return intForBinding("cellColSpan", 1);
}
public int maxColumns() {
if (_maxColumns == -1) {
Object maxStr = valueForBinding("maxColumns");
if (maxStr != null) {
try {
_maxColumns = Integer.parseInt(maxStr.toString());
} catch (NumberFormatException e) {
throw new IllegalStateException("WOTable - problem parsing int from maxColumns binding "+e);
}
}
if (_maxColumns <= 0)
_maxColumns=1;
}
return _maxColumns;
}
public NSArray colCounts() {
if (_colCounts==null) {
_colCounts = (NSArray)valueForBinding("colCounts");
if(_colCounts == null) {
NSMutableArray colCounts = new NSMutableArray();
int maxColumns = maxColumns();
int row = 0;
int col = 0;
int index = 0;
int total = 0;
for (Enumeration iter = list().objectEnumerator(); iter.hasMoreElements();) {
Object item = iter.nextElement();
setValueForBinding(item, "item");
setValueForBinding(ERXConstant.integerForInt(row), "row");
setValueForBinding(ERXConstant.integerForInt(col), "col");
setValueForBinding(ERXConstant.integerForInt(index), "index");
int rowSpan = cellRowSpan();
int colSpan = cellColSpan();
// fill up rows until enough are present
// this currently doesn't work when a col has eaten all
for(int i = colCounts.count(); i < rowSpan + row; i++) {
colCounts.addObject(Integer.valueOf(maxColumns));
//log.info("Added: {} {}", item, colCounts);
}
//log.info("Start: {} {}/{} {}/{} {}", item, currentRow, rowSpan, currentCol, colSpan, colCounts);
for(int i = row; i < row + rowSpan; i++) {
int currentMaxColumns = ((Integer) colCounts.objectAtIndex(i)).intValue();
currentMaxColumns = currentMaxColumns - (colSpan - (i == row ? 1 : 0));
colCounts.replaceObjectAtIndex(Integer.valueOf(currentMaxColumns), i);
//log.info("Curr: {} {}/{} {}/{} {}", item, i, rowSpan, currentMaxColumns, colSpan, colCounts);
}
//log.info("Intern: {} {}/{} {}/{} {}", item, currentRow, rowSpan, currentCol, colSpan, colCounts);
int currentRowMaxColums = ((Integer) colCounts.objectAtIndex(row)).intValue();
total += rowSpan * colSpan;
col += colSpan;
if(col >= currentRowMaxColums) {
row++;
col = 0;
//log.info("Bumping row: {} {} {}", item, currentRow, colCounts);
}
index = index + 1;
}
if(total > maxColumns * colCounts.count()) {
colCounts.addObject(Integer.valueOf(total - maxColumns * colCounts.count()));
}
//log.info("Result: {}", colCounts);
_colCounts = colCounts;
}
}
return _colCounts;
}
public NSArray list() {
if (_list==null) {
_list = (NSArray)valueForBinding("list");
}
return _list;
}
public int rowCount() {
return colCounts().count();
}
public int colCount() {
return ((Number) colCounts().objectAtIndex(currentRow)).intValue();
}
public void setCurrentRow(int newValue) {
currentRow=newValue;
currentCol=-1;
}
public void pushItem() {
NSArray aList = list();
int index = currentItemIndex;
Object item = index < aList.count() ? aList.objectAtIndex(index) : null;
// log.debug("Index: {}: {} -> {}/{}", currentItemIndex, item, currentRow, currentCol);
setValueForBinding(item, "item");
setValueForBinding(ERXConstant.integerForInt(currentRow), "row");
setValueForBinding(ERXConstant.integerForInt(currentCol), "col");
setValueForBinding(ERXConstant.integerForInt(index), "index");
currentItemIndex++;
}
public void setCurrentCol(int newValue){
currentCol=newValue;
// log.debug("Index: {}", newValue);
if(colCount() != newValue) {
pushItem();
} else {
setValueForBinding(null, "item");
}
}
protected void _resetInternalCaches() {
_list=null;
currentCol=-1;
currentRow=-1;
currentItemIndex = 0;
_maxColumns = -1;
_colCounts = null;
}
@Override
public void takeValuesFromRequest(WORequest aRequest, WOContext aContext) {
_resetInternalCaches();
super.takeValuesFromRequest(aRequest, aContext);
}
@Override
public void reset() {
_resetInternalCaches();
setValueForBinding(null, "item");
}
}