py.una.pol.karaku.reports.DynamicUtils.java Source code

Java tutorial

Introduction

Here is the source code for py.una.pol.karaku.reports.DynamicUtils.java

Source

/*-
 * Copyright (c)
 *
 *       2012-2014, Facultad Politcnica, Universidad Nacional de Asuncin.
 *       2012-2014, Facultad de Ciencias Mdicas, Universidad Nacional de Asuncin.
 *       2012-2013, Centro Nacional de Computacin, Universidad Nacional de Asuncin.
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301  USA
 */

package py.una.pol.karaku.reports;

import java.awt.Color;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import py.una.pol.karaku.dao.entity.annotations.Time;
import py.una.pol.karaku.exception.ReportException;
import py.una.pol.karaku.math.Quantity;
import py.una.pol.karaku.reports.KarakuReportBlockSign.Sign;
import py.una.pol.karaku.reports.KarakuReportDetails.Detail;
import py.una.pol.karaku.util.FormatProvider;
import py.una.pol.karaku.util.I18nHelper;
import ar.com.fdvs.dj.core.DJConstants;
import ar.com.fdvs.dj.core.layout.ClassicLayoutManager;
import ar.com.fdvs.dj.domain.CustomExpression;
import ar.com.fdvs.dj.domain.DJCrosstab;
import ar.com.fdvs.dj.domain.DynamicReport;
import ar.com.fdvs.dj.domain.Style;
import ar.com.fdvs.dj.domain.builders.ColumnBuilder;
import ar.com.fdvs.dj.domain.builders.FastReportBuilder;
import ar.com.fdvs.dj.domain.builders.SubReportBuilder;
import ar.com.fdvs.dj.domain.constants.Border;
import ar.com.fdvs.dj.domain.constants.Font;
import ar.com.fdvs.dj.domain.constants.HorizontalAlign;
import ar.com.fdvs.dj.domain.constants.VerticalAlign;
import ar.com.fdvs.dj.domain.entities.Subreport;
import ar.com.fdvs.dj.domain.entities.columns.AbstractColumn;

/**
 * Clase que provee las funcionalidades basicas para generar reportes dinamicos.
 * 
 * @author Nathalia Ochoa
 * @since 1.0
 * @version 1.5 19/03/2013
 */
@Component
public final class DynamicUtils {

    private static final String FONT_ARIAL = "Arial";
    private static final int BIG = 12;
    private static final int SMALL = 10;
    private static final int WIDTH_SEPARATOR = 10;
    private static final int WIDTH_DATE = 10;
    /**
     * Ubicacion del template base dentro de la aplicacion.
     */
    private static final String FILE_PORTRAIT_CRITERIA_LOCATION = "report/base/PortraitWithCriteria.jrxml";
    private static final String FILE_PORTRAIT_LOCATION = "report/base/Portrait.jrxml";
    private static final String FILE_LOCATION = "report/";
    private static final String FILE_LANDSCAPE_CRITERIA_LOCATION = "report/base/LandscapeWithCriteria.jrxml";
    private static final String FILE_LANDSCAPE_LOCATION = "report/base/Landscape.jrxml";
    private static final String NOT_DATA = "BASE_REPORT_NOT_DATA";

    @Autowired
    private FormatProvider fp;

    /**
     * Crea una estructura de reporte configurada con las caractersticas
     * generales sin template alguno.
     * 
     * @return Reporte con las configuraciones generales
     */
    public FastReportBuilder newInstance() {

        FastReportBuilder structReport = new FastReportBuilder();
        this.setWhenNotData(structReport);
        structReport.setUseFullPageWidth(true);

        return structReport;
    }

    /**
     * Crea una estructura de reporte vertical configurada con las
     * caractersticas generales.
     * 
     * <p>
     * Este reporte tendra la seccin de criterios
     * </p>
     * 
     * @return Reporte con las configuraciones generales
     */
    public FastReportBuilder newInstancePortrait() {

        return this.newInstancePortrait(true);
    }

    /**
     * Crea una estructura de reporte vertical configurada con las
     * caractersticas generales.
     * 
     * @param criteria
     *            <li><b><code>true</code></b> S se desea que el reporte tenga
     *            la seccin de criterios. <li><b><code>false</code></b> Caso
     *            contrario.
     * 
     * 
     * @return Reporte con las configuraciones generales
     */
    public FastReportBuilder newInstancePortrait(boolean criteria) {

        FastReportBuilder structReport = this.newInstance();
        this.setTemplatePortrait(structReport, criteria);
        return structReport;
    }

    /**
     * Crea una estructura de reporte horizontal configurada con las
     * caractersticas generales.
     * 
     * @param criteria
     *            <li><b><code>true</code></b> S se desea que el reporte tenga
     *            la seccin de criterios. <li><b><code>false</code></b> Caso
     *            contrario.
     * @return Reporte con las configuraciones generales
     */
    public FastReportBuilder newInstanceLandScape(boolean criteria) {

        FastReportBuilder structReport = this.newInstance();
        this.setTemplateLandScape(structReport, criteria);
        return structReport;

    }

