/*
* JasperReports - Free Java Reporting Library.
* Copyright (C) 2001 - 2009 Jaspersoft Corporation. All rights reserved.
* http://www.jaspersoft.com
*
* Unless you have purchased a commercial license agreement from Jaspersoft,
* the following license terms apply:
*
* This program is part of JasperReports.
*
* JasperReports 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 3 of the License, or
* (at your option) any later version.
*
* JasperReports 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 JasperReports. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.jasperreports.crosstabs.fill.calculation;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.fill.AbstractValueProvider;
import net.sf.jasperreports.engine.fill.JRCalculable;
import net.sf.jasperreports.engine.fill.JRDistinctCountExtendedIncrementerFactory;
import net.sf.jasperreports.engine.fill.JRExtendedIncrementer;
import net.sf.jasperreports.engine.fill.JRExtendedIncrementerFactory;
import net.sf.jasperreports.engine.type.CalculationEnum;
/**
* Crosstab measure definition.
*
* @author Lucian Chirita (lucianc@users.sourceforge.net)
* @version $Id: MeasureDefinition.java 3529 2010-03-06 16:46:03Z teodord $
*/
public class MeasureDefinition
{
protected CalculationEnum calculation;
protected final JRExtendedIncrementerFactory incrementerFactory;
protected final Class valueClass;
protected final boolean isSystemDefined;
/**
* Create a measure definition.
*
* @param valueClass the value class
* @param calculation the calculation type
* @param incrementerFactory the incrementer factory
*/
public MeasureDefinition(
Class valueClass,
CalculationEnum calculation,
JRExtendedIncrementerFactory incrementerFactory)
{
this(valueClass, calculation, incrementerFactory, false);
}
protected MeasureDefinition(
Class valueClass,
CalculationEnum calculation,
JRExtendedIncrementerFactory incrementerFactory,
boolean isSystemDefined)
{
this.valueClass = valueClass;
this.calculation = calculation;
this.incrementerFactory = incrementerFactory;
this.isSystemDefined = isSystemDefined;
}
/**
* Creates a helper measure for a specific calculation.
*
* @param measure the measure
* @param helperCalculation the calculation
* @return the helper measure having the specified calculation
*/
public static MeasureDefinition createHelperMeasure(MeasureDefinition measure, CalculationEnum helperCalculation)
{
return new MeasureDefinition(measure.valueClass, helperCalculation, measure.incrementerFactory, true);
}
/**
* Creates a helper measure for a distinct count calculation.
*
* @param measure the measure
* @return the helper measure having the specified calculation
*/
public static MeasureDefinition createDistinctCountHelperMeasure(MeasureDefinition measure)
{
return new MeasureDefinition(measure.valueClass, CalculationEnum.NOTHING, JRDistinctCountExtendedIncrementerFactory.getInstance(), true);
}
/**
* Returns the calculation type.
*
* @return the calculation type
*/
public CalculationEnum getCalculation()
{
return calculation;
}
/**
* Returns the incrementer factory.
*
* @return the incrementer factory
*/
public JRExtendedIncrementerFactory getIncrementerFactory()
{
return incrementerFactory;
}
/**
* Returns the incrementer used for this measure.
*
* @return the incrementer used for this measure
*/
public JRExtendedIncrementer getIncrementer()
{
return incrementerFactory.getExtendedIncrementer(calculation.getValue());//FIXMEENUM should we create new method in interface?
}
protected boolean isSystemDefined()
{
return isSystemDefined;
}
/**
* Returns the measure value class.
*
* @return the measure value class
*/
public Class getValueClass()
{
return valueClass;
}
/**
* Measure value provider.
*/
protected static final AbstractValueProvider VALUE_PROVIDER = new AbstractValueProvider()
{
public Object getValue(JRCalculable calculable)
{
return calculable.getValue();
}
};
/**
* An accumulated value of a crosstab measure.
*
* @author Lucian Chirita (lucianc@users.sourceforge.net)
*/
public class MeasureValue implements JRCalculable
{
private Object value;
private MeasureValue[] helpers;
private boolean initialized;
private JRExtendedIncrementer incrementer;
/**
* Initializes the value.
*/
public MeasureValue()
{
this.value = null;
this.helpers = new MeasureValue[HELPER_SIZE];
incrementer = getIncrementer();
init();
}
protected void init()
{
this.value = incrementer.initialValue();
setInitialized(true);
}
/**
* Accumulates a value.
*
* @param addValue the value
* @throws JRException
*/
public void addValue(Object addValue) throws JRException
{
if (addValue != null || !incrementer.ignoresNullValues())
{
this.value = incrementer.increment(this, addValue, VALUE_PROVIDER);
setInitialized(false);
}
}
/**
* Accumulates another measure value.
* <p>
* This is used for total calculations, when two accumulated values are combined into a total.
*
* @param measureValue the measure value
* @throws JRException
*/
public void addValue(MeasureValue measureValue) throws JRException
{
if (!measureValue.isInitialized())
{
this.value = incrementer.combine(this, measureValue, VALUE_PROVIDER);
setInitialized(false);
}
}
public Object getValue()
{
return value;
}
public String toString()
{
return String.valueOf(getValue());
}
/**
* Sets a helper variable.
*
* @param helperVariable the helper variable
* @param type the helper type
* @return the previous helper variable for the type
*/
public MeasureValue setHelper(MeasureValue helperVariable, byte type)
{
MeasureValue old = helpers[type];
helpers[type] = helperVariable;
return old;
}
public boolean isInitialized()
{
return initialized;
}
public Object getIncrementedValue()
{
return value;
}
public JRCalculable getHelperVariable(byte helperType)
{
return helpers[helperType];
}
public void setInitialized(boolean isInitialized)
{
this.initialized = isInitialized;
}
}
}