org.pentaho.reporting.engine.classic.wizard.WizardProcessor.java Source code

Java tutorial

Introduction

Here is the source code for org.pentaho.reporting.engine.classic.wizard.WizardProcessor.java

Source

/*!
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program 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.
*
* Copyright (c) 2002-2017 Hitachi Vantara..  All rights reserved.
*/

package org.pentaho.reporting.engine.classic.wizard;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.reporting.engine.classic.core.AbstractReportDefinition;
import org.pentaho.reporting.engine.classic.core.AbstractReportPreProcessor;
import org.pentaho.reporting.engine.classic.core.AttributeNames;
import org.pentaho.reporting.engine.classic.core.Band;
import org.pentaho.reporting.engine.classic.core.CrosstabColumnGroup;
import org.pentaho.reporting.engine.classic.core.CrosstabColumnGroupBody;
import org.pentaho.reporting.engine.classic.core.CrosstabGroup;
import org.pentaho.reporting.engine.classic.core.CrosstabOtherGroup;
import org.pentaho.reporting.engine.classic.core.CrosstabOtherGroupBody;
import org.pentaho.reporting.engine.classic.core.CrosstabRowGroup;
import org.pentaho.reporting.engine.classic.core.CrosstabRowGroupBody;
import org.pentaho.reporting.engine.classic.core.Element;
import org.pentaho.reporting.engine.classic.core.Group;
import org.pentaho.reporting.engine.classic.core.GroupBody;
import org.pentaho.reporting.engine.classic.core.GroupFooter;
import org.pentaho.reporting.engine.classic.core.GroupHeader;
import org.pentaho.reporting.engine.classic.core.MasterReport;
import org.pentaho.reporting.engine.classic.core.MetaAttributeNames;
import org.pentaho.reporting.engine.classic.core.RelationalGroup;
import org.pentaho.reporting.engine.classic.core.ReportElement;
import org.pentaho.reporting.engine.classic.core.ReportProcessingException;
import org.pentaho.reporting.engine.classic.core.Section;
import org.pentaho.reporting.engine.classic.core.SubGroupBody;
import org.pentaho.reporting.engine.classic.core.SubReport;
import org.pentaho.reporting.engine.classic.core.Watermark;
import org.pentaho.reporting.engine.classic.core.filter.types.ContentType;
import org.pentaho.reporting.engine.classic.core.filter.types.LabelType;
import org.pentaho.reporting.engine.classic.core.filter.types.TextFieldType;
import org.pentaho.reporting.engine.classic.core.function.ProcessingContext;
import org.pentaho.reporting.engine.classic.core.function.StructureFunction;
import org.pentaho.reporting.engine.classic.core.metadata.ElementType;
import org.pentaho.reporting.engine.classic.core.states.datarow.DefaultFlowController;
import org.pentaho.reporting.engine.classic.core.style.BandStyleKeys;
import org.pentaho.reporting.engine.classic.core.style.BorderStyle;
import org.pentaho.reporting.engine.classic.core.style.ElementStyleKeys;
import org.pentaho.reporting.engine.classic.core.style.ElementStyleSheet;
import org.pentaho.reporting.engine.classic.core.style.TextStyleKeys;
import org.pentaho.reporting.engine.classic.core.wizard.AutoGeneratorUtility;
import org.pentaho.reporting.engine.classic.core.wizard.DataAttributes;
import org.pentaho.reporting.engine.classic.core.wizard.DefaultDataAttributeContext;
import org.pentaho.reporting.engine.classic.core.wizard.RelationalAutoGeneratorPreProcessor;
import org.pentaho.reporting.engine.classic.wizard.model.DetailFieldDefinition;
import org.pentaho.reporting.engine.classic.wizard.model.FieldDefinition;
import org.pentaho.reporting.engine.classic.wizard.model.GroupDefinition;
import org.pentaho.reporting.engine.classic.wizard.model.GroupType;
import org.pentaho.reporting.engine.classic.wizard.model.Length;
import org.pentaho.reporting.engine.classic.wizard.model.RootBandDefinition;
import org.pentaho.reporting.engine.classic.wizard.model.WatermarkDefinition;
import org.pentaho.reporting.engine.classic.wizard.model.WizardSpecification;
import org.pentaho.reporting.libraries.base.util.ObjectUtilities;
import org.pentaho.reporting.libraries.base.util.StringUtils;
import org.pentaho.reporting.libraries.resourceloader.ResourceManager;

import java.awt.*;
import java.util.ArrayList;

/**
 * @author Thomas Morgner
 * @noinspection UnnecessaryBoxing, UnnecessaryUnboxing, UnusedDeclaration
 */
public class WizardProcessor extends AbstractReportPreProcessor {
    private static final Log logger = LogFactory.getLog(WizardProcessor.class);

    protected DefaultDataAttributeContext attributeContext;
    protected AbstractReportDefinition definition;
    protected DefaultFlowController flowController;
    protected WizardSpecification wizardSpecification;

    public WizardProcessor() {
    }

    public MasterReport performPreProcessing(final MasterReport definition,
            final DefaultFlowController flowController) throws ReportProcessingException {
        return (MasterReport) performCommonPreProcessing(definition, flowController,
                definition.getResourceManager());
    }

    public SubReport performPreProcessing(final SubReport definition, final DefaultFlowController flowController)
            throws ReportProcessingException {
        return (SubReport) performCommonPreProcessing(definition, flowController, definition.getResourceManager());
    }