    public FastReportBuilder newInstanceWithCustomTemplate(String path) {

        FastReportBuilder structReport = this.newInstance();
        this.setTemplate(path, structReport);
        return structReport;
    }

    /**
     * Metodo que crea un reporte dinamico(en memoria), utilizando el template
     * base (con la seccin de criterios)para la configuracion general. Se
     * utiliza para los reportes simples.
     * 
     * @param columns
     *            Lista de columnas -> [header, field], que deben ser generadas
     *            de forma dinamica.
     * @param clazz
     *            Clase de la entidad sobre la cual se desea realizar el reporte
     * @return Reporte dinamico estructurado listo para ser generado
     * @throws ReportException
     */
    public <T> DynamicReport buildReportSimple(List<Column> columns, Class<T> clazz) throws ReportException {

        FastReportBuilder structReport = this.newInstancePortrait(true);
        this.buildColumnHeader(structReport, columns, clazz);

        return structReport.build();
    }

    /**
     * Mtodo que crea un reporte dinmico(en memoria), utilizando el template
     * base (con la seccin de criterios) para la configuracion general. Se
     * utiliza para los reportes simples, cuya grilla no define los atributos
     * fisicos de la entidad, sino son atributos transformados.
     * 
     * @param columns
     *            Lista de columnas -> [header, field] que deben ser generadas
     *            de forma dinamica.
     * @return Reporte dinamico estructurado listo para ser generado
     * @throws ReportException
     */
    public <T> DynamicReport buildReportSimple(List<Column> columns) throws ReportException {

        FastReportBuilder structReport = this.newInstancePortrait(true);
        this.buildColumnHeader(structReport, columns);

        return structReport.build();
    }

    /**
     * Construye un reporte dinamico, el cual posee una lista de bloques, donde
     * cada bloque es una lista de fields o una grilla de elementos.
     * 
     * @param blocks
     *            bloques del reporte.
     * @return reporte dinamico con bloques del tipo fields
     * @throws ReportException
     */

    public <T> DynamicReport buildReportBlock(Align align, boolean criteria, List<KarakuReportBlock> blocks)
            throws ReportException {

        FastReportBuilder structReport = getInstanceByAlign(align, criteria);
        structReport.setAllowDetailSplit(false);

        this.addBlocks(structReport, blocks);

        return structReport.build();
    }

    public <T> DynamicReport buildReportBlock(boolean criteria, List<KarakuReportBlock> blocks)
            throws ReportException {

        FastReportBuilder structReport = this.newInstancePortrait(criteria);
        structReport.setAllowDetailSplit(false);

        this.addBlocks(structReport, blocks);

        return structReport.build();
    }

    public <T> DynamicReport buildReportBlock(boolean criteria, List<KarakuReportBlock> blocks, String templateFile)
            throws ReportException {

        FastReportBuilder structReport = this.newInstanceWithCustomTemplate(templateFile);

        this.addBlocks(structReport, blocks);

        return structReport.build();

    }

    public <T> DynamicReport buidReportBlockGrid(List<KarakuReportBlockGrid> blocks) throws ReportException {

        FastReportBuilder structReport = this.newInstancePortrait(true);

        this.addBlocksGrid(structReport, blocks);

        return structReport.build();
    }

    /**
     * 
     * Construye un reporte dinamico (maestro) formado por bloques del tipo
     * field y del tipo firma, es decir un reporte que posee una lista de
     * columnas horizontales y al final del reporte posee una serie de firmas
     * (se aplica a los reportes que necesitan ser firmados).
     * 
     * @param criteria
     *            <li><b><code>true</code></b> S se desea que el reporte tenga
     *            la seccin de criterios. <li><b><code>false</code></b> Caso
     *            contrario.
     * 
     * @param blocks
     *            bloques del reporte que son solo del tipo field, es decir que
     *            posee columnas horizontales(label,value)
     * @param signs
     *            bloques del reporte que son solo del tipo firma, es decir que
     *            posee uaa lista de firmas que deben ser agregadas al final del
     *            reporte
     * @return
     * @throws ReportException
     */
    public <T> DynamicReport buidReportFields(boolean criteria, List<KarakuReportBlock> blocks,
            List<KarakuReportBlockSign> signs) throws ReportException {

        FastReportBuilder structReport = this.newInstancePortrait(criteria);

        this.addBlocks(structReport, blocks);
        this.addBlocksSign(structReport, signs);

        return structReport.build();
    }

