/**
* =========================================
* LibFormula : a free Java formula library
* =========================================
*
* Project Info: http://reporting.pentaho.org/libformula/
*
* (C) Copyright 2006-2008, by Pentaho Corporation and Contributors.
*
* This library is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
*
* ------------
* DefaultDataTable.java
* ------------
*/
package org.pentaho.reporting.libraries.formula.lvalues;
import org.pentaho.reporting.libraries.formula.EvaluationException;
import org.pentaho.reporting.libraries.formula.FormulaContext;
import org.pentaho.reporting.libraries.formula.LibFormulaErrorValue;
import org.pentaho.reporting.libraries.formula.typing.Type;
import org.pentaho.reporting.libraries.formula.typing.ArrayCallback;
import org.pentaho.reporting.libraries.formula.typing.coretypes.AnyType;
import org.pentaho.reporting.libraries.base.util.ObjectTable;
/**
* Creation-Date: 05.11.2006, 13:34:01
*
* @author Thomas Morgner
* @author Cedric Pronzato
*/
public class DefaultDataTable extends ObjectTable implements DataTable
{
private static class DefaultArrayCallback implements ArrayCallback
{
private DefaultDataTable table;
private TypeValuePair[][] backend;
private DefaultArrayCallback(final DefaultDataTable table)
{
this.table = table;
backend = new TypeValuePair[table.getRowCount()][table.getColumnCount()];
}
public LValue getRaw(final int row, final int column)
{
return table.getValueAt(row, column);
}
public Object getValue(final int row, final int column) throws EvaluationException
{
final TypeValuePair value = get(row, column);
return value.getValue();
}
private TypeValuePair get(final int row, final int column)
throws EvaluationException
{
TypeValuePair value = backend[row][column];
if(value == null)
{
value = getRaw(row, column).evaluate();
backend[row][column] = value;
}
return value;
}
public Type getType(final int row, final int column) throws EvaluationException
{
return get(row, column).getType();
}
public int getColumnCount()
{
return table.getColumnCount();
}
public int getRowCount()
{
return table.getRowCount();
}
}
private transient Boolean constant;
private static final LValue[] EMPTY_LVALUES = new LValue[0];
private static final long serialVersionUID = 4942690291611203409L;
private ParsePosition parsePosition;
/**
* Creates a new table.
*/
public DefaultDataTable()
{
}
public DefaultDataTable(final LValue[][] array)
{
if(array != null && array.length > 0)
{
final int colCount = array[0].length;
setData(array, colCount);
}
}
public ParsePosition getParsePosition()
{
return parsePosition;
}
public void setParsePosition(final ParsePosition parsePosition)
{
this.parsePosition = parsePosition;
}
public String getColumnName(int column)
{
final StringBuffer result = new StringBuffer(10);
for (; column >= 0; column = column / 26 - 1)
{
final int colChar = (char) (column % 26) + 'A';
result.append(colChar);
}
return result.toString();
}
/**
* Sets the object for a cell in the table. The table is expanded if
* necessary.
*
* @param row the row index (zero-based).
* @param column the column index (zero-based).
* @param object the object.
*/
public void setObject(final int row, final int column, final LValue object)
{
super.setObject(row, column, object);
}
public LValue getValueAt(final int row, final int column)
{
return (LValue) getObject(row, column);
}
public void initialize(final FormulaContext context) throws EvaluationException
{
final int rows = getRowCount();
final int cols = getColumnCount();
for (int row = 0; row < rows; row++)
{
for (int col = 0; col < cols; col++)
{
final LValue value = getValueAt(row, col);
if(value != null)
{
value.initialize(context);
}
}
}
}
public TypeValuePair evaluate() throws EvaluationException
{
int colCount = -1;
final LValue[][] array = (LValue[][])getData();
for(int i=0; i<array.length; i++)
{
final LValue[] row = array[i];
if(colCount > 0 && row.length != colCount)
{
// error, different column count is not allowed
throw new EvaluationException(LibFormulaErrorValue.ERROR_ILLEGAL_ARRAY_VALUE);
}
else
{
colCount = row.length;
}
}
return new TypeValuePair(AnyType.ANY_ARRAY, new DefaultArrayCallback(this));
}
public Object clone() throws CloneNotSupportedException
{
final DefaultDataTable table = (DefaultDataTable) super.clone();
final Object[][] data = getData();
final Object[][] targetData = (Object[][]) data.clone();
for (int i = 0; i < targetData.length; i++)
{
final Object[] objects = targetData[i];
if (objects == null)
{
continue;
}
targetData[i] = (Object[]) objects.clone();
for (int j = 0; j < objects.length; j++)
{
final LValue object = (LValue) objects[j];
if (object == null)
{
continue;
}
objects[j] = object.clone();
}
}
table.setData(targetData, getColumnCount());
return table;
}
/**
* Querying the value type is only valid *after* the value has been
* evaluated.
*
* @return
*/
public Type getValueType()
{
return AnyType.ANY_ARRAY;
}
/**
* Returns any dependent lvalues (parameters and operands, mostly).
*
* @return
*/
public LValue[] getChildValues()
{
// too expensive ...
return EMPTY_LVALUES;
}
/**
* Checks whether the LValue is constant. Constant lvalues always return the
* same value.
*
* @return
*/
public boolean isConstant()
{
if (constant == null)
{
if (computeConstantValue())
{
constant = Boolean.TRUE;
}
else
{
constant = Boolean.FALSE;
}
}
return Boolean.TRUE.equals(constant);
}
private boolean computeConstantValue()
{
final int rows = getRowCount();
final int cols = getColumnCount();
for (int row = 0; row < rows; row++)
{
for (int col = 0; col < cols; col++)
{
final LValue value = getValueAt(row, col);
if (value.isConstant() == false)
{
return false;
}
}
}
return true;
}
}