    protected AbstractReportDefinition performCommonPreProcessing(final AbstractReportDefinition definition,
            final DefaultFlowController flowController, final ResourceManager resourceManager)
            throws ReportProcessingException {
        try {
            this.wizardSpecification = WizardProcessorUtil.loadWizardSpecification(definition, resourceManager);
            if (wizardSpecification == null) {
                return definition;
            }

            final StructureFunction[] functions = definition.getStructureFunctions();
            boolean hasOverrideFunction = false;
            for (int i = 0; i < functions.length; i++) {
                final StructureFunction function = functions[i];
                if (function instanceof WizardOverrideFormattingFunction) {
                    hasOverrideFunction = true;
                    break;
                }
            }
            if (hasOverrideFunction == false) {
                definition.addStructureFunction(new WizardOverrideFormattingFunction());
            }

            final ProcessingContext reportContext = flowController.getReportContext();
            this.definition = definition;
            this.flowController = flowController;
            this.attributeContext = new DefaultDataAttributeContext(reportContext.getOutputProcessorMetaData(),
                    reportContext.getResourceBundleFactory().getLocale());

            final Object o = definition.getAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.ENABLE);
            if (Boolean.TRUE.equals(o) == false) {
                return performRefreshPreProcessing();
            } else {
                return performGenerationPreProcessing();
            }
        } finally {
            this.wizardSpecification = null;
            this.definition = null;
            this.flowController = null;
            this.attributeContext = null;
        }

    }

    private AbstractReportDefinition performRefreshPreProcessing() throws ReportProcessingException {
        final GroupDefinition[] groupDefinitions = wizardSpecification.getGroupDefinitions();
        final int wizardCount = groupDefinitions.length; // 1  5   5
        final int groupCount = definition.getGroupCount(); // 5  1   5
        final int count = Math.min(groupCount, wizardCount);
        for (int i = 0; i < count; i++) {
            final int groupIdx = groupCount - i - 1;
            final int wizGroupIdx = wizardCount - i - 1;
            final GroupDefinition gd = groupDefinitions[wizGroupIdx];
            final RelationalGroup g = definition.getRelationalGroup(groupIdx);
            if (g == null) {
                break;
            }

            final Band groupHeader = g.getHeader();
            final Band groupFooter = g.getFooter();

            iterateSection(groupHeader, new UpdateHeaderTask(gd));
            iterateSection(groupFooter, new UpdateFooterTask(gd));
        }

        final Band itemband = definition.getItemBand();
        final Band detailsHeader = definition.getDetailsHeader();
        final Band detailsFooter = definition.getDetailsFooter();

        final DetailFieldDefinition[] detailFieldDefinitions = wizardSpecification.getDetailFieldDefinitions();
        for (int i = 0; i < detailFieldDefinitions.length; i++) {
            final DetailFieldDefinition fieldDefinition = detailFieldDefinitions[i];
            final UpdateDetailsTask updateTask = new UpdateDetailsTask(fieldDefinition);
            iterateSection(itemband, updateTask);
            iterateSection(detailsHeader, updateTask);
            iterateSection(detailsFooter, updateTask);
        }

        return definition;
    }

    protected static interface UpdateTask {
        public void processElement(ReportElement e);
    }

    private static class UpdateHeaderTask implements UpdateTask {
        private GroupDefinition groupDefinition;

        private UpdateHeaderTask(final GroupDefinition groupDefinition) {
            this.groupDefinition = groupDefinition;
        }

        public void processElement(final ReportElement e) {
            if (Boolean.TRUE.equals(e.getAttribute(AttributeNames.Wizard.NAMESPACE,
                    AttributeNames.Wizard.ALLOW_METADATA_STYLING))) {
                e.setAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.CACHED_WIZARD_FORMAT_DATA,
                        groupDefinition.getHeader());
            }
            if (Boolean.TRUE.equals(e.getAttribute(AttributeNames.Wizard.NAMESPACE,
                    AttributeNames.Wizard.ALLOW_METADATA_ATTRIBUTES))) {
                e.setAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.CACHED_WIZARD_FIELD_DATA,
                        groupDefinition);
            }
        }
    }

    private static class UpdateFooterTask implements UpdateTask {
        private GroupDefinition groupDefinition;

        private UpdateFooterTask(final GroupDefinition groupDefinition) {
            this.groupDefinition = groupDefinition;
        }

        public void processElement(final ReportElement e) {
            if (Boolean.TRUE.equals(e.getAttribute(AttributeNames.Wizard.NAMESPACE,
                    AttributeNames.Wizard.ALLOW_METADATA_STYLING))) {
                e.setAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.CACHED_WIZARD_FORMAT_DATA,
                        groupDefinition.getFooter());
            }
            if (Boolean.TRUE.equals(e.getAttribute(AttributeNames.Wizard.NAMESPACE,
                    AttributeNames.Wizard.ALLOW_METADATA_ATTRIBUTES))) {
                e.setAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.CACHED_WIZARD_FIELD_DATA,
                        groupDefinition);
            }
        }
    }

    private static class UpdateDetailsTask implements UpdateTask {
        private FieldDefinition fieldDefinition;

        private UpdateDetailsTask(final FieldDefinition groupDefinition) {
            this.fieldDefinition = groupDefinition;
        }

        public void processElement(final ReportElement e) {
            final String field = fieldDefinition.getField();
            final Object labelFor = e.getAttribute(AttributeNames.Wizard.NAMESPACE,
                    AttributeNames.Wizard.LABEL_FOR);
            if (labelFor != null) {
                if (ObjectUtilities.equal(field, labelFor) == false) {
                    return;
                }
            } else {
                final Object fieldName = e.getAttribute(AttributeNames.Core.NAMESPACE, AttributeNames.Core.FIELD);
                if (ObjectUtilities.equal(field, fieldName) == false) {
                    return;
                }
            }

            if (Boolean.TRUE.equals(e.getAttribute(AttributeNames.Wizard.NAMESPACE,
                    AttributeNames.Wizard.ALLOW_METADATA_STYLING))) {
                e.setAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.CACHED_WIZARD_FORMAT_DATA,
                        fieldDefinition);

                if (Boolean.TRUE.equals(e.getAttribute(AttributeNames.Wizard.NAMESPACE,
                        AttributeNames.Wizard.PRESERVE_USER_STYLING))) {
                    final ElementStyleSheet styleSheet = e.getStyle();
                    if (styleSheet.isLocalKey(TextStyleKeys.BOLD)) {
                        if (e.getAttribute(AttributeNames.Wizard.NAMESPACE,
                                AttributeNames.Wizard.ENABLE_STYLE_BOLD) != null) {
                            e.setAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.ENABLE_STYLE_BOLD,
                                    Boolean.FALSE);
                        }
                    }
                    if (styleSheet.isLocalKey(TextStyleKeys.ITALIC)) {
                        if (e.getAttribute(AttributeNames.Wizard.NAMESPACE,
                                AttributeNames.Wizard.ENABLE_STYLE_ITALICS) != null) {
                            e.setAttribute(AttributeNames.Wizard.NAMESPACE,
                                    AttributeNames.Wizard.ENABLE_STYLE_ITALICS, Boolean.FALSE);
                        }
                    }
                    if (styleSheet.isLocalKey(TextStyleKeys.UNDERLINED)) {
                        if (e.getAttribute(AttributeNames.Wizard.NAMESPACE,
                                AttributeNames.Wizard.ENABLE_STYLE_UNDERLINE) != null) {
                            e.setAttribute(AttributeNames.Wizard.NAMESPACE,
                                    AttributeNames.Wizard.ENABLE_STYLE_UNDERLINE, Boolean.FALSE);
                        }
                    }
                    if (styleSheet.isLocalKey(TextStyleKeys.STRIKETHROUGH)) {
                        if (e.getAttribute(AttributeNames.Wizard.NAMESPACE,
                                AttributeNames.Wizard.ENABLE_STYLE_STRIKETHROUGH) != null) {
                            e.setAttribute(AttributeNames.Wizard.NAMESPACE,
                                    AttributeNames.Wizard.ENABLE_STYLE_STRIKETHROUGH, Boolean.FALSE);
                        }
                    }
                    if (styleSheet.isLocalKey(TextStyleKeys.FONT)) {
                        if (e.getAttribute(AttributeNames.Wizard.NAMESPACE,
                                AttributeNames.Wizard.ENABLE_STYLE_FONTFAMILY) != null) {
                            e.setAttribute(AttributeNames.Wizard.NAMESPACE,
                                    AttributeNames.Wizard.ENABLE_STYLE_FONTFAMILY, Boolean.FALSE);
                        }
                    }
                    if (styleSheet.isLocalKey(TextStyleKeys.FONTSIZE)) {
                        if (e.getAttribute(AttributeNames.Wizard.NAMESPACE,
                                AttributeNames.Wizard.ENABLE_STYLE_FONTSIZE) != null) {
                            e.setAttribute(AttributeNames.Wizard.NAMESPACE,
                                    AttributeNames.Wizard.ENABLE_STYLE_FONTSIZE, Boolean.FALSE);
                        }
                    }
                    if (styleSheet.isLocalKey(ElementStyleKeys.PAINT)) {
                        if (e.getAttribute(AttributeNames.Wizard.NAMESPACE,
                                AttributeNames.Wizard.ENABLE_STYLE_COLOR) != null) {
                            e.setAttribute(AttributeNames.Wizard.NAMESPACE,
                                    AttributeNames.Wizard.ENABLE_STYLE_COLOR, Boolean.FALSE);
                        }
                    }
                    if (styleSheet.isLocalKey(ElementStyleKeys.BACKGROUND_COLOR)) {
                        if (e.getAttribute(AttributeNames.Wizard.NAMESPACE,
                                AttributeNames.Wizard.ENABLE_STYLE_BACKGROUND_COLOR) != null) {
                            e.setAttribute(AttributeNames.Wizard.NAMESPACE,
                                    AttributeNames.Wizard.ENABLE_STYLE_BACKGROUND_COLOR, Boolean.FALSE);
                        }
                    }
                    if (styleSheet.isLocalKey(ElementStyleKeys.VALIGNMENT)) {
                        if (e.getAttribute(AttributeNames.Wizard.NAMESPACE,
                                AttributeNames.Wizard.ENABLE_STYLE_VALIGNMENT) != null) {
                            e.setAttribute(AttributeNames.Wizard.NAMESPACE,
                                    AttributeNames.Wizard.ENABLE_STYLE_VALIGNMENT, Boolean.FALSE);
                        }
                    }
                    if (styleSheet.isLocalKey(ElementStyleKeys.ALIGNMENT)) {
                        if (e.getAttribute(AttributeNames.Wizard.NAMESPACE,
                                AttributeNames.Wizard.ENABLE_STYLE_ALIGNMENT) != null) {
                            e.setAttribute(AttributeNames.Wizard.NAMESPACE,
                                    AttributeNames.Wizard.ENABLE_STYLE_ALIGNMENT, Boolean.FALSE);
                        }
                    }
                }
            }
            if (Boolean.TRUE.equals(e.getAttribute(AttributeNames.Wizard.NAMESPACE,
                    AttributeNames.Wizard.ALLOW_METADATA_ATTRIBUTES))) {
                e.setAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.CACHED_WIZARD_FIELD_DATA,
                        fieldDefinition);
            }
        }
    }

    protected void iterateSection(final Section s, final UpdateTask task) {
        final int count = s.getElementCount();
        for (int i = 0; i < count; i++) {
            final ReportElement element = s.getElement(i);
            task.processElement(element);
            if (element instanceof SubReport) {
                continue;
            }
            if (element instanceof Section) {
                iterateSection((Section) element, task);
            }
        }
    }

    protected AbstractReportDefinition performGenerationPreProcessing() throws ReportProcessingException {
        setupWatermark();
        setupRelationalGroups();
        /** remove check on data source to display to use cross-tab
         if (isCrosstab())
         {
         setupCrosstab();
         }
         else
         {
         clearCrosstab();
            
         }
         */
        setupDetails();
        return definition;
    }

    private void clearCrosstab() {
        final CrosstabGroup crosstabGroup = lookupCrosstab();
        if (crosstabGroup != null) {
            if (definition.getRootGroup() == crosstabGroup) {
                definition.setRootGroup(new RelationalGroup());
            } else {
                final Section parentSection = crosstabGroup.getParentSection();
                if (parentSection instanceof SubGroupBody) {
                    final SubGroupBody sgb = (SubGroupBody) parentSection;
                    sgb.setGroup(new RelationalGroup());
                }
            }
        }

    }

    /**
     * Creating a crosstab report deletes all sub-definitions and the itemband.
     *
     * @throws ReportProcessingException if an error occurs.
     */
    private void setupCrosstab() throws ReportProcessingException {
        CrosstabGroup crosstab = lookupCrosstab();
        if (crosstab == null) {
            crosstab = new CrosstabGroup();
            insertCrosstab(crosstab);
        }

        Group insertGroup = crosstab;
        final GroupDefinition[] groupDefinitions = wizardSpecification.getGroupDefinitions();
        for (int i = 0; i < groupDefinitions.length; i++) {
            final GroupDefinition groupDefinition = groupDefinitions[i];
            if (GroupType.CT_OTHER.equals(groupDefinition.getGroupType()) == false) {
                continue;
            }

            // create a new group and insert it at the end
            final CrosstabOtherGroup relationalGroup = new CrosstabOtherGroup();
            if (groupDefinition.getGroupName() != null) {
                relationalGroup.setName(groupDefinition.getGroupName());
            }
            configureCrosstabOtherGroup(relationalGroup, groupDefinition);
            insertGroup.setBody(new CrosstabOtherGroupBody(relationalGroup));
            insertGroup = relationalGroup;
        }

        for (int i = 0; i < groupDefinitions.length; i++) {
            final GroupDefinition groupDefinition = groupDefinitions[i];
            if (GroupType.CT_ROW.equals(groupDefinition.getGroupType()) == false) {
                continue;
            }

            // create a new group and insert it at the end
            final CrosstabRowGroup relationalGroup = new CrosstabRowGroup();
            if (groupDefinition.getGroupName() != null) {
                relationalGroup.setName(groupDefinition.getGroupName());
            }
            configureCrosstabRowGroup(relationalGroup, groupDefinition);
            insertGroup.setBody(new CrosstabRowGroupBody(relationalGroup));
            insertGroup = relationalGroup;
        }

        for (int i = 0; i < groupDefinitions.length; i++) {
            final GroupDefinition groupDefinition = groupDefinitions[i];
            if (GroupType.CT_COLUMN.equals(groupDefinition.getGroupType()) == false) {
                continue;
            }

            // create a new group and insert it at the end
            final CrosstabColumnGroup relationalGroup = new CrosstabColumnGroup();
            if (groupDefinition.getGroupName() != null) {
                relationalGroup.setName(groupDefinition.getGroupName());
            }
            configureCrosstabColumnGroup(relationalGroup, groupDefinition);
            insertGroup.setBody(new CrosstabColumnGroupBody(relationalGroup));
            insertGroup = relationalGroup;
        }

        final Band itemBand = AutoGeneratorUtility.findGeneratedContent(definition.getItemBand());
        if (itemBand == null) {
            return;
        }
        final DetailFieldDefinition[] detailFieldDefinitions = wizardSpecification.getDetailFieldDefinitions();
        if (detailFieldDefinitions.length == 0) {
            return;
        }

        final Float[] widthSpecs = new Float[detailFieldDefinitions.length];
        for (int i = 0; i < detailFieldDefinitions.length; i++) {
            final DetailFieldDefinition fieldDefinition = detailFieldDefinitions[i];
            final Length length = fieldDefinition.getWidth();
            if (length == null) {
                continue;
            }
            widthSpecs[i] = length.getNormalizedValue();
        }
        final float[] computedWidth = AutoGeneratorUtility.computeFieldWidths(widthSpecs,
                definition.getPageDefinition().getWidth());

        itemBand.getStyle().setStyleProperty(BandStyleKeys.LAYOUT, "row");
        for (int i = 0; i < detailFieldDefinitions.length; i++) {
            final DetailFieldDefinition detailFieldDefinition = detailFieldDefinitions[i];
            setupField(null, null, itemBand, detailFieldDefinition, computedWidth[i], i);
        }

    }

    protected void setupDetails() throws ReportProcessingException {
        final DetailFieldDefinition[] detailFieldDefinitions = wizardSpecification.getDetailFieldDefinitions();
        if (detailFieldDefinitions.length == 0) {
            if (wizardSpecification.isAutoGenerateDetails()) {
                final RelationalAutoGeneratorPreProcessor generatorPreProcessor = new RelationalAutoGeneratorPreProcessor();
                if (definition instanceof MasterReport) {
                    generatorPreProcessor.performPreProcessing((MasterReport) definition, flowController);
                } else if (definition instanceof SubReport) {
                    generatorPreProcessor.performPreProcessing((SubReport) definition, flowController);
                }
            }
            return;
        }

        definition.getDetailsHeader().setRepeat(true);
        definition.getDetailsFooter().setRepeat(true);

        final Band detailsHeader = AutoGeneratorUtility.findGeneratedContent(definition.getDetailsHeader());
        final Band detailsFooter = AutoGeneratorUtility.findGeneratedContent(definition.getDetailsFooter());
        final Band itemBand = AutoGeneratorUtility.findGeneratedContent(definition.getItemBand());

        if (itemBand == null) {
            return;
        }

        final Float[] widthSpecs = new Float[detailFieldDefinitions.length];
        for (int i = 0; i < detailFieldDefinitions.length; i++) {
            final DetailFieldDefinition fieldDefinition = detailFieldDefinitions[i];
            final Length length = fieldDefinition.getWidth();
            if (length == null) {
                continue;
            }
            widthSpecs[i] = length.getNormalizedValue();
        }
        final float[] computedWidth = AutoGeneratorUtility.computeFieldWidths(widthSpecs,
                definition.getPageDefinition().getWidth());

        itemBand.getStyle().setStyleProperty(BandStyleKeys.LAYOUT, "row");
        if (detailsHeader != null) {
            detailsHeader.getStyle().setStyleProperty(BandStyleKeys.LAYOUT, "row");
        }
        if (detailsFooter != null) {
            detailsFooter.getStyle().setStyleProperty(BandStyleKeys.LAYOUT, "row");
        }

        for (int i = 0; i < detailFieldDefinitions.length; i++) {
            final DetailFieldDefinition detailFieldDefinition = detailFieldDefinitions[i];
            setupField(detailsHeader, detailsFooter, itemBand, detailFieldDefinition, computedWidth[i], i);
        }

        if (detailsFooter != null) {
            final Element[] elements = detailsFooter.getElementArray();
            boolean footerEmpty = true;
            for (int i = 0; i < elements.length; i++) {
                final Element element = elements[i];
                if (LabelType.class.isInstance(element.getElementType()) == false) {
                    footerEmpty = false;
                    break;
                }
            }
            if (footerEmpty) {
                detailsFooter.clear();
            }
        }
    }

    protected void setupDefaultPadding(final Band band, final Element detailElement) {
        final Object maybePaddingTop = band.getAttribute(AttributeNames.Wizard.NAMESPACE,
                AttributeNames.Wizard.PADDING_TOP);
        final Object maybePaddingLeft = band.getAttribute(AttributeNames.Wizard.NAMESPACE,
                AttributeNames.Wizard.PADDING_LEFT);
        final Object maybePaddingBottom = band.getAttribute(AttributeNames.Wizard.NAMESPACE,
                AttributeNames.Wizard.PADDING_BOTTOM);
        final Object maybePaddingRight = band.getAttribute(AttributeNames.Wizard.NAMESPACE,
                AttributeNames.Wizard.PADDING_RIGHT);

        if (maybePaddingTop instanceof Number == false || maybePaddingLeft instanceof Number == false
                || maybePaddingBottom instanceof Number == false || maybePaddingRight instanceof Number == false) {
            return;
        }

        final Number paddingTop = (Number) maybePaddingTop;
        final Number paddingLeft = (Number) maybePaddingLeft;
        final Number paddingBottom = (Number) maybePaddingBottom;
        final Number paddingRight = (Number) maybePaddingRight;

        final ElementStyleSheet styleSheet = detailElement.getStyle();
        styleSheet.setStyleProperty(ElementStyleKeys.PADDING_TOP, new Float(paddingTop.floatValue()));
        styleSheet.setStyleProperty(ElementStyleKeys.PADDING_LEFT, new Float(paddingLeft.floatValue()));
        styleSheet.setStyleProperty(ElementStyleKeys.PADDING_BOTTOM, new Float(paddingBottom.floatValue()));
        styleSheet.setStyleProperty(ElementStyleKeys.PADDING_RIGHT, new Float(paddingRight.floatValue()));
    }

    protected void setupDefaultGrid(final Band band, final Element detailElement) {
        setupDefaultPadding(band, detailElement);
        final ElementStyleSheet styleSheet = detailElement.getStyle();
        // Always make the height of the detailElement dynamic to the band
        // According to thomas negative numbers equate to percentages
        styleSheet.setStyleProperty(ElementStyleKeys.MIN_HEIGHT, new Float(-100));

        final Object maybeBorderStyle = band.getAttribute(AttributeNames.Wizard.NAMESPACE,
                AttributeNames.Wizard.GRID_STYLE);
        final Object maybeBorderWidth = band.getAttribute(AttributeNames.Wizard.NAMESPACE,
                AttributeNames.Wizard.GRID_WIDTH);
        final Object maybeBorderColor = band.getAttribute(AttributeNames.Wizard.NAMESPACE,
                AttributeNames.Wizard.GRID_COLOR);

        if (maybeBorderColor instanceof Color == false || maybeBorderStyle instanceof BorderStyle == false
                || maybeBorderWidth instanceof Number == false) {
            return;
        }

        final BorderStyle style = (BorderStyle) maybeBorderStyle;
        final Color color = (Color) maybeBorderColor;
        final Number number = (Number) maybeBorderWidth;
        final Float width = new Float(number.floatValue());

        styleSheet.setStyleProperty(ElementStyleKeys.BORDER_TOP_WIDTH, width);
        styleSheet.setStyleProperty(ElementStyleKeys.BORDER_TOP_COLOR, color);
        styleSheet.setStyleProperty(ElementStyleKeys.BORDER_TOP_STYLE, style);

        styleSheet.setStyleProperty(ElementStyleKeys.BORDER_LEFT_WIDTH, width);
        styleSheet.setStyleProperty(ElementStyleKeys.BORDER_LEFT_COLOR, color);
        styleSheet.setStyleProperty(ElementStyleKeys.BORDER_LEFT_STYLE, style);

        styleSheet.setStyleProperty(ElementStyleKeys.BORDER_BOTTOM_WIDTH, width);
        styleSheet.setStyleProperty(ElementStyleKeys.BORDER_BOTTOM_COLOR, color);
        styleSheet.setStyleProperty(ElementStyleKeys.BORDER_BOTTOM_STYLE, style);

        styleSheet.setStyleProperty(ElementStyleKeys.BORDER_RIGHT_WIDTH, width);
        styleSheet.setStyleProperty(ElementStyleKeys.BORDER_RIGHT_COLOR, color);
        styleSheet.setStyleProperty(ElementStyleKeys.BORDER_RIGHT_STYLE, style);
    }

    protected void setupField(final Band detailsHeader, final Band detailsFooter, final Band itemBand,
            final DetailFieldDefinition field, final float width, final int fieldIdx)
            throws ReportProcessingException {
        if (StringUtils.isEmpty(field.getField())) {
            return;
        }

        final Element detailElement = AutoGeneratorUtility.generateDetailsElement(field.getField(),
                computeElementType(field));
        setupDefaultGrid(itemBand, detailElement);

        final String id = "wizard::details-" + field.getField();
        detailElement.setName(id);
        detailElement.getStyle().setStyleProperty(ElementStyleKeys.MIN_WIDTH, new Float(width));
        if (Boolean.TRUE.equals(detailElement.getAttribute(AttributeNames.Wizard.NAMESPACE,
                AttributeNames.Wizard.ALLOW_METADATA_STYLING))) {
            detailElement.setAttribute(AttributeNames.Wizard.NAMESPACE,
                    AttributeNames.Wizard.CACHED_WIZARD_FORMAT_DATA, field);
        }
        if (Boolean.TRUE.equals(detailElement.getAttribute(AttributeNames.Wizard.NAMESPACE,
                AttributeNames.Wizard.ALLOW_METADATA_ATTRIBUTES))) {
            detailElement.setAttribute(AttributeNames.Wizard.NAMESPACE,
                    AttributeNames.Wizard.CACHED_WIZARD_FIELD_DATA, field);
        }
        itemBand.addElement(detailElement);

        if (Boolean.TRUE.equals(field.getOnlyShowChangingValues())) {
            detailElement.setAttribute(AttributeNames.Wizard.NAMESPACE,
                    AttributeNames.Wizard.ONLY_SHOW_CHANGING_VALUES, Boolean.TRUE);
        }

        if (detailsHeader != null) {
            final Element headerElement = AutoGeneratorUtility.generateHeaderElement(field.getField());
            setupDefaultGrid(detailsHeader, headerElement);
            headerElement.getStyle().setStyleProperty(ElementStyleKeys.MIN_WIDTH, new Float(width));
            if (Boolean.TRUE.equals(headerElement.getAttribute(AttributeNames.Wizard.NAMESPACE,
                    AttributeNames.Wizard.ALLOW_METADATA_STYLING))) {
                headerElement.setAttribute(AttributeNames.Wizard.NAMESPACE,
                        AttributeNames.Wizard.CACHED_WIZARD_FORMAT_DATA, field);
            }
            if (Boolean.TRUE.equals(headerElement.getAttribute(AttributeNames.Wizard.NAMESPACE,
                    AttributeNames.Wizard.ALLOW_METADATA_ATTRIBUTES))) {
                headerElement.setAttribute(AttributeNames.Wizard.NAMESPACE,
                        AttributeNames.Wizard.CACHED_WIZARD_FIELD_DATA, field);
            }
            headerElement.setAttribute(AttributeNames.Wizard.NAMESPACE,
                    MetaAttributeNames.Style.HORIZONTAL_ALIGNMENT, field.getHorizontalAlignment());

            detailsHeader.addElement(headerElement);
        }

        if (detailsFooter != null) {
            final Class aggFunctionClass = field.getAggregationFunction();
            final Element footerElement = AutoGeneratorUtility.generateFooterElement(aggFunctionClass,
                    computeElementType(field), null, field.getField());

            setupDefaultGrid(detailsFooter, footerElement);

            footerElement.getStyle().setStyleProperty(ElementStyleKeys.MIN_WIDTH, new Float(width));
            if (Boolean.TRUE.equals(footerElement.getAttribute(AttributeNames.Wizard.NAMESPACE,
                    AttributeNames.Wizard.ALLOW_METADATA_STYLING))) {
                footerElement.setAttribute(AttributeNames.Wizard.NAMESPACE,
                        AttributeNames.Wizard.CACHED_WIZARD_FORMAT_DATA, field);
            }
            if (Boolean.TRUE.equals(footerElement.getAttribute(AttributeNames.Wizard.NAMESPACE,
                    AttributeNames.Wizard.ALLOW_METADATA_ATTRIBUTES))) {
                footerElement.setAttribute(AttributeNames.Wizard.NAMESPACE,
                        AttributeNames.Wizard.CACHED_WIZARD_FIELD_DATA, field);
            }

            detailsFooter.addElement(footerElement);
        }
    }

    /*
     * Removes the unusedTemplateGroups based on the assumption that if a group doesn't have any
     * fields assigned to it that it is empty.
     */
    private void removedUnusedTemplateGroups(final int groupsDefined) {
        final RelationalGroup[] templateRelationalGroups = getTemplateRelationalGroups();
        final int templateRelationalGroupCount = templateRelationalGroups.length;
        for (int i = groupsDefined; i < templateRelationalGroupCount; i++) {
            final RelationalGroup templateRelationalGroup = templateRelationalGroups[i];
            definition.removeGroup(templateRelationalGroup);
        }
    }

    /**
     * @return the relational groups in the templates in a flattened array.
     */
    private RelationalGroup[] getTemplateRelationalGroups() {
        final ArrayList<RelationalGroup> relationalGroups = new ArrayList<RelationalGroup>();
        Group group = definition.getRootGroup();
        while (group != null && group instanceof RelationalGroup) {
            relationalGroups.add((RelationalGroup) group);
            final GroupBody body = group.getBody();
            if (body instanceof SubGroupBody) {
                final SubGroupBody sgBody = (SubGroupBody) body;
                if (sgBody.getGroup() instanceof RelationalGroup) {
                    group = sgBody.getGroup();
                } else {
                    group = null;
                }
            } else {
                group = null;
            }
        }

        return relationalGroups.toArray(new RelationalGroup[relationalGroups.size()]);
    }

    private void setupRelationalGroups() throws ReportProcessingException {
        final Group rootgroup = definition.getRootGroup();
        RelationalGroup group;
        if (rootgroup instanceof RelationalGroup == false) {
            group = null;
        } else {
            group = (RelationalGroup) rootgroup;
        }

        final RelationalGroup template = findInnermostRelationalGroup(definition);

        final GroupDefinition[] groupDefinitions = wizardSpecification.getGroupDefinitions();
        for (int i = 0; i < groupDefinitions.length; i++) {
            final GroupDefinition groupDefinition = groupDefinitions[i];
            final GroupType type = groupDefinition.getGroupType();
            if (type != null && GroupType.RELATIONAL.equals(type) == false) {
                continue;
            }

            if (group == null) {
                // create a new group and insert it at the end
                final RelationalGroup relationalGroup;
                if (template != null) {
                    relationalGroup = (RelationalGroup) template.derive();
                } else {
                    relationalGroup = new RelationalGroup();
                }

                if (groupDefinition.getGroupName() != null) {
                    relationalGroup.setName(groupDefinition.getGroupName());
                }
                configureRelationalGroup(relationalGroup, groupDefinition, i);
                insertGroup(relationalGroup);
            } else {
                // modify the existing group
                configureRelationalGroup(group, groupDefinition, i);

                final GroupBody body = group.getBody();
                if (body instanceof SubGroupBody) {
                    final SubGroupBody sgBody = (SubGroupBody) body;
                    if (sgBody.getGroup() instanceof RelationalGroup) {
                        group = (RelationalGroup) sgBody.getGroup();
                    } else {
                        group = null;
                    }
                } else {
                    group = null;
                }
            }
        }
        // Remove any group bands are not being used ie. groups with no fields
        removedUnusedTemplateGroups(groupDefinitions.length);
    }

    private RelationalGroup findInnermostRelationalGroup(final AbstractReportDefinition definition) {
        RelationalGroup retval = null;
        Group existingGroup = definition.getRootGroup();
        while (existingGroup instanceof RelationalGroup) {
            retval = (RelationalGroup) existingGroup;
            final GroupBody body = existingGroup.getBody();
            if (body instanceof SubGroupBody == false) {
                return retval;
            }
            final SubGroupBody sgb = (SubGroupBody) body;
            existingGroup = sgb.getGroup();
        }

        return retval;
    }

    /**
     * Inserts the crosstab into the report as innermost group. This method will fail if there is already a crosstab
     * active.
     *
     * @param crosstabGroup
     */
    private void insertCrosstab(final CrosstabGroup crosstabGroup) {
        Group existingGroup = definition.getRootGroup();
        GroupBody gb = existingGroup.getBody();
        while (gb instanceof SubGroupBody) {
            final SubGroupBody sgb = (SubGroupBody) gb;
            existingGroup = sgb.getGroup();
            gb = existingGroup.getBody();
        }
        existingGroup.setBody(new SubGroupBody(crosstabGroup));
    }

    private CrosstabGroup lookupCrosstab() {
        Group existingGroup = definition.getRootGroup();
        if (existingGroup instanceof CrosstabGroup) {
            return (CrosstabGroup) existingGroup;
        }

        GroupBody gb = existingGroup.getBody();
        while (gb instanceof SubGroupBody) {
            final SubGroupBody sgb = (SubGroupBody) gb;
            existingGroup = sgb.getGroup();
            if (existingGroup instanceof CrosstabGroup) {
                return (CrosstabGroup) existingGroup;
            }
            gb = existingGroup.getBody();
        }

        return null;
    }

    private void insertGroup(final RelationalGroup group) {
        Group lastGroup = null;
        Group insertGroup = definition.getRootGroup();
        while (true) {
            if (insertGroup instanceof RelationalGroup == false) {
                if (lastGroup == null) {
                    definition.setRootGroup(group);
                    group.setBody(new SubGroupBody(insertGroup));
                    return;
                }

                final GroupBody body = lastGroup.getBody();
                final SubGroupBody sgb = new SubGroupBody(group);
                lastGroup.setBody(sgb);
                group.setBody(body);
                return;
            }

            final GroupBody body = insertGroup.getBody();
            if (body instanceof SubGroupBody == false) {
                final SubGroupBody sgb = new SubGroupBody(group);
                insertGroup.setBody(sgb);
                group.setBody(body);
                return;
            }

            lastGroup = insertGroup;
            final SubGroupBody sgb = (SubGroupBody) body;
            insertGroup = sgb.getGroup();
        }
    }

    private void configureCrosstabOtherGroup(final CrosstabOtherGroup group, final GroupDefinition groupDefinition)
            throws ReportProcessingException {
        final String groupField = groupDefinition.getField();
        group.setField(groupField);

        configureCrosstabGroupHeader(group, groupDefinition);
        configureCrosstabGroupFooter(group, groupDefinition);
    }

    private void configureCrosstabRowGroup(final CrosstabRowGroup group, final GroupDefinition groupDefinition)
            throws ReportProcessingException {
        final String groupField = groupDefinition.getField();
        group.setField(groupField);

        configureCrosstabGroupHeader(group, groupDefinition);
        configureCrosstabGroupFooter(group, groupDefinition);
    }

    private void configureCrosstabColumnGroup(final CrosstabColumnGroup group,
            final GroupDefinition groupDefinition) throws ReportProcessingException {
        final String groupField = groupDefinition.getField();
        group.setField(groupField);

        configureCrosstabGroupHeader(group, groupDefinition);
        configureCrosstabGroupFooter(group, groupDefinition);
    }

    protected void configureRelationalGroup(final RelationalGroup group, final GroupDefinition groupDefinition,
            final int index) throws ReportProcessingException {
        final String groupField = groupDefinition.getField();
        if (groupField != null) {
            group.setFieldsArray(new String[] { groupField });
        }

        configureRelationalGroupFooter(group, groupDefinition, index);
        configureRelationalGroupHeader(group, groupDefinition, index);
    }

    private void configureCrosstabGroupHeader(final Group group, final GroupDefinition groupDefinition) {
        /*
        final RootBandDefinition headerDefinition = groupDefinition.getHeader();
        if (headerDefinition.isVisible())
        {
          final GroupHeader header = group.getHeader();
          final Boolean repeat = headerDefinition.getRepeat();
          if (repeat != null)
          {
            header.setRepeat(repeat.booleanValue());
          }
            
          final Band content = AutoGeneratorUtility.findGeneratedContent(header);
          if (content == null)
          {
            return;
          }
            
          final Element headerElement = AutoGeneratorUtility.generateDetailsElement
              (groupDefinition.getField(), computeElementType(groupDefinition));
          final Length length = groupDefinition.getWidth();
          if (length != null)
          {
            headerElement.getStyle().setStyleProperty(ElementStyleKeys.MIN_WIDTH, length.getNormalizedValue());
          }
          headerElement.setAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.CACHED_WIZARD_FORMAT_DATA,
          headerDefinition);
          headerElement.setAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.CACHED_WIZARD_FIELD_DATA,
          groupDefinition);
            
          content.clear();
          content.addElement(headerElement);
        }
        */
    }

    protected void configureRelationalGroupHeader(final RelationalGroup group,
            final GroupDefinition groupDefinition, final int index) {
        final RootBandDefinition headerDefinition = groupDefinition.getHeader();
        if (headerDefinition.isVisible()) {
            final GroupHeader header = group.getHeader();
            final Boolean repeat = headerDefinition.getRepeat();
            if (repeat != null) {
                header.setRepeat(repeat.booleanValue());
            }

            final Band content = AutoGeneratorUtility.findGeneratedContent(header);
            if (content == null) {
                return;
            }

            final Element headerLabelElement = new Element();
            headerLabelElement.setElementType(new LabelType());
            if (groupDefinition.getDisplayName() != null) {
                headerLabelElement.setAttribute(AttributeNames.Core.NAMESPACE, AttributeNames.Core.VALUE,
                        groupDefinition.getDisplayName());
            } else {
                headerLabelElement.setAttribute(AttributeNames.Core.NAMESPACE, AttributeNames.Core.VALUE,
                        groupDefinition.getField());
                headerLabelElement.setAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.LABEL_FOR,
                        groupDefinition.getField());
                headerLabelElement.setAttribute(AttributeNames.Wizard.NAMESPACE,
                        AttributeNames.Wizard.ALLOW_METADATA_ATTRIBUTES, Boolean.TRUE);
            }

            final Element headerValueElement = AutoGeneratorUtility
                    .generateDetailsElement(groupDefinition.getField(), computeElementType(groupDefinition));
            headerValueElement.setAttribute(AttributeNames.Core.NAMESPACE, AttributeNames.Core.NULL_VALUE, "-");

            final Band headerElement = new Band();
            headerElement.getStyle().setStyleProperty(BandStyleKeys.LAYOUT, BandStyleKeys.LAYOUT_INLINE);
            headerElement.getStyle().setStyleProperty(ElementStyleKeys.MIN_WIDTH, new Float(-100));
            headerElement.getStyle().setStyleProperty(ElementStyleKeys.DYNAMIC_HEIGHT, Boolean.TRUE);
            headerElement.setAttribute(AttributeNames.Wizard.NAMESPACE,
                    AttributeNames.Wizard.ALLOW_METADATA_STYLING, Boolean.TRUE);
            headerElement.setAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.LABEL_FOR,
                    groupDefinition.getField());
            headerElement.setAttribute(AttributeNames.Wizard.NAMESPACE,
                    AttributeNames.Wizard.CACHED_WIZARD_FORMAT_DATA, headerDefinition);
            headerElement.addElement(headerLabelElement);
            headerElement.addElement(headerValueElement);
            content.clear();
            content.addElement(headerElement);
        }
    }

    protected void configureRelationalGroupFooter(final RelationalGroup group,
            final GroupDefinition groupDefinition, final int index) throws ReportProcessingException {
        final RootBandDefinition footerDefinition = groupDefinition.getFooter();
        if (footerDefinition.isVisible() == false) {
            return;
        }

        if (groupDefinition.getAggregationFunction() == null && (groupDefinition.getGroupTotalsLabel() == null
                || groupDefinition.getGroupTotalsLabel().length() == 0)) {
            return;
        }

        final GroupFooter footer = group.getFooter();
        final Boolean repeat = footerDefinition.getRepeat();
        if (repeat != null) {
            footer.setRepeat(repeat.booleanValue());
        }

        final Band content = AutoGeneratorUtility.findGeneratedContent(footer);
        if (content == null) {
            return;
        }

        final Class aggFunctionClass = groupDefinition.getAggregationFunction();
        final Element footerValueElement = AutoGeneratorUtility.generateFooterElement(aggFunctionClass,
                computeElementType(groupDefinition), groupDefinition.getGroupName(), groupDefinition.getField());

        final Element footerLabelElement = new Element();
        footerLabelElement.setElementType(new LabelType());
        if (groupDefinition.getGroupTotalsLabel() != null) {
            footerLabelElement.setAttribute(AttributeNames.Core.NAMESPACE, AttributeNames.Core.VALUE,
                    groupDefinition.getGroupTotalsLabel());
        } else {
            footerLabelElement.setAttribute(AttributeNames.Core.NAMESPACE, AttributeNames.Core.VALUE,
                    groupDefinition.getField());
            footerLabelElement.setAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.LABEL_FOR,
                    groupDefinition.getField());
            footerLabelElement.setAttribute(AttributeNames.Wizard.NAMESPACE,
                    AttributeNames.Wizard.ALLOW_METADATA_ATTRIBUTES, Boolean.TRUE);
        }

        final Band footerElement = new Band();
        footerElement.getStyle().setStyleProperty(BandStyleKeys.LAYOUT, BandStyleKeys.LAYOUT_INLINE);
        footerElement.getStyle().setStyleProperty(ElementStyleKeys.MIN_WIDTH, new Float(-100));
        footerElement.getStyle().setStyleProperty(ElementStyleKeys.DYNAMIC_HEIGHT, Boolean.TRUE);
        footerElement.setAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.ALLOW_METADATA_STYLING,
                Boolean.TRUE);
        footerElement.setAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.LABEL_FOR,
                groupDefinition.getField());
        footerElement.setAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.CACHED_WIZARD_FORMAT_DATA,
                footerDefinition);
        footerElement.setAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.CACHED_WIZARD_FIELD_DATA,
                groupDefinition);
        footerElement.addElement(footerLabelElement);
        footerElement.addElement(footerValueElement);

        content.clear();
        content.addElement(footerElement);
    }

    private void configureCrosstabGroupFooter(final Group group, final GroupDefinition groupDefinition)
            throws ReportProcessingException {
        /*
        final RootBandDefinition footerDefinition = groupDefinition.getFooter();
        if (footerDefinition.isVisible() == false)
        {
          return;
        }
            
        if (groupDefinition.getAggregationFunction() == null)
        {
          return;
        }
            
        final GroupFooter footer = group.getFooter();
        final Boolean repeat = footerDefinition.getRepeat();
        if (repeat != null)
        {
          footer.setRepeat(repeat.booleanValue());
        }
            
        final Band content = AutoGeneratorUtility.findGeneratedContent(footer);
        if (content == null)
        {
          return;
        }
            
        final Class aggFunctionClass = groupDefinition.getAggregationFunction();
        final Element footerValueElement = AutoGeneratorUtility.generateFooterElement
            (aggFunctionClass, computeElementType(groupDefinition),
        groupDefinition.getGroupName(), groupDefinition.getField());
        footerValueElement.setAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.CACHED_WIZARD_FORMAT_DATA,
         footer);
        footerValueElement.setAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.CACHED_WIZARD_FIELD_DATA,
        groupDefinition);
            
        content.clear();
        content.addElement(footerValueElement);
        */
    }

    protected ElementType computeElementType(final FieldDefinition fieldDefinition) {
        final String field = fieldDefinition.getField();
        final DataAttributes attributes = flowController.getDataSchema().getAttributes(field);
        if (attributes == null) {
            logger.warn("Field '" + field + "' is declared in the wizard-specification, "
                    + "but not present in the data. Assuming defaults.");
            return new TextFieldType();
        }
        final Class fieldType = (Class) attributes.getMetaAttribute(MetaAttributeNames.Core.NAMESPACE,
                MetaAttributeNames.Core.TYPE, Class.class, attributeContext);
        if (fieldType == null) {
            return new TextFieldType();
        }

        return AutoGeneratorUtility.createFieldType(fieldType);
    }

    private boolean isCrosstab() {
        final GroupDefinition[] groupDefinitions = wizardSpecification.getGroupDefinitions();
        for (int i = 0; i < groupDefinitions.length; i++) {
            final GroupDefinition groupDefinition = groupDefinitions[i];
            final GroupType groupType = groupDefinition.getGroupType();
            if (GroupType.CT_COLUMN.equals(groupType) || GroupType.CT_ROW.equals(groupType)) {
                return true;
            }
        }

        final DataAttributes tableAttributes = flowController.getDataSchema().getTableAttributes();
        final Object crosstabMode = tableAttributes.getMetaAttribute(MetaAttributeNames.Core.NAMESPACE,
                MetaAttributeNames.Core.CROSSTAB_MODE, String.class, attributeContext);
        if (MetaAttributeNames.Core.CROSSTAB_VALUE_NORMALIZED.equals(crosstabMode)) {
            // the data-source indicates a high probability that a crosstab is requested. 
            return true;
        }
        return false;
    }

    private void setupWatermark() {
        final WatermarkDefinition watermarkDefinition = wizardSpecification.getWatermarkDefinition();
        if (watermarkDefinition.isVisible() == false) {
            return;
        }

        if (watermarkDefinition.getSource() == null) {
            return;
        }

        final Watermark watermark = definition.getWatermark();
        final Band content = AutoGeneratorUtility.findGeneratedContent(watermark);
        if (content == null) {
            // there is already some content, and we are not allowed to override it.
            return;
        }

        content.clear();

        final Element watermarkImage = new Element();
        watermarkImage.setElementType(new ContentType());
        watermarkImage.setAttribute(AttributeNames.Core.NAMESPACE, AttributeNames.Core.VALUE,
                watermarkDefinition.getSource());
        final ElementStyleSheet watermarkStyle = watermarkImage.getStyle();
        watermarkStyle.setStyleProperty(ElementStyleKeys.POS_X, convertLength(watermarkDefinition.getX()));
        watermarkStyle.setStyleProperty(ElementStyleKeys.POS_Y, convertLength(watermarkDefinition.getY()));
        watermarkStyle.setStyleProperty(ElementStyleKeys.MIN_WIDTH, convertLength(watermarkDefinition.getWidth()));
        watermarkStyle.setStyleProperty(ElementStyleKeys.MIN_HEIGHT,
                convertLength(watermarkDefinition.getHeight()));
        watermarkStyle.setStyleProperty(ElementStyleKeys.KEEP_ASPECT_RATIO,
                watermarkDefinition.getKeepAspectRatio());
        watermarkStyle.setStyleProperty(ElementStyleKeys.SCALE, watermarkDefinition.getScale());

        content.addElement(watermarkImage);
    }

    private Float convertLength(final Length length) {
        if (length == null) {
            return null;
        }
        return length.getNormalizedValue();
    }

}