    /**
     * Metodo que crea un reporte dinamico, utilizando un template base para la
     * configuracion general, los atributos de la cabecera tambien son generados
     * dinamicamente. Se utiliza para los reportes del tipo cabecera-detalle.
     * 
     * @param report
     *            Estructura que contiene la definicion y datos necesarios para
     *            generar el reporte.
     * @param align
     *            Alineacion con la cual se desea visualizar el reporte
     * @param criteria
     *            <li><b><code>true</code></b> S se desea que el reporte tenga
     *            la seccin de criterios. <li><b><code>false</code></b> Caso
     *            contrario.
     * @param clazz
     *            Clase de la entidad sobre la cual se desea realizar el reporte
     * @return Reporte dinamico estructurado listo para ser generado
     * @throws ReportException
     */
    public <T> DynamicReport buildReportDetail(KarakuReportDetails report, Align align, boolean criteria,
            Class<T> clazz) throws ReportException {

        FastReportBuilder structReportHead = this.newInstance();

        this.setAlignReport(structReportHead, align, criteria);

        this.buildColumnHeader(structReportHead, report.getColumns(), clazz);

        if (!(report.getDetails() == null)) {
            this.addDetails(structReportHead, report, clazz);
        }

        return structReportHead.build();

    }

    /**
     * Metodo que crea un reporte dinamico, utilizando un template especifico
     * para la configuracion referente a los atributos de la cabecera. Se
     * utiliza para los reportes del tipo cabecera-detalle.
     * 
     * @param path
     *            Ubicacion del template que se desea adicionar al reporte. Debe
     *            ser el nombre de la dependencia,luego el nombre del
     *            directorio, seguido del nombre del jrxml.<br>
     *            <b>Por ejemplo</b><br>
     *            <ol>
     *            <li><b>identificacion/persona/detallesPersona.jrxml</b>
     *            </ol>
     * @param report
     *            Estructura que contiene la definicion y datos necesarios para
     *            generar el reporte.
     * @param clazz
     *            Clase de la entidad sobre la cual se desea realizar el reporte
     * @return
     * @throws ReportException
     */
    public <T> DynamicReport buildReportDetail(String path, KarakuReportDetails report, Class<T> clazz)
            throws ReportException {

        FastReportBuilder structReportHead = this.newInstance();
        this.setTemplate(path, structReportHead);

        this.addDetails(structReportHead, report, clazz);

        return structReportHead.build();

    }

    /**
     * Agrega una lista de detalles al reporte cabecera.
     * 
     * @param structReportHead
     *            Structura del reporte principal
     * @param report
     *            Estructura que contiene la definicion y datos necesarios para
     *            generar el reporte.
     * @param clazz
     *            Clase de la entidad principal sobre la cual se desea realizar
     *            el reporte
     * @return
     * @throws ReportException
     */
    public <T> FastReportBuilder addDetails(FastReportBuilder structReportHead, KarakuReportDetails report,
            Class<T> clazz) throws ReportException {

        Style titleStyle = new Style();
        titleStyle.setHorizontalAlign(HorizontalAlign.LEFT);
        for (Detail detail : report.getDetails()) {
            structReportHead.addField(detail.getField(), Collection.class.getName());

            FastReportBuilder structSubreport = this.newInstance();
            structSubreport.setTitle(detail.getTitle());
            structSubreport.setTitleStyle(titleStyle);

            Class<?> clazzDetail = this.getClazzDetail(clazz, detail);

            this.buildColumnDetail(structSubreport, detail.getColumns(), clazzDetail);

            DynamicReport subreport = structSubreport.build();

            structReportHead.addConcatenatedReport(subreport, new ClassicLayoutManager(), detail.getField(),
                    DJConstants.SUBREPORT_PARAM_ORIGIN_FIELD, DJConstants.DATA_SOURCE_TYPE_COLLECTION);
        }
        return structReportHead;
    }

    /**
     * Agrega un subreporte al reporte maestro, donde el dataSource del
     * subReporte se encuentra en la lista de parametros.
     * 
     * @param structReportHead
     *            Reporte maestro o principal.
     * @param subReport
     *            Subreporte que se desea agregar
     * @param field
     *            Nombre del parametro donde se encuentra el dataSource del
     *            subreporte
     * @return Reporte maestro con el subreporte concatenado
     * @throws ReportException
     */
    public FastReportBuilder addDetailByParameter(FastReportBuilder structReportHead, FastReportBuilder subReport,
            String field) throws ReportException {

        subReport.setDefaultStyles(this.getStyleTitle(), null, this.getStyleColumnHeader(),
                this.getStyleColumnDetail());

        Subreport subAux = new SubReportBuilder().setDataSource(DJConstants.DATA_SOURCE_ORIGIN_PARAMETER,
                DJConstants.DATA_SOURCE_TYPE_JRDATASOURCE, field)
                .setDynamicReport(subReport.build(), new ClassicLayoutManager()).build();

        structReportHead.addConcatenatedReport(subAux);

        return structReportHead;
    }

    /**
     * Agrega un subreporte al reporte maestro, donde el dataSource del
     * subReporte se encuentra en un field del tipo <b>List</b> del dataSource
     * principal, por ejemplo: <li><b>documentos</b> Lista de documentos de una
     * persona</li>
     * 
     * @param structReportHead
     *            Reporte maestro o principal.
     * @param subReport
     *            Subreporte que se desea agregar
     * @param field
     *            Nombre del parametro donde se encuentra el dataSource del
     *            subreporte
     * @return Reporte maestro con el subreporte concatenado
     * @throws ReportException
     */
    public FastReportBuilder addDetailByField(FastReportBuilder structReportHead, FastReportBuilder subReport,
            String field) throws ReportException {

        structReportHead.addField(field, Collection.class.getName());
        subReport.setDefaultStyles(this.getStyleTitle(), null, this.getStyleColumnHeader(),
                this.getStyleColumnDetail());

        structReportHead.addConcatenatedReport(subReport.build(), new ClassicLayoutManager(), field,
                DJConstants.SUBREPORT_PARAM_ORIGIN_FIELD, DJConstants.DATA_SOURCE_TYPE_COLLECTION);

        return structReportHead;
    }

    /**
     * Genera un reporte utilizando crosstab.
     * 
     * @param crosstab
     *            Crosstab estructurado a ser agregado al reporte.
     * @return
     */
    public DynamicReport builReportCrossTab(DJCrosstab crosstab) throws ClassNotFoundException {

        FastReportBuilder structReport = this.newInstanceLandScape(true);

        structReport.addHeaderCrosstab(crosstab).setUseFullPageWidth(true);

        return structReport.build();

    }

    /**
     * Metodo que genera las columnas principales de un reporte de forma
     * dinamica,ademas configura los estilos correspondientes.
     * 
     * @param structReport
     *            Estructura del reporte
     * @param columns
     *            Lista de columnas que deben ser generadas
     * @param clazz
     *            Clase de la entidad sobre la cual se desea realizar el reporte
     * @return Reporte con las correspondientes columnas generadas y estilos
     *         aplicados.
     * @throws ReportException
     */
    public <T> FastReportBuilder buildColumnHeader(FastReportBuilder structReport, List<Column> columns,
            Class<T> clazz) throws ReportException {

        if (Object.class.equals(clazz)) {
            addColumn(structReport, columns);
        } else {
            addColumn(structReport, columns, clazz);
        }

        structReport.setDefaultStyles(null, null, this.getStyleColumnHeader(), this.getStyleColumnDetail());
        return structReport;
    }

    /**
     * Metodo que genera las columnas principales de un reporte de forma
     * dinamica,ademas configura los estilos correspondientes.
     * 
     * @param structReport
     *            Estructura del reporte
     * @param columns
     *            Lista de columnas que deben ser generadas
     * @return Reporte con las correspondientes columnas generadas y estilos
     *         aplicados.
     * @throws ReportException
     */
    public <T> FastReportBuilder buildColumnHeader(FastReportBuilder structReport, List<Column> columns)
            throws ReportException {

        this.addColumn(structReport, columns);

        structReport.setDefaultStyles(null, null, this.getStyleColumnHeader(), this.getStyleColumnDetail());
        return structReport;
    }

    /**
     * Metodo que genera las columnas secundarias correspondientes a los
     * subreportes de forma dinamica, ademas configura los estilos
     * correspondientes.
     * 
     * @param structReport
     *            Estructura del reporte
     * @param columns
     *            Lista de columnas que deben ser generadas
     * @param clazz
     *            Clase de la entidad sobre la cual se desea realizar el reporte
     * @return Reporte con las correspondientes columnas generadas y estilos
     *         aplicados
     * @throws ReportException
     */
    private FastReportBuilder buildColumnDetail(FastReportBuilder structReport, List<Column> columns,
            Class<?> clazz) throws ReportException {

        if (Object.class.equals(clazz)) {
            addColumn(structReport, columns);
        } else {
            addColumn(structReport, columns, clazz);
        }

        structReport.setDefaultStyles(this.getStyleTitle(), null, this.getStyleColumnHeaderDetails(),
                this.getStyleColumnDetail());

        return structReport;
    }

    /**
     * Metodo que obtiene el tipo de dato de cada columna que debe ser generada
     * de forma dinamica y finalmente agrega las columnas correctamente
     * definidas al reporte.
     * 
     * @param structReport
     *            Estructura del reporte
     * @param columns
     *            Lista de columnas que deben ser generadas
     * @param clazz
     *            Clase de la entidad sobre la cual se desea realizar el reporte
     * @return Reporte con las correspondientes columnas generadas
     * @throws ReportException
     */

    public <T> FastReportBuilder addColumn(FastReportBuilder structReport, List<Column> columns, Class<T> clazz)
            throws ReportException {

        for (Column column : columns) {
            try {
                if (column.getField().contains(".")) {
                    structReport.addColumn(column.getTitle(), column.getField(), Object.class.getName(),
                            column.getWidth(), getStyleColumn(column));
                } else {
                    Field field = ReflectionUtils.findField(clazz, column.getNameField());

                    structReport.addColumn(column.getTitle(), column.getField(), field.getType().getName(),
                            getWidthColumn(column, field), this.getStyleColumn(column, field));
                }

            } catch (ClassNotFoundException e) {
                throw new ReportException(e);
            } catch (SecurityException e) {
                throw new ReportException(e);
            }
        }
        return structReport;
    }

    /**
     * Configura la alineacin de las columnas de los reportes.
     * 
     * @param field
     *            Field que se desea alinear
     * 
     * @return
     */
    private HorizontalAlign getAlignColumn(Field field) {

        if (Number.class.isAssignableFrom(field.getType())) {
            return HorizontalAlign.RIGHT;
        } else {
            if (Date.class.isAssignableFrom(field.getType())) {
                return HorizontalAlign.CENTER;
            }
        }
        return HorizontalAlign.LEFT;
    }

    /**
     * Verifica si la columna es del tipo {@link Date} y coloca un ancho fijo a
     * la misma.
     * 
     * @param column
     * @param field
     * @return
     */
    protected int getWidthColumn(Column column, Field field) {

        if (Date.class.isAssignableFrom(field.getType())) {
            return WIDTH_DATE;
        } else {
            return column.getWidth();
        }
    }

    /**
     * Obtiene el estilo para una columna en particular, si posee un patron se
     * establece dicho patron de lo contrario solo la alineacin.
     * 
     * @param column
     * @return
     */
    private Style getStyleColumn(Column column) {

        if (column.getPattern() == null) {
            return this.getStyleColumn(column.getAlign());

        } else {
            return this.getStyleColumn(column.getAlign(), column.getPattern());
        }
    }

    private Style getStyleColumn(HorizontalAlign align) {

        Style style = this.getStyleColumnDetail();
        style.setHorizontalAlign(align);
        return style;
    }

    /**
     * Construye el estilo de la columna del reporte
     * 
     * @param column
     *            Columna del reporte
     * @param field
     *            Field asociado a la columna
     * @return
     */
    private Style getStyleColumn(Column column, Field field) {

        Style style = this.getStyleColumnDetail();
        if (column.getPattern() == null) {
            style.setPattern(getPattern(field));
        } else {
            style.setPattern(column.getPattern());
        }
        if (column.getAlign() == null) {
            style.setHorizontalAlign(getAlignColumn(field));
        } else {
            style.setHorizontalAlign(column.getAlign());
        }
        return style;
    }

    /**
     * Verifica el pattern que se debe aplicar a la columna
     * 
     * <li>Si es del tipo {@link Date} se verifica el tipo que se encuentra
     * asociada a la anotacion {@link Time} para establecer el pattern a
     * utilizar.
     * 
     * @param field
     */
    protected String getPattern(Field field) {

        if (Date.class.isAssignableFrom(field.getType())) {
            if (field.isAnnotationPresent(Time.class)) {
                switch (field.getAnnotation(Time.class).type()) {
                case DATE:
                    return fp.getDateFormat();
                case DATETIME:
                    return fp.getDateTimeFormat();
                case TIME:
                    return fp.getTimeFormat();
                default:
                    break;
                }
            } else {
                return fp.getDateFormat();
            }
        }
        return null;
    }

    private Style getStyleColumn(HorizontalAlign align, String pattern) {

        Style style = this.getStyleColumnDetail();
        style.setHorizontalAlign(align);
        style.setPattern(pattern);
        return style;
    }

    /**
     * Metodo que agrega las columnas al reporte, el tipo de las columnas
     * generadas es del tipo Object, se utiliza para el caso que el objeto
     * utilizado dentro del reporte no sea un objeto fisico existente, sino uno
     * creado en memoria.
     * 
     * @param structReport
     *            Estructura del reporte
     * @param columns
     *            Lista de columnas que deben ser generadas
     * @return Reporte con las correspondiente columnas generadas
     * @throws ReportException
     */
    public FastReportBuilder addColumn(FastReportBuilder structReport, List<Column> columns)
            throws ReportException {

        try {
            for (Column column : columns) {

                structReport.addColumn(column.getTitle(), column.getField(), Object.class.getName(),
                        column.getWidth(), getStyleColumn(column));
            }
            return structReport;
        } catch (ClassNotFoundException e) {
            throw new ReportException(e);
        }
    }

    /**
     * Agrega la lista de bloques del tipo field(label,value)al reporte maestro
     * 
     * @param structReport
     *            estructura del reporte dinamico
     * @param blocks
     *            bloques que son solo del tipo field, es decir que posee
     *            columnas horizontales(label,value)
     * @return reporte dinamico formado con los bloques recibidos como parametro
     * @throws ReportException
     */
    public <T> FastReportBuilder addBlocks(FastReportBuilder structReport, List<KarakuReportBlock> blocks)
            throws ReportException {

        for (KarakuReportBlock block : blocks) {
            // Si es un bloque de fields
            if (block instanceof KarakuReportBlockField) {
                this.buildBlock(structReport, (KarakuReportBlockField) block);
            } else {
                // Si es un bloque de firmas
                if (block instanceof KarakuReportBlockSign) {
                    this.buildBlockSign(structReport, (KarakuReportBlockSign) block);
                } else {
                    // Si es un bloque de grillas
                    this.buildBlockGrid(structReport, (KarakuReportBlockGrid) block);
                }
            }
        }

        return structReport;
    }

    public <T> FastReportBuilder addBlocksGrid(FastReportBuilder structReport, List<KarakuReportBlockGrid> blocks)
            throws ReportException {

        for (KarakuReportBlockGrid block : blocks) {
            this.buildBlockGrid(structReport, block);
        }

        return structReport;
    }

    /**
     * Agrega la lista de bloques del tipo firma al reporte maestro
     * 
     * @param structReport
     *            estructura del reporte dinamico
     * @param blocks
     *            bloques que son solo del tipo firma, es decir que posee uaa
     *            lista de firmas que deben ser agregadas al final del reporte
     * @return reporte dinamico formado con los bloques recibidos como parametro
     * @throws ReportException
     */
    public <T> FastReportBuilder addBlocksSign(FastReportBuilder structReport, List<KarakuReportBlockSign> blocks)
            throws ReportException {

        for (KarakuReportBlockSign block : blocks) {
            this.buildBlockSign(structReport, block);
        }

        return structReport;
    }

    /**
     * Construye un bloque del tipo field dinamico y lo agrega al reporte.
     * 
     * @param structReportHead
     *            estructura del reporte maestro(principal)
     * @param block
     *            bloque del tipo field, es decir que posee columnas
     *            horizontales(label,value)
     * @return reporte con el bloque construido
     * @throws ReportException
     */
    public FastReportBuilder buildBlock(FastReportBuilder structReportHead, KarakuReportBlockField block)
            throws ReportException {

        FastReportBuilder structBlockReport = new FastReportBuilder();

        Style styleTitle = null;
        Style styleDetail = null;

        if (block.isSubBlock()) {
            styleTitle = getStyleTitleSecundary();
            styleDetail = getStyleDetailSecundary();
        } else {
            styleTitle = getStyleTitleTransparentUnderline();
        }
        if (block.isTitle()) {
            styleTitle = getStyleOnlyTitle();
        }

        structBlockReport.setDefaultStyles(styleTitle, this.getStyleTitle(), this.getStyleColumnHeaderBlank(),
                styleDetail);

        structBlockReport.setUseFullPageWidth(true);

        this.setWhenNotData(structBlockReport);

        try {
            /* Bloques sin titulo */
            structBlockReport.setTitle(block.getTitle());
            structBlockReport.setTopMargin(0);
            structBlockReport.setBottomMargin(0);
            structBlockReport.setHeaderHeight(0);
            structBlockReport.addColumn("", "label", String.class, block.getWidthLabel());
            structBlockReport.addColumn("", "value", String.class, block.getWidthValue());

            Subreport subReport = new SubReportBuilder()
                    .setDataSource(DJConstants.DATA_SOURCE_ORIGIN_PARAMETER,
                            DJConstants.DATA_SOURCE_TYPE_JRDATASOURCE, block.getNameDataSource())
                    .setDynamicReport(structBlockReport.build(), new ClassicLayoutManager()).build();

            structReportHead.addConcatenatedReport(subReport);

            return structReportHead;

        } catch (ClassNotFoundException e) {
            throw new ReportException(e);
        }

    }

    public FastReportBuilder buildBlockGrid(FastReportBuilder structReportHead, KarakuReportBlockGrid block)
            throws ReportException {

        FastReportBuilder structBlockReport = this.newInstance();
        structBlockReport.setDefaultStyles(this.getStyleTitle(), null, this.getStyleColumnHeader(),
                getStyleColumnDetail());

        structBlockReport.setTitle(block.getTitle());
        structBlockReport.setTopMargin(0);
        structBlockReport.setBottomMargin(0);

        this.addColumn(structBlockReport, block.getColumns());

        Subreport subReport = new SubReportBuilder()
                .setDataSource(DJConstants.DATA_SOURCE_ORIGIN_PARAMETER, DJConstants.DATA_SOURCE_TYPE_JRDATASOURCE,
                        block.getNameDataSource())
                .setDynamicReport(structBlockReport.build(), new ClassicLayoutManager()).build();

        structReportHead.addConcatenatedReport(subReport);

        return structReportHead;

    }

    /**
     * Construye un bloque del tipo firma dinamico y lo agrega al reporte.
     * 
     * @param structReportHead
     *            estructura del reporte maestro(principal)
     * @param block
     *            bloque del tipo firma, es decir que posee una lista de firmas
     *            que deben ser agregadas al final del reporte
     * @return reporte con el bloque construido
     * @throws ReportException
     */
    public FastReportBuilder buildBlockSign(FastReportBuilder structReportHead, KarakuReportBlockSign block)
            throws ReportException {

        FastReportBuilder structBlockReport = new FastReportBuilder();
        structBlockReport.setDefaultStyles(this.getStyleTitle(), this.getStyleTitle(),
                this.getStyleColumnHeaderTransparentUnderlineTop(), null);

        structBlockReport.setUseFullPageWidth(true);
        structBlockReport.setTopMargin(50);
        this.setWhenNotDataEmpty(structBlockReport);

        try {

            for (Sign sign : block.getSigns()) {

                structBlockReport.addColumn(sign.getValue(), "label", String.class, sign.getWidth());
                if (!sign.equals(block.getSigns().get(block.getSigns().size() - 1))) {
                    structBlockReport.addColumn(this.buildColumnSeparator());
                }

            }

            Subreport subReport = new SubReportBuilder().setDataSource("")
                    .setDynamicReport(structBlockReport.build(), new ClassicLayoutManager()).build();
            structReportHead.addConcatenatedReport(subReport);

            return structReportHead;

        } catch (ClassNotFoundException e) {
            throw new ReportException(e);
        }

    }

    private AbstractColumn buildColumnSeparator() {

        return ColumnBuilder.getNew().setStyle(this.getStyleColumnHeader()).setColumnProperty("label", String.class)
                .setWidth(WIDTH_SEPARATOR).build();
    }

    /**
     * Metodo que obtiene la clase de cada detalle que sera incorporado en los
     * reportes del tipo cabecera-detalle.
     * 
     * @param clazz
     *            Clase de la cabecera
     * @param detail
     *            Detalle que se desea agregar al reporte
     * @return Clase del detalle
     * @throws ReportException
     */
    private Class<?> getClazzDetail(Class<?> clazz, Detail detail) throws ReportException {

        Class<?> clazzDetail = null;
        try {
            if (detail.getField().contains(".")) {
                clazzDetail = Object.class;
            } else {
                Field field = clazz.getDeclaredField(detail.getField());
                clazzDetail = (Class<?>) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0];
            }
        } catch (NoSuchFieldException e) {
            throw new ReportException(e);
        }
        return clazzDetail;
    }

    /**
     * Metodo que define el estilo que debe ser aplicado al titulo principal de
     * los reportes.
     * 
     * @return StyleTitle
     */
    public Style getStyleTitle() {

        Style styleTitle = new Style();
        styleTitle.setFont(Font.ARIAL_MEDIUM_BOLD);

        return styleTitle;
    }

    /**
     * Metodo que define el estilo que debe ser aplicado al titulo principal de
     * los reportes.
     * 
     * @return StyleTitle
     */
    public Style getStyleOnlyTitle() {

        Style styleTitle = new Style();
        styleTitle.setFont(Font.ARIAL_BIG_BOLD);
        styleTitle.setHorizontalAlign(HorizontalAlign.CENTER);
        styleTitle.setVerticalAlign(VerticalAlign.MIDDLE);
        styleTitle.setBorderBottom(Border.THIN());
        styleTitle.setBorderLeft(Border.THIN());
        styleTitle.setBorderRight(Border.THIN());
        styleTitle.setBorderTop(Border.THIN());
        styleTitle.setTransparent(false);
        return styleTitle;
    }

    /**
     * Metodo que define el estilo para las columnas principales de los
     * reportes.
     * 
     * @return StyleColumnHeader
     */

    public Style getStyleColumnHeader() {

        Style styleColumns = new Style();
        styleColumns.setTransparent(false);
        styleColumns.setBorder(Border.THIN());
        styleColumns.setBackgroundColor(Color.white);
        styleColumns.setFont(Font.ARIAL_SMALL_BOLD);
        styleColumns.setTextColor(Color.black);
        styleColumns.setHorizontalAlign(HorizontalAlign.CENTER);
        styleColumns.setVerticalAlign(VerticalAlign.MIDDLE);
        return styleColumns;
    }

    public Style getStyleColumnDetail() {

        Style styleColumns = new Style();
        styleColumns.setBorder(Border.THIN());
        return styleColumns;
    }

    /**
     * @return
     */
    private Style getStyleColumnHeaderBlank() {

        Style styleColumns = new Style();
        styleColumns.setTransparent(true);
        return styleColumns;
    }

    /**
     * Estilo utilizado para el titulo de los bloques principales
     * 
     * @return
     */
    public Style getStyleTitleTransparentUnderline() {

        Style style = new Style();
        style.setFont(new Font(BIG, FONT_ARIAL, false, false, false));
        style.setHorizontalAlign(HorizontalAlign.LEFT);
        style.setBorderBottom(Border.PEN_1_POINT());
        style.setTransparent(true);
        return style;
    }

    /**
     * Estilo utilizado para el titulo de los bloques secundarios
     * 
     * @return
     */
    public Style getStyleTitleSecundary() {

        Style style = new Style();
        style.setFont(new Font(SMALL, FONT_ARIAL, true, false, false));
        style.setHorizontalAlign(HorizontalAlign.LEFT);
        return style;
    }

    /**
     * Estilo utilizado para el contenido de los bloques secundarios
     * 
     * @return
     */
    public Style getStyleDetailSecundary() {

        Style style = new Style();
        style.setFont(new Font(SMALL, FONT_ARIAL, false, false, false));
        return style;
    }

    public Style getStyleColumnHeaderTransparentUnderlineTop() {

        Style styleColumns = new Style();
        styleColumns.setBorderTop(Border.PEN_1_POINT());
        styleColumns.setHorizontalAlign(HorizontalAlign.CENTER);
        styleColumns.setTransparent(true);
        return styleColumns;
    }

    /**
     * Metodo que define el estilo para las columnas secundarias de los
     * reportes.
     * 
     * @return StyleColumnHeader Estilo de las columnas de la grilla.
     */

    public Style getStyleColumnHeaderDetails() {

        Style styleColumns = new Style();
        styleColumns.setTransparent(false);
        styleColumns.setBackgroundColor(Color.gray);
        styleColumns.setFont(Font.ARIAL_SMALL_BOLD);
        styleColumns.setTextColor(Color.white);
        styleColumns.setHorizontalAlign(HorizontalAlign.CENTER);
        styleColumns.setVerticalAlign(VerticalAlign.MIDDLE);
        return styleColumns;
    }

    /**
     * Proporciona el estilo para el pivot utilizado al realizar el crosstab.
     * 
     * @return
     */

    public Style getStyleColumnPivot() {

        return new Style();
    }

    /**
     * Agrega al reporte un mensaje personalizado en el caso de que el reporte
     * no tenga datos que puedan ser visualizados.
     * 
     * @param structReport
     * @return
     */
    public FastReportBuilder setWhenNotData(FastReportBuilder structReport) {

        structReport.setWhenNoData(I18nHelper.getMessage(NOT_DATA), null);
        return structReport;
    }

    private FastReportBuilder setWhenNotDataEmpty(FastReportBuilder structReport) {

        structReport.setWhenNoData(" ", null);
        return structReport;
    }

    /**
     * Configura el template del reporte de acuerdo a la alineacin y seccin de
     * criterios.
     * 
     * @param report
     *            Reporte que se desea configurar.
     * @param align
     *            Alineacin del reporte: <li>Horizontal <li>Vertical
     * @param criteria
     *            <li><b><code>true</code></b> S se desea que el reporte tenga
     *            la seccin de criterios. <li><b><code>false</code></b> Caso
     *            contrario.
     * @return
     */
    public FastReportBuilder setAlignReport(FastReportBuilder report, Align align, boolean criteria) {

        if (align.equals(Align.HORIZONTAL)) {
            this.setTemplateLandScape(report, criteria);
        } else {
            this.setTemplatePortrait(report, criteria);

        }
        return report;

    }

    /**
     * Adiciona al reporte el template base con orientacin horizontal.
     * 
     * @param report
     * @return
     */
    public FastReportBuilder setTemplatePortrait(FastReportBuilder report, boolean criteria) {

        if (criteria) {
            report.setTemplateFile(FILE_PORTRAIT_CRITERIA_LOCATION, true, false, true, true);
        } else {
            report.setTemplateFile(FILE_PORTRAIT_LOCATION, true, false, true, true);
        }

        return report;
    }

    /**
     * Adiciona al reporte el template base con orientacin vertical.
     * 
     * @param report
     * @return
     */
    public FastReportBuilder setTemplateLandScape(FastReportBuilder report, boolean criteria) {

        if (criteria) {
            report.setTemplateFile(FILE_LANDSCAPE_CRITERIA_LOCATION, true, false, true, true);
        } else {
            report.setTemplateFile(FILE_LANDSCAPE_LOCATION, true, false, true, true);
        }
        return report;
    }

    /**
     * Adiciona al reporte un template especifico, definido por el usuario.
     * 
     * @param path
     *            Ubicacion del template que se desea adicionar al reporte. Debe
     *            ser el nombre del directorio, seguido del nombre del jrxml.
     * @param report
     * @return
     */
    private FastReportBuilder setTemplate(String path, FastReportBuilder report) {

        report.setTemplateFile(FILE_LOCATION + path, true, false, true, true);
        return report;
    }

    /**
     * Mtodo que genera una expresin para hacer la conversin del tipo de dato
     * {@link Quantity} a {@link Bigdecimal}
     * 
     * @param value
     *            Field del dataSource que se desea convertir.
     * @return
     */
    public CustomExpression getQuantityCustomExpression(final String value) {

        return new CustomExpression() {

            private static final long serialVersionUID = 2200118849765160960L;

            @SuppressWarnings("rawtypes")
            @Override
            public Object evaluate(Map fields, Map variables, Map parameters) {

                return ((Quantity) fields.get(value)).bigDecimalValue();
            }

            @Override
            public String getClassName() {

                return BigDecimal.class.getName();
            }
        };
    }

    public FastReportBuilder getInstanceByAlign(Align align, boolean criteria) {

        if (align.equals(align.HORIZONTAL)) {

            return newInstanceLandScape(criteria);
        } else {
            return newInstancePortrait(criteria);
        }
    }

}