net.ceos.project.poi.annotated.core.Engine.java Source code

Java tutorial

Introduction

Here is the source code for net.ceos.project.poi.annotated.core.Engine.java

Source

/**
 * Copyright 2016 Carlos CRISTO ABREU
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.ceos.project.poi.annotated.core;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.RegionUtil;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import net.ceos.project.poi.annotated.annotation.XlsConditionalFormat;
import net.ceos.project.poi.annotated.annotation.XlsConfiguration;
import net.ceos.project.poi.annotated.annotation.XlsDecorator;
import net.ceos.project.poi.annotated.annotation.XlsDecorators;
import net.ceos.project.poi.annotated.annotation.XlsElement;
import net.ceos.project.poi.annotated.annotation.XlsFreeElement;
import net.ceos.project.poi.annotated.annotation.XlsNestedHeader;
import net.ceos.project.poi.annotated.annotation.XlsSheet;
import net.ceos.project.poi.annotated.definition.ExceptionMessage;
import net.ceos.project.poi.annotated.definition.ExtensionFileType;
import net.ceos.project.poi.annotated.definition.PropagationType;
import net.ceos.project.poi.annotated.definition.TitleOrientationType;
import net.ceos.project.poi.annotated.exception.ConfigurationException;
import net.ceos.project.poi.annotated.exception.CustomizedRulesException;
import net.ceos.project.poi.annotated.exception.ElementException;
import net.ceos.project.poi.annotated.exception.SheetException;
import net.ceos.project.poi.annotated.exception.WorkbookException;

public class Engine implements IEngine {

    /**
     * Get the runtime class of the object passed as parameter.
     * 
     * @param object
     *            the object
     * @return the runtime class
     * @throws ElementException
     *             given when null object.
     */
    private Class<?> initializeRuntimeClass(final Object object) throws ElementException {
        Class<?> oC = null;
        try {
            /* instance object class */
            oC = object.getClass();
        } catch (Exception e) {
            throw new ElementException(ExceptionMessage.ELEMENT_NULL_OBJECT.getMessage(), e);
        }
        return oC;
    }

    /**
     * Initialize the configuration to apply at the Excel.
     * 
     * @param configCriteria
     *            the {@link XConfigCriteria}
     * @param oC
     *            the {@link Class<?>}
     * @param insideCollection
     *            true if this configuration is inside of one collection
     * @param excludeCascadeInit
     *            true if to exclude the initialization of the parameter cascade
     *            level
     * @throws ConfigurationException
     *             given when basic configuration is missing.
     */
    private void initializeConfigurationData(final XConfigCriteria configCriteria, final Class<?> oC,
            final boolean insideCollection, final boolean excludeCascadeInit) throws ConfigurationException {
        /* Process @XlsConfiguration */
        if (PredicateFactory.isAnnotationXlsConfigurationPresent.test(oC)) {
            XlsConfiguration xlsAnnotation = (XlsConfiguration) oC.getAnnotation(XlsConfiguration.class);
            initializeXlsConfiguration(configCriteria, xlsAnnotation);
        } else {
            throw new ConfigurationException(ExceptionMessage.CONFIGURATION_XLSCONFIGURATION_MISSING.getMessage());
        }
        /* Process @XlsSheet */
        if (PredicateFactory.isAnnotationXlsSheetPresent.test(oC)) {
            XlsSheet xlsAnnotation = (XlsSheet) oC.getAnnotation(XlsSheet.class);
            initializeXlsSheet(configCriteria, xlsAnnotation, excludeCascadeInit);
            if (insideCollection && oC.isAnnotationPresent(XlsElement.class)) {
                /**
                 * if the collection is an attribut inside an object we get the
                 * sheet title name from the element
                 */
                XlsElement xlsElement = (XlsElement) oC.getAnnotation(XlsElement.class);
                if (!xlsElement.parentSheet()) {
                    configCriteria.setTitleSheet(xlsElement.title());
                    configCriteria.setElement(xlsElement);
                }
            }
        } else {
            throw new ConfigurationException(ExceptionMessage.CONFIGURATION_XLSSHEET_MISSING.getMessage());
        }
    }

    /**
     * Add the main XlsConfiguration configuration.
     * 
     * @param configCriteria
     *            the {@link XConfigCriteria}
     * @param annotation
     *            the {@link XlsConfiguration}
     */
    private void initializeXlsConfiguration(final XConfigCriteria configCriteria,
            final XlsConfiguration annotation) {
        configCriteria.setFileName(StringUtils.isBlank(configCriteria.getFileName()) ? annotation.nameFile()
                : configCriteria.getFileName());
        configCriteria.setExtension(
                configCriteria.getExtension() == null ? annotation.extensionFile() : configCriteria.getExtension());
        configCriteria
                .setCompleteFileName(configCriteria.getFileName() + configCriteria.getExtension().getExtension());
    }

    /**
     * Add the XlsSheet configuration.
     * 
     * @param configCriteria
     *            the {@link XConfigCriteria}
     * @param annotation
     *            the {@link XlsSheet}
     */
    private void initializeXlsSheet(final XConfigCriteria configCriteria, final XlsSheet annotation,
            final boolean excludeCascadeInit) {
        configCriteria.setTitleSheet(annotation.title());
        configCriteria.setTabColorSheet(annotation.tabColor());

        configCriteria.setPropagation(annotation.propagation());
        if (excludeCascadeInit) {
            configCriteria.setCascadeLevel(annotation.cascadeLevel());
        }

        configCriteria.setStartRow(annotation.startRow());
        configCriteria.setStartCell(annotation.startCell());

        configCriteria.setFreezePane(annotation.freezePane());
        configCriteria.setGroupElement(annotation.groupElement());

        configCriteria.setAutoResizeColumn(annotation.autoResizeColumn());
    }

    /**
     * initialize style cell via annotation {@link XlsDecorators}
     * 
     * @param objectClass
     *            the object class
     * @param configCriteria
     *            the {@link XConfigCriteria}
     * @throws ConfigurationException
     */
    private void initializeCellStyleViaAnnotation(final Class<?> objectClass, final XConfigCriteria configCriteria)
            throws ConfigurationException {
        if (PredicateFactory.isAnnotationXlsDecoratorsPresent.test(objectClass)) {
            XlsDecorators xlsDecorators = (XlsDecorators) objectClass.getAnnotation(XlsDecorators.class);
            for (XlsDecorator decorator : xlsDecorators.values()) {
                if (configCriteria.getStylesMap().containsKey(decorator.decoratorName())) {
                    throw new ConfigurationException(
                            ExceptionMessage.CONFIGURATION_CELLSTYLE_DUPLICATED.getMessage());
                }
                configCriteria.getStylesMap().put(decorator.decoratorName(), CellStyleHandler
                        .initializeCellStyleByXlsDecorator(configCriteria.getWorkbook(), decorator));
            }
        }
    }

    /**
     * Initialize the Workbook.
     * 
     * @param type
     *            the {@link ExtensionFileType} of workbook
     * @return the {@link Workbook}.
     */
    private Workbook initializeWorkbook(final ExtensionFileType type) {
        if (PredicateFactory.isExtensionFileDefault.test(type)) {
            return new HSSFWorkbook();
        } else {
            return new XSSFWorkbook();
        }
    }

    /**
     * Initialize Workbook from FileInputStream.
     * 
     * @param inputStream
     *            the file input stream
     * @param type
     *            the {@link ExtensionFileType} of workbook
     * @return the {@link Workbook} created
     * @throws WorkbookException
     */
    private Workbook initializeWorkbook(final FileInputStream inputStream, final ExtensionFileType type)
            throws WorkbookException {
        try {
            if (PredicateFactory.isExtensionFileDefault.test(type)) {
                return new HSSFWorkbook(inputStream);
            } else {
                return new XSSFWorkbook(inputStream);
            }
        } catch (IOException e) {
            throw new WorkbookException(e.getMessage(), e);
        }
    }

    /**
     * Initialize Workbook from byte[].
     * 
     * @param byteArray
     *            the array of bytes
     * @param type
     *            the {@link ExtensionFileType} of workbook
     * @return the {@link Workbook} created
     * @throws WorkbookException
     *             given when problem at the initialization of the workbook.
     */
    private Workbook initializeWorkbook(final byte[] byteArray, final ExtensionFileType type)
            throws WorkbookException {
        try {
            if (PredicateFactory.isExtensionFileDefault.test(type)) {
                return new HSSFWorkbook(new ByteArrayInputStream(byteArray));
            } else {
                return new XSSFWorkbook(new ByteArrayInputStream(byteArray));
            }
        } catch (IOException e) {
            throw new WorkbookException(e.getMessage(), e);
        }
    }

    /**
     * Initialize Sheet.
     * 
     * @param wb
     *            the {@link Workbook} to use
     * @param sheetName
     *            the name of the sheet
     * @return the {@link Sheet} created
     * @throws SheetException
     *             given when problem at the initialization of the sheet.
     */
    private Sheet initializeSheet(final Workbook wb, final String sheetName) throws SheetException {
        Sheet s = null;
        try {
            s = wb.createSheet(sheetName);
        } catch (Exception e) {
            throw new SheetException(ExceptionMessage.SHEET_CREATION_SHEET.getMessage(), e);
        }
        return s;
    }

    /**
     * Validate if the nested header configuration is valid.
     * 
     * @param isPH
     *            true if propagation is HORIZONTAL otherwise false to
     *            propagation VERTICAL
     * @param annotation
     *            the {@link XlsNestedHeader} annotation
     * @throws ConfigurationException
     *             given when conflict between NestedHeader and propagation
     *             type.
     */
    private void isValidNestedHeaderConfiguration(final boolean isPH, final XlsNestedHeader annotation)
            throws ConfigurationException {

        if (isPH && PredicateFactory.isNestedHeaderIdenticalHorizontalConfiguration.test(annotation)) {
            throw new ConfigurationException(ExceptionMessage.CONFIGURATION_CONFLICT_NESTED_HEADER.getMessage());

        } else if (!isPH && PredicateFactory.isNestedHeaderIdenticalVerticalConfiguration.test(annotation)) {
            throw new ConfigurationException(ExceptionMessage.CONFIGURATION_CONFLICT_NESTED_HEADER.getMessage());
        }
    }

    /**
     * Apply merge region if necessary.
     * 
     * @param configCriteria
     *            the {@link XConfigCriteria}
     * @param r
     *            the {@link Row}
     * @param idxR
     *            the position of the row
     * @param idxC
     *            the position of the cell
     * @param isPH
     *            true if propagation horizontally, false if propagation
     *            vertically
     * @throws ConfigurationException
     *             given when problem at the applying the merge region.
     */
    private void applyMergeRegion(final XConfigCriteria configCriteria, Row r, final int idxR, final int idxC,
            final boolean isPH) throws ConfigurationException {
        /* Process @XlsNestedHeader */
        if (PredicateFactory.isFieldAnnotationXlsNestedHeaderPresent.test(configCriteria.getField())) {
            XlsNestedHeader annotation = (XlsNestedHeader) configCriteria.getField()
                    .getAnnotation(XlsNestedHeader.class);

            /* validation of configuration */
            isValidNestedHeaderConfiguration(isPH, annotation);

            /* if row null is necessary to create it */
            Row row = r;
            if (row == null) {
                /* check if the row already exist */
                row = configCriteria.getSheet().getRow(idxR);
                if (row == null) {
                    /* create a new row */
                    row = initializeRow(configCriteria.getSheet(), idxR);
                }
            }

            /* prepare position rows / cells */
            int startRow;
            int endRow;
            int startCell;
            int endCell;
            if (isPH) {
                startRow = endRow = idxR;
                startCell = idxC + annotation.startX();
                endCell = idxC + annotation.endX();
            } else {
                startRow = idxR + annotation.startY();
                endRow = idxR + annotation.endY();
                startCell = endCell = idxC;
            }

            /* initialize nested header cell */
            CellStyleHandler.initializeHeaderCell(configCriteria.getStylesMap(), row, startCell,
                    annotation.title());

            /* merge region of the nested header cell */
            CellRangeAddress range = new CellRangeAddress(startRow, endRow, startCell, endCell);
            configCriteria.getSheet().addMergedRegion(range);

            /* apply the border to the nested header cell */
            applyBorderToRegion(configCriteria, range);
        }
    }

    /**
     * Apply the border to region according the {@link CellStyle}
     * 
     * @param configCriteria
     *            the {@link XConfigCriteria}
     * @param range
     *            the {@link CellRangeAddress}
     */
    private void applyBorderToRegion(final XConfigCriteria configCriteria, CellRangeAddress range) {
        RegionUtil.setBorderBottom(
                configCriteria.getStylesMap().get(CellStyleHandler.CELL_DECORATOR_HEADER).getBorderBottom(), range,
                configCriteria.getSheet(), configCriteria.getWorkbook());

        RegionUtil.setBorderTop(
                configCriteria.getStylesMap().get(CellStyleHandler.CELL_DECORATOR_HEADER).getBorderTop(), range,
                configCriteria.getSheet(), configCriteria.getWorkbook());

        RegionUtil.setBorderLeft(
                configCriteria.getStylesMap().get(CellStyleHandler.CELL_DECORATOR_HEADER).getBorderLeft(), range,
                configCriteria.getSheet(), configCriteria.getWorkbook());

        RegionUtil.setBorderRight(
                configCriteria.getStylesMap().get(CellStyleHandler.CELL_DECORATOR_HEADER).getBorderRight(), range,
                configCriteria.getSheet(), configCriteria.getWorkbook());
    }

    /**
     * Initialize an row.
     * 
     * @param s
     *            the {@link Sheet} to add the row
     * @param idxR
     *            position of the new row
     * @return the {@link Row} created
     */
    private Row initializeRow(final Sheet s, final int idxR) {
        return s.createRow(idxR);
    }

    /**
     * Initialize the cell position based at the title orientation.
     * 
     * @param positionCell
     *            the cell position defined at the element
     * @param orientation
     *            the {@link TitleOrientationType} of the element
     * @return the cell position
     */
    private int initializeHeaderCellPosition(final int positionCell, final TitleOrientationType orientation) {
        int idxCell = positionCell - 1;
        if (TitleOrientationType.LEFT == orientation) {
            idxCell -= 1;
        } else if (TitleOrientationType.RIGHT == orientation) {
            idxCell += 1;
        }
        return idxCell;
    }

    /**
     * initialize the row position based at the title orientation.
     * 
     * @param positionRow
     *            the row position defined at the element
     * @param orientation
     *            the {@link TitleOrientationType} of the element
     * @return the row position
     */
    private int initializeHeaderRowPosition(final int positionRow, final TitleOrientationType orientation) {
        int idxRow = positionRow;
        if (TitleOrientationType.TOP == orientation) {
            idxRow -= 1;
        } else if (TitleOrientationType.BOTTOM == orientation) {
            idxRow += 1;
        }
        return idxRow;
    }

    /**
     * Initialization of the cell by the field.
     * 
     * @param configCriteria
     *            the {@link XConfigCriteria}
     * @param xlsAnnotation
     *            the {@link XlsFreeElement}
     * @param o
     *            the object
     * @param field
     *            the field
     * @param idxC
     *            the position of the cell
     * @param cL
     *            the cascade level
     * @throws WorkbookException
     *             given when the object is complex.
     */
    private void initializeCellByField(final XConfigCriteria configCriteria, final XlsFreeElement xlsAnnotation,
            final Object o, final Field field, final int idxC, final int cL) throws WorkbookException {

        /* make the field accessible to recover the value */
        field.setAccessible(true);

        Class<?> fT = field.getType();

        if (configCriteria.getSheet().getRow(xlsAnnotation.row()) != null) {
            configCriteria.setRow(configCriteria.getSheet().getRow(xlsAnnotation.row()));
        } else {
            configCriteria.setRow(configCriteria.getSheet().createRow(xlsAnnotation.row()));
        }
        configCriteria.setField(field);

        // initialize Element
        configCriteria.setElement(XlsElementFactory.build(xlsAnnotation));

        boolean isAppliedObject = toExcel(configCriteria, o, fT, idxC);

        if (!isAppliedObject && !fT.isPrimitive()) {
            throw new ElementException(ExceptionMessage.ELEMENT_COMPLEX_OBJECT.getMessage());
        }

    }

    /**
     * Initialize an cell according the type of field and the PropagationType is
     * PROPAGATION_HORIZONTAL.
     * 
     * @param configCriteria
     *            the {@link XConfigCriteria}
     * @param o
     *            the object
     * @param idxR
     *            the position of the row
     * @param idxC
     *            the position of the cell
     * @param cL
     *            the cascade level
     * @return in case of the object return the number of cells created,
     *         otherwise 0
     * @throws WorkbookException
     *             given when no such element.
     */
    private int initializeCellByFieldHorizontal(final XConfigCriteria configCriteria, final Object o,
            final int idxR, final int idxC, final int cL) throws WorkbookException {

        int counter = 0;

        /* make the field accessible to recover the value */
        configCriteria.getField().setAccessible(true);

        Class<?> fT = configCriteria.getField().getType();

        if (Collection.class.isAssignableFrom(fT)) {
            try {
                // E uma lista entao ha que crear uma sheet nova
                marshallCollectionEngineT(configCriteria, (Collection<?>) configCriteria.getField().get(o), idxC,
                        fT, cL + 1);
            } catch (IllegalAccessException e) {
                throw new CustomizedRulesException(ExceptionMessage.ELEMENT_NO_SUCH_METHOD.getMessage(), e);
            }
        } else {

            boolean isAppliedObject = toExcel(configCriteria, o, fT, idxC);

            /* backup of the cell index */
            configCriteria.setLastCellIndex(idxC);

            if (!isAppliedObject && !fT.isPrimitive()) {
                try {
                    Object nO = configCriteria.getField().get(o);
                    /* manage null objects */
                    if (nO == null) {
                        nO = fT.newInstance();
                    }
                    Class<?> oC = nO.getClass();

                    counter = marshalAsPropagationHorizontal(configCriteria, nO, oC, idxR, idxC - 1, cL + 1);
                } catch (InstantiationException | IllegalAccessException e) {
                    throw new CustomizedRulesException(ExceptionMessage.ELEMENT_NO_SUCH_METHOD.getMessage(), e);
                }
            }
        }

        return counter;
    }

    /**
     * Initialize an cell according the type of field and the PropagationType is
     * PROPAGATION_VERTICAL.
     * 
     * @param configCriteria
     *            the {@link XConfigCriteria}
     * @param o
     *            the object
     * @param r
     *            the content row
     * @param idxR
     *            the position of the row
     * @param idxC
     *            the position of the cell
     * @param cL
     *            the cascade level
     * @return in case of the object return the number of cells created,
     *         otherwise 0
     * @throws WorkbookException
     *             given when the object is complex.
     */
    private int initializeCellByFieldVertical(final XConfigCriteria configCriteria, final Object o, final Row r,
            final int idxR, final int idxC, int cL) throws WorkbookException {

        int counter = 0;

        /* make the field accessible to recover the value */
        configCriteria.getField().setAccessible(true);

        Class<?> fT = configCriteria.getField().getType();

        configCriteria.setRow(r);

        if (Collection.class.isAssignableFrom(fT)) {
            Collection<?> collection = null;
            try {
                collection = (Collection<?>) configCriteria.getField().get(o);
            } catch (IllegalArgumentException | IllegalAccessException e1) {
                throw new ElementException(ExceptionMessage.ELEMENT_NULL_OBJECT.getMessage());
            }
            if (collection != null) {
                Object objectRT;
                try {
                    objectRT = collection.stream().findFirst().get();
                } catch (Exception e) {
                    throw new ElementException(ExceptionMessage.ELEMENT_NULL_OBJECT.getMessage());
                }

                /* initialize the runtime class of the object */
                Class<?> oC = initializeRuntimeClass(objectRT);

                // E uma lista entao ha que crear uma sheet nova
                marshallCollectionEngineT(configCriteria, collection, idxC, oC, cL + 1);
            }

        } else {
            boolean isAppliedObject = toExcel(configCriteria, o, fT, idxC);

            /* backup of the cell index */
            configCriteria.setLastCellIndex(idxC);

            if (!isAppliedObject && !fT.isPrimitive()) {
                try {
                    Object nO = configCriteria.getField().get(o);
                    /* manage null objects */
                    if (nO == null) {
                        nO = fT.newInstance();
                    }
                    Class<?> oC = nO.getClass();

                    counter = marshalAsPropagationVertical(configCriteria, nO, oC, idxR - 1, idxC - 1, cL + 1);
                } catch (InstantiationException | IllegalAccessException e) {
                    throw new CustomizedRulesException(ExceptionMessage.ELEMENT_NO_SUCH_METHOD.getMessage(), e);
                }
            }
        }
        return counter;
    }

    /**
     * Apply the base object to cell.
     * 
     * @param configCriteria
     *            the {@link XConfigCriteria}
     * @param o
     *            the object
     * @param fT
     *            the field type
     * @param idxC
     *            the position of the cell
     * @return false if problem otherwise true
     * @throws WorkbookException
     *             given when a not supported action.
     */
    private boolean toExcel(final XConfigCriteria configCriteria, final Object o, final Class<?> fT, final int idxC)
            throws WorkbookException {
        /* flag which define if the cell was updated or not */
        boolean isUpdated;
        /* initialize cell */
        Cell cell;

        /*
         * check if the cell to be applied the element is empty otherwise one
         * exception will be launched
         */
        if (configCriteria.getRow().getCell(idxC) != null) {
            throw new ElementException(ExceptionMessage.ELEMENT_OVERWRITE_CELL.getMessage());
        }

        if (PredicateFactory.isPropagationVertical.test(configCriteria.getPropagation())) {
            if (ExtensionFileType.XLS.equals(configCriteria.getExtension()) && idxC > 255) {
                throw new SheetException(ExceptionMessage.SHEET_INVALID_COLUMN_INDEX_XLS.getMessage());
            } else if (ExtensionFileType.XLSX.equals(configCriteria.getExtension()) && idxC > 16383) {
                throw new SheetException(ExceptionMessage.SHEET_INVALID_COLUMN_INDEX_XLSX.getMessage());
            }
        }

        switch (fT.getName()) {
        case CellHandler.OBJECT_DATE:
            cell = configCriteria.getRow().createCell(idxC);
            isUpdated = CellHandler.dateWriter(configCriteria, o, cell);
            break;

        case CellHandler.OBJECT_LOCALDATE:
            cell = configCriteria.getRow().createCell(idxC);
            isUpdated = CellHandler.localDateWriter(configCriteria, o, cell);
            break;

        case CellHandler.OBJECT_LOCALDATETIME:
            cell = configCriteria.getRow().createCell(idxC);
            isUpdated = CellHandler.localDateTimeWriter(configCriteria, o, cell);
            break;

        case CellHandler.OBJECT_STRING:
            cell = configCriteria.getRow().createCell(idxC);
            isUpdated = CellHandler.stringWriter(configCriteria, o, cell);
            break;

        case CellHandler.OBJECT_SHORT:
            /* falls through */
        case CellHandler.PRIMITIVE_SHORT:
            cell = configCriteria.getRow().createCell(idxC);
            isUpdated = CellHandler.shortWriter(configCriteria, o, cell);
            break;

        case CellHandler.OBJECT_INTEGER:
            /* falls through */
        case CellHandler.PRIMITIVE_INTEGER:
            cell = configCriteria.getRow().createCell(idxC);
            isUpdated = CellHandler.integerWriter(configCriteria, o, cell);
            break;

        case CellHandler.OBJECT_LONG:
            /* falls through */
        case CellHandler.PRIMITIVE_LONG:
            cell = configCriteria.getRow().createCell(idxC);
            isUpdated = CellHandler.longWriter(configCriteria, o, cell);
            break;

        case CellHandler.OBJECT_DOUBLE:
            /* falls through */
        case CellHandler.PRIMITIVE_DOUBLE:
            cell = configCriteria.getRow().createCell(idxC);
            isUpdated = CellHandler.doubleWriter(configCriteria, o, cell);
            break;

        case CellHandler.OBJECT_BIGDECIMAL:
            cell = configCriteria.getRow().createCell(idxC);
            isUpdated = CellHandler.bigDecimalWriter(configCriteria, o, cell);
            break;

        case CellHandler.OBJECT_FLOAT:
            /* falls through */
        case CellHandler.PRIMITIVE_FLOAT:
            cell = configCriteria.getRow().createCell(idxC);
            isUpdated = CellHandler.floatWriter(configCriteria, o, cell);
            break;

        case CellHandler.OBJECT_BOOLEAN:
            /* falls through */
        case CellHandler.PRIMITIVE_BOOLEAN:
            cell = configCriteria.getRow().createCell(idxC);
            isUpdated = CellHandler.booleanWriter(configCriteria, o, cell);
            break;

        default:
            isUpdated = false;
            break;
        }

        if (!isUpdated && fT.isEnum()) {
            cell = configCriteria.getRow().createCell(idxC);
            isUpdated = CellHandler.enumWriter(configCriteria, o, cell);
        }

        return isUpdated;
    }

    /**
     * Apply the base object from cell.
     * 
     * @param o
     *            the object
     * @param fT
     *            the field type
     * @param f
     *            the field
     * @param c
     *            the cell
     * @param xlsAnnotation
     *            the {@link XlsElement} annotation
     * @return false if problem otherwise true
     * @throws WorkbookException
     *             given when a not supported action.
     */
    private boolean toObject(final Object o, final Class<?> fT, final Field f, final Cell c,
            final XlsElement xlsAnnotation) throws WorkbookException {
        /* flag which define if the cell was updated or not */
        boolean isUpdated;

        f.setAccessible(true);

        switch (fT.getName()) {
        case CellHandler.OBJECT_DATE:
            CellHandler.dateReader(o, f, c, xlsAnnotation);
            isUpdated = true;
            break;

        case CellHandler.OBJECT_LOCALDATE:
            CellHandler.localDateReader(o, f, c, xlsAnnotation);
            isUpdated = true;
            break;

        case CellHandler.OBJECT_LOCALDATETIME:
            CellHandler.localDateTimeReader(o, f, c, xlsAnnotation);
            isUpdated = true;
            break;

        case CellHandler.OBJECT_STRING:
            CellHandler.stringReader(o, f, c);
            isUpdated = true;
            break;

        case CellHandler.OBJECT_SHORT:
            /* falls through */
        case CellHandler.PRIMITIVE_SHORT:
            CellHandler.shortReader(o, f, c);
            isUpdated = true;
            break;

        case CellHandler.OBJECT_INTEGER:
            /* falls through */
        case CellHandler.PRIMITIVE_INTEGER:
            CellHandler.integerReader(o, f, c);
            isUpdated = true;
            break;

        case CellHandler.OBJECT_LONG:
            /* falls through */
        case CellHandler.PRIMITIVE_LONG:
            CellHandler.longReader(o, f, c);
            isUpdated = true;
            break;

        case CellHandler.OBJECT_DOUBLE:
            /* falls through */
        case CellHandler.PRIMITIVE_DOUBLE:
            CellHandler.doubleReader(o, f, c, xlsAnnotation);
            isUpdated = true;
            break;

        case CellHandler.OBJECT_BIGDECIMAL:
            CellHandler.bigDecimalReader(o, f, c, xlsAnnotation);
            isUpdated = true;
            break;

        case CellHandler.OBJECT_FLOAT:
            /* falls through */
        case CellHandler.PRIMITIVE_FLOAT:
            CellHandler.floatReader(o, f, c);
            isUpdated = true;
            break;

        case CellHandler.OBJECT_BOOLEAN:
            /* falls through */
        case CellHandler.PRIMITIVE_BOOLEAN:
            CellHandler.booleanReader(o, f, c, xlsAnnotation);
            isUpdated = true;
            break;

        default:
            isUpdated = false;
            break;
        }

        if (!isUpdated && fT.isEnum()) {
            CellHandler.enumReader(o, fT, f, c);
            isUpdated = true;
        }

        return isUpdated;
    }

    /**
     * Process the annotation {@link XlsFreeElement}
     * 
     * @param configCriteria
     *            the {@link XConfigCriteria}
     * @param o
     *            the object
     * @param oC
     *            the object class
     * @param f
     *            the field
     * @throws WorkbookException
     *             given when a not supported action.
     */
    private void processXlsFreeElement(final XConfigCriteria configCriteria, final Object o, final int cL,
            final Field f) throws WorkbookException {

        if (PredicateFactory.isFieldAnnotationXlsFreeElementPresent.test(f)) {
            XlsFreeElement xlsAnnotation = (XlsFreeElement) f.getAnnotation(XlsFreeElement.class);

            /* validate the row/cell of the element */
            if (PredicateFactory.isXlsFreeElementInvalid.test(xlsAnnotation)) {
                throw new ElementException(ExceptionMessage.ELEMENT_INVALID_POSITION.getMessage());
            }

            /* header treatment */
            if (xlsAnnotation.showTitle()) {
                /* initialize the row position */
                int idxRow = initializeHeaderRowPosition(xlsAnnotation.row(), xlsAnnotation.titleOrientation());
                /* initialize the cell position */
                int idxCell = initializeHeaderCellPosition(xlsAnnotation.cell(), xlsAnnotation.titleOrientation());
                /* obtain/initialize the row */
                Row row = configCriteria.getSheet().getRow(idxRow);
                if (row == null) {
                    row = initializeRow(configCriteria.getSheet(), idxRow);
                }

                /*
                 * check if the cell to be applied the element is empty
                 * otherwise one exception will be launched
                 */
                if (row.getCell(idxCell) != null) {
                    throw new ElementException(ExceptionMessage.ELEMENT_OVERWRITE_CELL.getMessage());
                }

                CellStyleHandler.initializeHeaderCell(configCriteria.getStylesMap(), row, idxCell,
                        xlsAnnotation.title());
            }

            /* prepare the column width */
            if (configCriteria.getResizeActive() && xlsAnnotation.columnWidthInUnits() != 0) {
                configCriteria.getColumnWidthMap().put(xlsAnnotation.cell() - 1,
                        xlsAnnotation.columnWidthInUnits());
            }

            /* content treatment */
            initializeCellByField(configCriteria, xlsAnnotation, o, f, xlsAnnotation.cell() - 1, cL);
        }
    }

    /**
     * Prepare the propagation horizontal:
     * <ul>
     * <li>1. initialize sheet
     * <li>2. initialize header row
     * <li>3. initialize row
     * </ul>
     * 
     * @param configCriteria
     *            the {@link XConfigCriteria}
     * @return the the position of the row
     * @throws SheetException
     *             given when problem at the sheet initialization.
     */
    private int preparePropagationHorizontal(final XConfigCriteria configCriteria) throws SheetException {
        int idxRow;
        if (configCriteria.getWorkbook().getNumberOfSheets() == 0
                || configCriteria.getWorkbook().getSheet(truncateTitle(configCriteria.getTitleSheet())) == null) {
            configCriteria.setSheet(initializeSheet(configCriteria.getWorkbook(), configCriteria.getTitleSheet()));
            idxRow = configCriteria.getStartRow();
            configCriteria.setRowHeader(initializeRow(configCriteria.getSheet(), idxRow++));
            configCriteria.setRow(initializeRow(configCriteria.getSheet(), idxRow++));

        } else {
            // TOVERIFY se ha que aumentar a 5 pelo nestedheader
            idxRow = configCriteria.getElement() != null && configCriteria.getElement().parentSheet()
                    ? configCriteria.getWorkbook().getSheet(truncateTitle(configCriteria.getTitleSheet()))
                            .getLastRowNum() + 3
                    : configCriteria.getWorkbook().getSheet(truncateTitle(configCriteria.getTitleSheet()))
                            .getLastRowNum() + 1;
            // idxRow = configCriteria.getSheet().getLastRowNum() + 1;
            configCriteria.setRowHeader(null);
            configCriteria.setRow(initializeRow(
                    configCriteria.getWorkbook().getSheet(truncateTitle(configCriteria.getTitleSheet())),
                    idxRow++));

        }
        return idxRow;
    }

    /**
     * Prepare the propagation vertical:
     * <ul>
     * <li>initialize sheet
     * <li>define next cell index value
     * </ul>
     * 
     * @param configCriteria
     *            the {@link XConfigCriteria}
     * @param idxCell
     *            the cell index
     * @return the the position of the cell
     * @throws SheetException
     *             given when problem at the sheet initialization.
     */
    private int preparePropagationVertical(final XConfigCriteria configCriteria, int idxCell)
            throws SheetException {
        int indexCell = idxCell;
        if (configCriteria.getWorkbook().getNumberOfSheets() == 0
                || configCriteria.getWorkbook().getSheet(truncateTitle(configCriteria.getTitleSheet())) == null) {
            configCriteria.setSheet(initializeSheet(configCriteria.getWorkbook(), configCriteria.getTitleSheet()));
            indexCell = configCriteria.getStartCell() + 1;
        } else {
            configCriteria
                    .setSheet(configCriteria.getWorkbook().getSheet(truncateTitle(configCriteria.getTitleSheet())));
            short sh = configCriteria.getSheet().getRow(configCriteria.getStartRow() + 1).getLastCellNum();
            indexCell = sh - 1;
        }
        return indexCell;
    }

    /**
     * Convert the object to file with the PropagationType as
     * PROPAGATION_HORIZONTAL.
     * 
     * @param configCriteria
     *            the {@link XConfigCriteria}
     * @param o
     *            the object
     * @param oC
     *            the object class
     * @param idxR
     *            the position of the row
     * @param idxC
     *            the position of the cell
     * @param cL
     *            the cascade level
     * @return in case of the object return the number of cells created,
     *         otherwise 0
     * @throws WorkbookException
     *             given when a not supported action.
     * 
     */
    private int marshalAsPropagationHorizontal(final XConfigCriteria configCriteria, final Object o,
            final Class<?> oC, final int idxR, final int idxC, final int cL) throws WorkbookException {
        /* counter related to the number of fields (if new object) */
        int counter = -1;
        int indexCell = idxC;
        int elementPosition = 0;
        int rem = 0;

        /* validate cascade level */
        if (!CascadeHandler.isAuthorizedCascadeLevel(configCriteria, cL, o)) {
            return counter;
        }

        /* get declared fields */
        List<Field> fL = Arrays.asList(oC.getDeclaredFields());

        // Order by the list by position
        Collections.sort(fL, new Comparator<Field>() {
            @Override
            public int compare(Field f1, Field f2) {
                if (f2 == null) {
                    return 0;
                } else if (f1 != null && f2 != null && f1.isAnnotationPresent(XlsElement.class)
                        && f2.isAnnotationPresent(XlsElement.class)) {
                    XlsElement element1 = (XlsElement) f1.getAnnotation(XlsElement.class);
                    XlsElement element2 = (XlsElement) f2.getAnnotation(XlsElement.class);
                    return element1.position() - element2.position();
                } else {
                    return 0;
                }
            }
        });

        for (Field f : fL) {
            /* update field at ConfigCriteria */
            configCriteria.setField(f);

            /* process each field from the object */
            if (PredicateFactory.isRowValid.test(configCriteria.getRowHeader())) {
                /* calculate index of the cell */
                int tmpIdxRow = idxR - 3;
                /* apply merge region */
                applyMergeRegion(configCriteria, null, tmpIdxRow, indexCell, true);
            }

            /* validate non-conflict annotation type */
            if (PredicateFactory.isFieldAnnotationXlsElementPresent.test(f)
                    && PredicateFactory.isFieldAnnotationXlsFreeElementPresent.test(f)) {
                throw new ElementException(ExceptionMessage.ELEMENT_CONFLICT_WITH_FREEELEMENT.getMessage());
            }

            /* Process @XlsElement */
            if (PredicateFactory.isFieldAnnotationXlsElementPresent.test(f)) {
                XlsElement xlsAnnotation = (XlsElement) f.getAnnotation(XlsElement.class);

                /* validate the position of the element */
                if (PredicateFactory.isXlsElementInvalid.test(xlsAnnotation)) {
                    throw new ElementException(ExceptionMessage.ELEMENT_INVALID_POSITION.getMessage());
                }

                /* validate the propagation type & formulas */
                if (xlsAnnotation.isFormula() && StringUtils.isNotBlank(xlsAnnotation.formula())
                        && xlsAnnotation.formula().contains("idy")) {
                    throw new ElementException(ExceptionMessage.CONFIGURATION_CONFLICT_FORMULA.getMessage());
                }

                /* set position of the element */
                elementPosition = xlsAnnotation.position() == -99 ? elementPosition + 1 : xlsAnnotation.position();

                /* update annotation at ConfigCriteria */
                configCriteria.setElement(xlsAnnotation);

                /* apply customized rules defined at the object */
                if (StringUtils.isNotBlank(xlsAnnotation.customizedRules())) {
                    CellHandler.applyCustomizedRules(o, xlsAnnotation.customizedRules());
                }

                /*
                 * increment of the counter related to the number of fields (if
                 * new object)
                 */
                counter++;
                int pos = idxC + elementPosition;
                // if is a list don't generate the head
                if (configCriteria.getRowHeader() != null && !Collection.class.isAssignableFrom(f.getType())
                        && CellHandler.isAuthorizedType(f)) {
                    pos = pos - rem;
                    /* header treatment */
                    CellStyleHandler.initializeHeaderCell(configCriteria.getStylesMap(),
                            configCriteria.getRowHeader(), indexCell + elementPosition, xlsAnnotation.title());
                    rem = 0;
                } else {
                    //
                    rem = rem + 1;
                }
                /* prepare the column width */
                if (configCriteria.getResizeActive() && xlsAnnotation.columnWidthInUnits() != 0) {
                    configCriteria.getColumnWidthMap().put(indexCell + elementPosition,
                            xlsAnnotation.columnWidthInUnits());
                }

                /* content treatment */
                indexCell += initializeCellByFieldHorizontal(configCriteria, o, idxR, indexCell + elementPosition,
                        cL);
            }
        }

        for (Field f : fL) {
            /* update field at ConfigCriteria */
            configCriteria.setField(f);

            /* Process @XlsFreeElement */
            processXlsFreeElement(configCriteria, o, cL, f);
        }

        /* disable the resize */
        configCriteria.setResizeActive(false);

        return counter;
    }

    /**
     * Convert the object to file with the PropagationType as
     * PROPAGATION_VERTICAL.
     * 
     * @param configCriteria
     *            the {@link XConfigCriteria}
     * @param o
     *            the object
     * @param oC
     *            the object class
     * @param idxR
     *            the position of the row
     * @param idxC
     *            the position of the cell
     * @param cL
     *            the cascade level
     * @return in case of the object return the number of cells created,
     *         otherwise 0
     * @throws WorkbookException
     *             given when a not supported action.
     */
    private int marshalAsPropagationVertical(final XConfigCriteria configCriteria, final Object o, Class<?> oC,
            final int idxR, final int idxC, final int cL) throws WorkbookException {
        /* counter related to the number of fields (if new object) */
        int counter = -1;
        int indexCell = idxC;
        int indexRow = idxR;
        int elementPosition = 0;
        /* backup base index of the cell */
        int baseIdxCell = indexCell;
        int rem = 0;

        /* validate cascade level */
        if (!CascadeHandler.isAuthorizedCascadeLevel(configCriteria, cL, o)) {
            return counter;
        }

        /* get declared fields */
        List<Field> fL = Arrays.asList(oC.getDeclaredFields());

        Collections.sort(fL, new Comparator<Field>() {
            @Override
            public int compare(Field f1, Field f2) {
                if (f2 == null) {
                    return 0;
                } else if (f1 != null && f2 != null && f1.isAnnotationPresent(XlsElement.class)
                        && f2.isAnnotationPresent(XlsElement.class)) {
                    XlsElement element1 = (XlsElement) f1.getAnnotation(XlsElement.class);
                    XlsElement element2 = (XlsElement) f2.getAnnotation(XlsElement.class);
                    return element1.position() - element2.position();
                } else {
                    return 0;
                }
            }
        });

        for (Field f : fL) {
            /* process each field from the object */
            configCriteria.setField(f);

            /* restart the index of the cell */
            indexCell = baseIdxCell;

            /* validate non-conflict annotation type */
            if (PredicateFactory.isFieldAnnotationXlsElementPresent.test(f)
                    && PredicateFactory.isFieldAnnotationXlsFreeElementPresent.test(f)) {
                throw new ElementException(ExceptionMessage.ELEMENT_CONFLICT_WITH_FREEELEMENT.getMessage());
            }

            /* Process @XlsElement */
            if (PredicateFactory.isFieldAnnotationXlsElementPresent.test(f)) {
                XlsElement xlsAnnotation = (XlsElement) f.getAnnotation(XlsElement.class);

                /* validate the position of the element */
                if (PredicateFactory.isXlsElementInvalid.test(xlsAnnotation)) {
                    throw new ElementException(ExceptionMessage.ELEMENT_INVALID_POSITION.getMessage());
                }

                /* validate the propagation type & formulas */
                if (xlsAnnotation.isFormula() && StringUtils.isNotBlank(xlsAnnotation.formula())
                        && xlsAnnotation.formula().contains("idx")) {
                    throw new ElementException(ExceptionMessage.CONFIGURATION_CONFLICT_FORMULA.getMessage());
                }

                /* set position of the element */
                elementPosition = xlsAnnotation.position() == -99 ? elementPosition + 1 : xlsAnnotation.position();

                /* update annotation at ConfigCriteria */
                configCriteria.setElement(xlsAnnotation);

                /* apply customized rules defined at the object */
                if (StringUtils.isNotBlank(xlsAnnotation.customizedRules())) {
                    CellHandler.applyCustomizedRules(o, xlsAnnotation.customizedRules());
                }

                /*
                 * increment of the counter related to the number of fields (if
                 * new object)
                 */
                counter++;

                /* create the row */
                Row row = configCriteria.getSheet().getRow(indexRow + elementPosition);
                if (row == null || baseIdxCell == 0 || baseIdxCell == 1) {
                    /* header treatment with nested header */
                    int tmpIdxCell = indexCell - 1;
                    /* initialize row */
                    row = initializeRow(configCriteria.getSheet(), indexRow + elementPosition);

                    /* apply merge region */
                    applyMergeRegion(configCriteria, row, indexRow, tmpIdxCell, false);

                    int pos = indexRow + elementPosition;
                    // if is a list don't generate the head
                    if (row != null && !Collection.class.isAssignableFrom(f.getType())
                            && CellHandler.isAuthorizedType(f)) {
                        pos = pos - rem;
                        /* header treatment */
                        CellStyleHandler.initializeHeaderCell(configCriteria.getStylesMap(), row, indexCell,
                                xlsAnnotation.title());
                        rem = 0;
                    } else {
                        //
                        rem = rem + 1;
                    }

                } else {
                    row = configCriteria.getSheet().getRow(indexRow + elementPosition);
                    /* header treatment without nested header */
                    // CellStyleHandler.initializeHeaderCell(configCriteria.getStylesMap(),
                    // row, indexCell,
                    // xlsAnnotation.title());
                }

                /* prepare the column width */
                if (configCriteria.getResizeActive() && xlsAnnotation.columnWidthInUnits() != 0) {
                    configCriteria.getColumnWidthMap().put(indexCell + elementPosition,
                            xlsAnnotation.columnWidthInUnits());
                }

                /* increment the cell position */
                indexCell++;
                /* content treatment */
                indexRow += initializeCellByFieldVertical(configCriteria, o, row, indexRow + elementPosition,
                        indexCell, cL);
            }
        }

        for (Field f : fL) {
            /* update field at ConfigCriteria */
            configCriteria.setField(f);

            /* Process @XlsFreeElement */
            processXlsFreeElement(configCriteria, o, cL, f);
        }

        /* disable the resize */
        configCriteria.setResizeActive(false);

        return counter;
    }

    /**
     * Convert the file to object with the PropagationType as
     * PROPAGATION_HORIZONTAL.
     * 
     * @param configCriteria
     *            the {@link XConfigCriteria}
     * @param o
     *            the object
     * @param oC
     *            the object class
     * @param idxR
     *            the position of the row
     * @param idxC
     *            the position of the cell
     * @return in case of the object return the number of cells created,
     *         otherwise 0
     * @throws WorkbookException
     *             given when a not supported action.
     */
    private int unmarshalAsPropagationHorizontal(final XConfigCriteria configCriteria, Object o, Class<?> oC,
            final int idxR, final int idxC, final int cL) throws WorkbookException {
        /* counter related to the number of fields (if new object) */
        int counter = -1;
        int indexCell = idxC;
        int elementPosition = 0;

        if (!CascadeHandler.isAuthorizedCascadeLevel(configCriteria, cL, o)) {
            return counter;
        }

        /* get declared fields */
        List<Field> fL = Arrays.asList(oC.getDeclaredFields());
        for (Field f : fL) {
            /* process each field from the object */
            Class<?> fT = f.getType();

            /* Process @XlsElement */
            if (PredicateFactory.isFieldAnnotationXlsElementPresent.test(f)) {
                XlsElement xlsAnnotation = (XlsElement) f.getAnnotation(XlsElement.class);

                /* validate the position of the element */
                if (PredicateFactory.isXlsElementInvalid.test(xlsAnnotation)) {
                    throw new ElementException(ExceptionMessage.ELEMENT_INVALID_POSITION.getMessage());
                }

                /* set position of the element */
                elementPosition = xlsAnnotation.position() == -99 ? elementPosition + 1 : xlsAnnotation.position();

                /*
                 * increment of the counter related to the number of fields (if
                 * new object)
                 */
                counter++;

                /* content row */
                // MAL - ERRO AQUI
                Row contentRow = configCriteria.getSheet().getRow(idxR + 1);
                if (contentRow != null && idxR < configCriteria.getSheet().getLastRowNum()) {
                    Cell contentCell = contentRow.getCell(indexCell + elementPosition);
                    if (contentCell != null) {
                        if (Collection.class.isAssignableFrom(fT)) {

                            try {
                                f.set(o, unmarshalTreatementToCollection(o, configCriteria));
                            } catch (IllegalArgumentException | IllegalAccessException e) {
                                throw new ElementException(ExceptionMessage.ELEMENT_COMPLEX_OBJECT.getMessage());
                            }
                        } else {
                            boolean isAppliedToBaseObject = toObject(o, fT, f, contentCell, xlsAnnotation);

                            if (!isAppliedToBaseObject && !fT.isPrimitive()) {
                                try {
                                    Object subObjbect = fT.newInstance();

                                    Class<?> subObjbectClass = subObjbect.getClass();

                                    int internalCellCounter = unmarshalAsPropagationHorizontal(configCriteria,
                                            subObjbect, subObjbectClass, idxR, indexCell + elementPosition - 1,
                                            cL + 1);

                                    /*
                                     * add the sub object to the parent object
                                     */
                                    f.set(o, subObjbect);

                                    /* update the index */
                                    indexCell += internalCellCounter;
                                } catch (InstantiationException | IllegalAccessException e) {
                                    throw new CustomizedRulesException(
                                            ExceptionMessage.ELEMENT_NO_SUCH_METHOD.getMessage(), e);

                                }
                            }
                        }

                    }
                } else {
                    counter = -5;
                    o = null;
                    break;

                }
            }

            /* Process @XlsFreeElement */
            if (PredicateFactory.isFieldAnnotationXlsFreeElementPresent.test(f)) {
                XlsFreeElement xlsFreeAnnotation = (XlsFreeElement) f.getAnnotation(XlsFreeElement.class);

                /* validate the row/cell of the element */
                if (PredicateFactory.isXlsFreeElementInvalid.test(xlsFreeAnnotation)) {
                    throw new ElementException(ExceptionMessage.ELEMENT_INVALID_POSITION.getMessage());
                }

                /* content row */
                Row contentRow = configCriteria.getSheet().getRow(xlsFreeAnnotation.row());
                Cell contentCell = contentRow.getCell(xlsFreeAnnotation.cell() - 1);

                // initialize Element
                XlsElement xlsAnnotation = XlsElementFactory.build(xlsFreeAnnotation);

                boolean isAppliedToBaseObject = toObject(o, fT, f, contentCell, xlsAnnotation);

                if (!isAppliedToBaseObject && !fT.isPrimitive()) {
                    throw new ElementException(ExceptionMessage.ELEMENT_COMPLEX_OBJECT.getMessage());
                }
            }
        }
        return counter;
    }

    /**
     * Convert the file to object with the PropagationType as
     * PROPAGATION_VERTICAL.
     * 
     * @param configCriteria
     *            the {@link XConfigCriteria}
     * @param o
     *            the object
     * @param oC
     *            the object class
     * @param idxR
     *            the position of the row
     * @param idxC
     *            the position of the cell
     * @return in case of the object return the number of cells created,
     *         otherwise 0
     * @throws WorkbookException
     *             given when a not supported action.
     */
    private int unmarshalAsPropagationVertical(final XConfigCriteria configCriteria, Object o, Class<?> oC,
            final int idxR, final int idxC, final int cL) throws WorkbookException {
        /* counter related to the number of fields (if new object) */
        int counter = -1;
        int indexRow = idxR;
        int elementPosition = idxR;

        if (!CascadeHandler.isAuthorizedCascadeLevel(configCriteria, cL, o)) {
            return counter;
        }

        /* get declared fields */
        List<Field> fL = Arrays.asList(oC.getDeclaredFields());
        for (Field f : fL) {
            /* process each field from the object */
            Class<?> fT = f.getType();

            /* Process @XlsElement */
            if (PredicateFactory.isFieldAnnotationXlsElementPresent.test(f)) {
                XlsElement xlsAnnotation = (XlsElement) f.getAnnotation(XlsElement.class);

                /* validate the position of the element */
                if (PredicateFactory.isXlsElementInvalid.test(xlsAnnotation)) {
                    throw new ElementException(ExceptionMessage.ELEMENT_INVALID_POSITION.getMessage());
                }

                /* set position of the element */
                elementPosition = xlsAnnotation.position() == -99 ? elementPosition + 1 : xlsAnnotation.position();

                /*
                 * increment of the counter related to the number of fields (if
                 * new object)
                 */
                counter++;

                /* content row */
                Row contentRow = configCriteria.getSheet().getRow(indexRow + elementPosition);
                Cell contentCell = contentRow.getCell(idxC + 2);
                if (contentCell != null) {
                    if (Collection.class.isAssignableFrom(fT)) {

                        // E uma lista entao ha que crear uma sheet nova
                        try {
                            f.set(o, unmarshalTreatementToCollection(o, configCriteria));
                        } catch (IllegalArgumentException | IllegalAccessException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    } else {
                        boolean isAppliedToBaseObject = toObject(o, fT, f, contentCell, xlsAnnotation);

                        if (!isAppliedToBaseObject && !fT.isPrimitive()) {

                            try {
                                Object subObjbect = fT.newInstance();

                                Class<?> subObjbectClass = subObjbect.getClass();

                                int internalCellCounter = unmarshalAsPropagationVertical(configCriteria, subObjbect,
                                        subObjbectClass, indexRow + elementPosition - 1, idxC, cL + 1);

                                /* add the sub object to the parent object */
                                f.set(o, subObjbect);

                                /* update the index */
                                indexRow += internalCellCounter;
                            } catch (InstantiationException | IllegalAccessException e) {
                                throw new CustomizedRulesException(
                                        ExceptionMessage.ELEMENT_NO_SUCH_METHOD.getMessage(), e);
                            }
                        }
                    }
                } else {
                    o = null;
                    counter = -5;
                    break;
                }
            }

            /* Process @XlsFreeElement */
            if (PredicateFactory.isFieldAnnotationXlsFreeElementPresent.test(f)) {
                XlsFreeElement xlsFreeAnnotation = (XlsFreeElement) f.getAnnotation(XlsFreeElement.class);

                /* validate the row/cell of the element */
                if (PredicateFactory.isXlsFreeElementInvalid.test(xlsFreeAnnotation)) {
                    throw new ElementException(ExceptionMessage.ELEMENT_INVALID_POSITION.getMessage());
                }

                /* content row */
                Row contentRow = configCriteria.getSheet().getRow(xlsFreeAnnotation.row());
                Cell contentCell = contentRow.getCell(xlsFreeAnnotation.cell() - 1);

                // initialize Element
                XlsElement xlsAnnotation = XlsElementFactory.build(xlsFreeAnnotation);

                boolean isAppliedToBaseObject = toObject(o, fT, f, contentCell, xlsAnnotation);

                if (!isAppliedToBaseObject && !fT.isPrimitive()) {
                    throw new ElementException(ExceptionMessage.ELEMENT_COMPLEX_OBJECT.getMessage());
                }
            }
        }
        return counter;
    }

    /**
     * Generate file output stream.
     * 
     * @param wb
     *            the {@link Workbook}
     * @param name
     *            the name
     * @return the {@link FileOutputStream} generated
     * @throws WorkbookException
     *             given when problem at the generation of the FileOutputStream.
     */
    private FileOutputStream workbookFileOutputStream(final Workbook wb, final String name)
            throws WorkbookException {
        FileOutputStream output = null;
        try {
            output = new FileOutputStream(name);
            wb.write(output);
            output.close();
        } catch (IOException e) {
            throw new WorkbookException(e.getMessage(), e);
        }
        return output;
    }

    /**
     * Generate the byte array.
     * 
     * @param wb
     *            the {@link Workbook}
     * @return the byte[]
     * @throws WorkbookException
     *             given when problem at the generation of the byte[].
     */
    private byte[] workbookToByteAray(final Workbook wb) throws WorkbookException {
        ByteArrayOutputStream bos = null;
        try {
            bos = new ByteArrayOutputStream();

            wb.write(bos);
            bos.close();
        } catch (IOException e) {
            throw new WorkbookException(e.getMessage(), e);
        }
        return bos.toByteArray();
    }

    /* ######################## engine methods ########################## */

    /**
     * Generate the workbook based at the {@link XConfigCriteria} and the object
     * passed as parameters.
     * 
     * @param configCriteria
     *            the {@link XConfigCriteria} to use.
     * @param object
     *            the object to apply at the workbook.
     * @throws WorkbookException
     *             given when a not supported action.
     */
    private void marshalEngine(final XConfigCriteria configCriteria, final Object object) throws WorkbookException {

        if (object == null) {
            throw new ElementException(ExceptionMessage.ELEMENT_NULL_OBJECT.getMessage());
        }

        /* initialize the runtime class of the object */
        Class<?> oC = initializeRuntimeClass(object);

        /* initialize configuration data */
        initializeConfigurationData(configCriteria, oC, false, true);

        /* initialize Workbook */
        configCriteria.setWorkbook(initializeWorkbook(configCriteria.getExtension()));

        /* initialize style cell via annotations */
        initializeCellStyleViaAnnotation(oC, configCriteria);

        /* initialize style cell via default option */
        configCriteria.initializeCellDecorator();

        /* initialize Sheet */
        configCriteria.setSheet(initializeSheet(configCriteria.getWorkbook(), configCriteria.getTitleSheet()));

        /* initialize Row & Cell */
        int idxRow = configCriteria.getStartRow();
        int idxCell = configCriteria.getStartCell();

        /* initialize rows according the PropagationType */
        if (PredicateFactory.isPropagationHorizontal.test(configCriteria.getPropagation())) {
            configCriteria.setRowHeader(initializeRow(configCriteria.getSheet(), idxRow++));
            configCriteria.setRow(initializeRow(configCriteria.getSheet(), idxRow++));
            marshalAsPropagationHorizontal(configCriteria, object, oC, idxRow, idxCell, 0);

        } else {
            // FiXME
            idxCell = configCriteria.getStartCell() + 1;
            marshalAsPropagationVertical(configCriteria, object, oC, idxRow, idxCell, 0);

        }

        /* apply the freeze pane */
        SheetFreezePaneHandler.applyFreezePane(configCriteria);

        /* apply the elements as group */
        SheetGroupElementHandler.applyGroupElements(configCriteria);

        if (PredicateFactory.isFieldAnnotationXlsConditionalFormatPresent.test(oC)) {
            XlsConditionalFormat xlsAnnotation = (XlsConditionalFormat) oC
                    .getAnnotation(XlsConditionalFormat.class);
            ConditionalFormattingHandler.applyCondition(configCriteria, xlsAnnotation);
        }

        /* apply background color to sheet tab */
        SheetStyleHandler.applyTabColor(configCriteria);

        /* apply column auto resize to sheet */
        SheetStyleHandler.applyAutoResizeColumn(configCriteria);

        /* apply the column resize */
        configCriteria.applyColumnWidthToSheet();

        /* re-evaluate formulas with POI's FormulaEvaluator */
        configCriteria.getWorkbook().getCreationHelper().createFormulaEvaluator().evaluateAll();
    }

    /**
     * Extract from the workbook based at the {@link XConfigCriteria} and the
     * object passed as parameters.
     * 
     * @param configCriteria
     *            the {@link XConfigCriteria} to use.
     * @param object
     *            the object to apply at the workbook.
     * @param oC
     *            the object class
     * @throws WorkbookException
     *             given when a not supported action.
     */
    private void unmarshalEngine(final XConfigCriteria configCriteria, final Object object, final Class<?> oC)
            throws WorkbookException {

        /* initialize sheet */
        if (StringUtils.isBlank(configCriteria.getTitleSheet())) {
            throw new SheetException(ExceptionMessage.SHEET_CREATION_SHEET.getMessage());
        }
        configCriteria.setSheet(configCriteria.getWorkbook().getSheet(configCriteria.getTitleSheet()));

        /* initialize index row & cell */
        int idxRow = configCriteria.getStartRow();
        int idxCell = configCriteria.getStartCell();

        if (PredicateFactory.isPropagationHorizontal.test(configCriteria.getPropagation())) {
            unmarshalAsPropagationHorizontal(configCriteria, object, oC, idxRow, idxCell, 0);
        } else {
            unmarshalAsPropagationVertical(configCriteria, object, oC, idxRow, idxCell, 0);
        }
    }

    /**
     * Generate the workbook based at the {@link XConfigCriteria} and the object
     * passed as parameters.
     * 
     * 
     * @param configCriteria
     *            the {@link XConfigCriteria} to use.
     * @param listObject
     *            the collection of objects to apply at the workbook.
     * @param insideCollection
     * @throws WorkbookException
     *             given when a not supported action.
     */
    private void marshalCollectionEngine(final XConfigCriteria configCriteria, final Collection<?> listObject,
            final boolean insideCollection) throws WorkbookException {
        int idxCell = 0;
        if (listObject == null || listObject.isEmpty()) {
            throw new ElementException(ExceptionMessage.ELEMENT_NULL_OBJECT.getMessage());
        }
        Object objectRT;
        try {
            objectRT = listObject.stream().findFirst().get();
        } catch (Exception e) {
            throw new ElementException(ExceptionMessage.ELEMENT_NULL_OBJECT.getMessage(), e);
        }

        /* initialize the runtime class of the object */
        Class<?> oC = initializeRuntimeClass(objectRT);

        /* initialize configuration data */
        initializeConfigurationData(configCriteria, oC, insideCollection, true);

        // initialize Workbook
        configCriteria.setWorkbook(initializeWorkbook(configCriteria.getExtension()));

        // initialize style cell via annotation
        initializeCellStyleViaAnnotation(oC, configCriteria);

        // initialize style cell via default option
        configCriteria.initializeCellDecorator();

        marshallCollectionEngineT(configCriteria, listObject, idxCell, oC, 0);

        if (PredicateFactory.isFieldAnnotationXlsConditionalFormatPresent.test(oC)) {
            XlsConditionalFormat xlsAnnotation = (XlsConditionalFormat) oC
                    .getAnnotation(XlsConditionalFormat.class);
            ConditionalFormattingHandler.applyCondition(configCriteria, xlsAnnotation);
        }

        /* apply background color to sheet tab */
        SheetStyleHandler.applyTabColor(configCriteria);

        /* apply column auto resize to sheet */
        SheetStyleHandler.applyAutoResizeColumn(configCriteria);

    }

    private void marshallCollectionEngineT(final XConfigCriteria configCriteria, final Collection<?> listObject,
            int idxCell, Class<?> oC, int cL) throws WorkbookException {

        if (!CascadeHandler.isAuthorizedCascadeLevel(configCriteria, cL, listObject)) {
            return;
        }

        int idxRow;
        int indexCellCalculated = idxCell;
        @SuppressWarnings("rawtypes")
        Iterator iterator = listObject.iterator();
        while (iterator.hasNext()) {
            Object object = iterator.next();

            /* initialize configuration data */
            initializeConfigurationData(configCriteria, object.getClass(), false, false);

            // initialize rows according the PropagationType
            if (PropagationType.PROPAGATION_HORIZONTAL.equals(configCriteria.getPropagation())) {
                indexCellCalculated = configCriteria.getStartCell();
                idxRow = preparePropagationHorizontal(configCriteria);

                marshalAsPropagationHorizontal(configCriteria, object, object.getClass(), idxRow,
                        indexCellCalculated, cL + 1);

            } else {
                // parentsheet para fazer
                indexCellCalculated = preparePropagationVertical(configCriteria, indexCellCalculated);
                idxRow = configCriteria.getStartRow();

                marshalAsPropagationVertical(configCriteria, object, oC, idxRow, indexCellCalculated, cL + 1);
            }

        }
        /* apply the column resize */
        configCriteria.applyColumnWidthToSheet();
    }

    /* ######################## Marshal methods ########################## */

    /**
     * Generate the sheet based at the object passed as parameter and return the
     * sheet generated.
     * 
     * @param object
     *            the object to apply at the workbook.
     * @return the {@link Sheet} generated
     * @throws WorkbookException
     *             given when a not supported action.
     */
    @Override
    public Collection<Sheet> marshalToSheet(final Object object) throws WorkbookException {
        /* Initialize a basic ConfigCriteria */
        XConfigCriteria configCriteria = new XConfigCriteria();

        /* Generate the workbook based at the object passed as parameter */
        marshalEngine(configCriteria, object);

        /* Return the collection of Sheet generated */
        List<Sheet> collection = new ArrayList<>();
        if (configCriteria.getWorkbook().getNumberOfSheets() > 0) {
            for (int i = 0; i < configCriteria.getWorkbook().getNumberOfSheets(); i++)
                collection.add(configCriteria.getWorkbook().getSheetAt(i));
        } else {
            return Collections.emptyList();
        }
        return collection;
    }

    /**
     * Generate the sheet based at the {@link XConfigCriteria} and the object
     * passed as parameters and return the sheet generated.
     * 
     * @param configCriteria
     *            the {@link XConfigCriteria} to use
     * @param object
     *            the object to apply at the workbook.
     * @return the {@link Sheet} generated
     * @throws WorkbookException
     *             given when a not supported action.
     */
    @Override
    public Collection<Sheet> marshalToSheet(final XConfigCriteria configCriteria, final Object object)
            throws WorkbookException {
        /* Generate the workbook based at the object passed as parameter */
        marshalEngine(configCriteria, object);

        /* Return the collection of Sheet generated */
        List<Sheet> collection = new ArrayList<>();
        if (configCriteria.getWorkbook().getNumberOfSheets() > 0) {
            for (int i = 0; i < configCriteria.getWorkbook().getNumberOfSheets(); i++)
                collection.add(configCriteria.getWorkbook().getSheetAt(i));
        } else {
            return Collections.emptyList();
        }
        return collection;
    }

    /**
     * Generate the workbook based at the object passed as parameter and return
     * the workbook generated.
     * 
     * @param object
     *            the object to apply at the workbook.
     * @return the {@link Workbook} generated
     * @throws WorkbookException
     *             given when a not supported action.
     */
    @Override
    public Workbook marshalToWorkbook(final Object object) throws WorkbookException {
        /* Initialize a basic ConfigCriteria */
        XConfigCriteria configCriteria = new XConfigCriteria();

        /* Generate the workbook based at the object passed as parameter */
        marshalEngine(configCriteria, object);

        /* Return the Workbook generated */
        return configCriteria.getWorkbook();
    }

    /**
     * Generate the workbook based at the {@link XConfigCriteria} and the object
     * passed as parameters and return the workbook generated.
     * 
     * @param configCriteria
     *            the {@link XConfigCriteria} to use
     * @param object
     *            the object to apply at the workbook.
     * @return the {@link Workbook} generated
     * @throws WorkbookException
     *             given when a not supported action.
     */
    @Override
    public Workbook marshalToWorkbook(final XConfigCriteria configCriteria, final Object object)
            throws WorkbookException {
        /* Generate the workbook from the object passed as parameter */
        marshalEngine(configCriteria, object);

        /* Return the Workbook generated */
        return configCriteria.getWorkbook();
    }

    /**
     * Generate the workbook based at the object passed as parameter and return
     * the byte[] generated.
     * 
     * @param object
     *            the object to apply at the workbook.
     * @return the {@link Workbook} generated
     * @throws WorkbookException
     *             given when a not supported action.
     */
    @Override
    public byte[] marshalToByte(final Object object) throws WorkbookException {
        /* Initialize a basic ConfigCriteria */
        XConfigCriteria configCriteria = new XConfigCriteria();

        /* Generate the workbook from the object passed as parameter */
        marshalEngine(configCriteria, object);

        /* Generate the byte array to return */
        return workbookToByteAray(configCriteria.getWorkbook());
    }

    /**
     * Generate the workbook based at the {@link XConfigCriteria} and the object
     * passed as parameter and return the byte[] generated.
     * 
     * @param configCriteria
     *            the {@link XConfigCriteria} to use
     * @param object
     *            the object to apply at the workbook.
     * @return the {@link Workbook} generated
     * @throws WorkbookException
     *             given when a not supported action.
     */
    @Override
    public byte[] marshalToByte(final XConfigCriteria configCriteria, final Object object)
            throws WorkbookException {
        /* Generate the workbook from the object passed as parameter */
        marshalEngine(configCriteria, object);

        /* Generate the byte array to return */
        return workbookToByteAray(configCriteria.getWorkbook());
    }

    /**
     * Generate the workbook based at the object passed as parameters and save
     * it at the path send as parameter.
     * 
     * @param object
     *            the object to apply at the workbook.
     * @param pathFile
     *            the file path where will be the file saved
     * @throws WorkbookException
     *             given when a not supported action.
     */
    @Override
    public void marshalAndSave(final Object object, final String pathFile) throws WorkbookException {
        /* Generate the workbook from the object passed as parameter */
        XConfigCriteria configCriteria = new XConfigCriteria();

        marshalAndSave(configCriteria, object, pathFile);
    }

    /**
     * Generate the workbook based at the {@link XConfigCriteria} and the object
     * passed as parameters and save it at the path send as parameter.
     * 
     * @param configCriteria
     *            the {@link XConfigCriteria} to use
     * @param object
     *            the object to apply at the workbook.
     * @param pathFile
     *            the file path where will be the file saved
     * @throws WorkbookException
     *             given when a not supported action.
     */
    @Override
    public void marshalAndSave(final XConfigCriteria configCriteria, final Object object, final String pathFile)
            throws WorkbookException {
        /* Generate the workbook from the object passed as parameter */
        marshalEngine(configCriteria, object);

        /*
         * check if the path terminate with the file separator, otherwise will
         * be added to avoid any problem
         */
        String internalPathFile = pathFile;
        if (!pathFile.endsWith(File.separator)) {
            internalPathFile = pathFile.concat(File.separator);
        }

        /* Save the Workbook at a specified path (received as parameter) */
        workbookFileOutputStream(configCriteria.getWorkbook(),
                internalPathFile + configCriteria.getCompleteFileName());
    }

    /**
     * Generate the sheet based at the collection of objects passed as parameter
     * and return the sheet generated.
     * 
     * @param listObject
     *            the collection to apply at the workbook.
     * @return the {@link Sheet} generated
     * @throws WorkbookException
     *             given when a not supported action.
     */
    @Override
    public Sheet marshalCollectionToSheet(final Collection<?> listObject) throws WorkbookException {
        /* Initialize a basic ConfigCriteria */
        XConfigCriteria configCriteria = new XConfigCriteria();

        /*
         * Generate the workbook based at the list of objects passed as
         * parameter
         */
        marshalCollectionEngine(configCriteria, listObject, false);

        /* Return the Sheet generated */
        return configCriteria.getWorkbook().getSheetAt(0);
    }

    /**
     * Generate the sheet based at the {@link XConfigCriteria} and the
     * collection of objects passed as parameters and return the sheet
     * generated.
     * 
     * @param configCriteria
     *            the {@link XConfigCriteria} to use
     * @param listObject
     *            the collection to apply at the workbook.
     * @return the {@link Sheet} generated
     * @throws WorkbookException
     *             given when a not supported action.
     */
    @Override
    public Sheet marshalCollectionToSheet(final XConfigCriteria configCriteria, final Collection<?> listObject)
            throws WorkbookException {
        /*
         * Generate the workbook based at the list of objects passed as
         * parameter
         */
        marshalCollectionEngine(configCriteria, listObject, false);

        /* Return the Sheet generated */
        return configCriteria.getWorkbook().getSheetAt(0);
    }

    /**
     * Generate the workbook based at the collection of objects passed as
     * parameter and return the workbook generated.
     * 
     * @param listObject
     *            the collection to apply at the workbook.
     * @return the {@link Workbook} generated
     * @throws WorkbookException
     *             given when a not supported action.
     */
    @Override
    public Workbook marshalCollectionToWorkbook(final Collection<?> listObject) throws WorkbookException {
        /* Initialize a basic ConfigCriteria */
        XConfigCriteria configCriteria = new XConfigCriteria();

        /* Generate the workbook based at the object passed as parameter */
        marshalCollectionEngine(configCriteria, listObject, false);

        /* Return the Workbook generated */
        return configCriteria.getWorkbook();
    }

    /**
     * Generate the workbook based at the {@link XConfigCriteria} and the
     * collection of objects passed as parameters and return the workbook
     * generated.
     * 
     * @param configCriteria
     *            the {@link XConfigCriteria} to use
     * @param listObject
     *            the collection to apply at the workbook.
     * @return the {@link Workbook} generated
     * @throws WorkbookException
     *             given when a not supported action.
     */
    @Override
    public Workbook marshalCollectionToWorkbook(final XConfigCriteria configCriteria,
            final Collection<?> listObject) throws WorkbookException {
        /* Generate the workbook from the object passed as parameter */
        marshalCollectionEngine(configCriteria, listObject, false);

        /* Return the Workbook generated */
        return configCriteria.getWorkbook();
    }

    /**
     * Generate the workbook based at the collection of objects passed as
     * parameter and save it at the path send as parameter.
     * 
     * @param listObject
     *            the collection to apply at the workbook.
     * @param pathFile
     *            the file path where will be the file saved
     * @throws WorkbookException
     *             given when a not supported action.
     */
    @Override
    public void marshalAsCollectionAndSave(final Collection<?> listObject, final String pathFile)
            throws WorkbookException {

        /* Initialize a basic ConfigCriteria */
        XConfigCriteria configCriteria = new XConfigCriteria();

        marshalAsCollectionAndSave(configCriteria, listObject, pathFile);
    }

    /**
     * Generate the workbook based at the {@link XConfigCriteria} and the
     * collection of objects passed as parameter and save it at the path send as
     * parameter.
     * 
     * @param configCriteria
     *            the {@link XConfigCriteria} to use
     * @param listObject
     *            the collection to apply at the workbook.
     * @param pathFile
     *            the file path where will be the file saved
     * @throws WorkbookException
     *             given when a not supported action.
     */
    @Override
    public void marshalAsCollectionAndSave(final XConfigCriteria configCriteria, final Collection<?> listObject,
            final String pathFile) throws WorkbookException {
        /* Generate the workbook from the object passed as parameter */
        marshalCollectionEngine(configCriteria, listObject, false);

        /*
         * check if the path terminate with the file separator, otherwise will
         * be added to avoid any problem
         */
        String internalPathFile = pathFile;
        if (!pathFile.endsWith(File.separator)) {
            internalPathFile = pathFile.concat(File.separator);
        }

        /* save the Workbook at a specified path (received as parameter) */
        workbookFileOutputStream(configCriteria.getWorkbook(),
                internalPathFile + configCriteria.getCompleteFileName());

    }

    /**
     * Generate the workbook based at the collection of objects and return the
     * byte[] generated.
     * 
     * @param listObject
     *            the collection to apply at the workbook.
     * @return the byte[] generated
     * @throws WorkbookException
     *             given when a not supported action.
     */
    @Override
    public byte[] marshalCollectionToByte(final Collection<?> listObject) throws WorkbookException {
        /* Initialize a basic ConfigCriteria */
        XConfigCriteria configCriteria = new XConfigCriteria();

        /* Generate the workbook from the object passed as parameter */
        marshalCollectionEngine(configCriteria, listObject, false);

        /* Generate the byte array to return */
        return workbookToByteAray(configCriteria.getWorkbook());
    }

    /**
     * Generate the workbook based at the {@link XConfigCriteria} and the
     * collection of objects and return the byte[] generated.
     * 
     * @param listObject
     *            the collection to apply at the workbook.
     * @return the byte[] generated
     * @throws WorkbookException
     *             given when a not supported action.
     */
    @Override
    public byte[] marshalCollectionToByte(final XConfigCriteria configCriteria, final Collection<?> listObject)
            throws WorkbookException {
        /* Generate the workbook from the object passed as parameter */
        marshalCollectionEngine(configCriteria, listObject, false);

        /* Generate the byte array to return */
        return workbookToByteAray(configCriteria.getWorkbook());
    }

    /* ######################## Unmarshal methods ######################## */

    /**
     * Generate the object from the workbook passed as parameter.
     * 
     * @param object
     *            the object to fill up.
     * @param workbook
     *            the {@link Workbook} to read and pass the information to the
     *            object
     * @throws WorkbookException
     *             given when a not supported action.
     */
    @Override
    public void unmarshalFromWorkbook(final Object object, final Workbook workbook) throws WorkbookException {
        /* initialize the runtime class of the object */
        Class<?> oC = initializeRuntimeClass(object);

        /* initialize configuration data */
        XConfigCriteria configCriteria = new XConfigCriteria();
        initializeConfigurationData(configCriteria, oC, false, true);

        /* set workbook */
        configCriteria.setWorkbook(workbook);

        /* Extract from the workbook to the object passed as parameter */
        unmarshalEngine(configCriteria, object, oC);
    }

    /**
     * Generate the object from the path file passed as parameter.
     * 
     * @param object
     *            the object to fill up.
     * @param pathFile
     *            the path where is found the file to read and pass the
     *            information to the object
     * @throws WorkbookException
     *             given when a not supported action.
     */
    @Override
    public void unmarshalFromPath(final Object object, final String pathFile) throws WorkbookException {
        /* initialize the runtime class of the object */
        Class<?> oC = initializeRuntimeClass(object);

        /* initialize configuration data */
        XConfigCriteria configCriteria = new XConfigCriteria();
        initializeConfigurationData(configCriteria, oC, false, true);

        /*
         * check if the path terminate with the file separator, otherwise will
         * be added to avoid any problem
         */
        String internalPathFile = pathFile;
        if (!pathFile.endsWith(File.separator)) {
            internalPathFile = pathFile.concat(File.separator);
        }

        try {
            FileInputStream input = new FileInputStream(internalPathFile + configCriteria.getCompleteFileName());

            /* set workbook */
            configCriteria.setWorkbook(initializeWorkbook(input, configCriteria.getExtension()));

            /* Extract from the workbook to the object passed as parameter */
            unmarshalEngine(configCriteria, object, oC);

            input.close();
        } catch (IOException e) {
            throw new WorkbookException(e.getMessage(), e);
        }
    }

    /**
     * Generate the object from the byte array passed as parameter.
     * 
     * @param object
     *            the object to fill up.
     * @param byteArray
     *            the byte[] to read and pass the information to the object
     * @throws WorkbookException
     *             given when a not supported action.
     */
    @Override
    public void unmarshalFromByte(final Object object, final byte[] byteArray) throws WorkbookException {
        /* initialize the runtime class of the object */
        Class<?> oC = initializeRuntimeClass(object);

        /* initialize configuration data */
        XConfigCriteria configCriteria = new XConfigCriteria();
        initializeConfigurationData(configCriteria, oC, false, true);

        /* set workbook */
        configCriteria.setWorkbook(initializeWorkbook(byteArray, configCriteria.getExtension()));

        /* Extract from the workbook to the object passed as parameter */
        unmarshalEngine(configCriteria, object, oC);
    }

    @Override
    public Collection<?> unmarshalToCollection(final XConfigCriteria configCriteria, final Object object,
            String excelFilePath) throws WorkbookException {
        // FileInputStream inputStream = new FileInputStream(new
        // File(excelFilePath));

        /* initialize configuration data */
        initializeConfigurationData(configCriteria, object.getClass(), false, true);

        /*
         * check if the path terminate with the file separator, otherwise will
         * be added to avoid any problem
         */
        String internalPathFile = excelFilePath;
        if (!excelFilePath.endsWith(File.separator)) {
            internalPathFile = excelFilePath.concat(File.separator);
        }

        Collection<Object> collection = null;
        try {
            FileInputStream input = new FileInputStream(internalPathFile + configCriteria.getCompleteFileName());

            /* set workbook */
            configCriteria.setWorkbook(initializeWorkbook(input, configCriteria.getExtension()));

            collection = unmarshalTreatementToCollection(object, configCriteria);
        } catch (IOException e) {
            throw new WorkbookException(e.getMessage(), e);
        }
        return collection;
    }

    private Collection<Object> unmarshalTreatementToCollection(Object object, XConfigCriteria configCriteria)
            throws WorkbookException {
        /* initialize the runtime class of the object */
        Class<?> oC = initializeRuntimeClass(object);

        initializeConfigurationData(configCriteria, oC, false, true);
        Sheet s = configCriteria.getWorkbook().getSheet(truncateTitle(configCriteria.getTitleSheet()));
        configCriteria.setSheet(s);
        /* initialize index row & cell */
        int idxRow = configCriteria.getStartRow();
        int idxCell = configCriteria.getStartCell();
        Iterator<Row> iterator = s.iterator();
        Collection<Object> collection = new ArrayList<>();
        if (PropagationType.PROPAGATION_HORIZONTAL.equals(configCriteria.getPropagation())) {
            while (iterator.hasNext()) {
                try {
                    Object obj = oC.newInstance();
                    int counter = unmarshalAsPropagationHorizontal(configCriteria, obj, oC, idxRow, idxCell, 1);
                    if (obj != null && counter != -5) {
                        collection.add((Object) obj);
                        idxRow = idxRow + 1;
                    } else {
                        break;
                    }
                } catch (InstantiationException | IllegalAccessException e) {
                    throw new CustomizedRulesException(ExceptionMessage.ELEMENT_NO_SUCH_METHOD.getMessage(), e);
                }

            }

        } else {
            while (iterator.hasNext()) {
                try {
                    Object obj = oC.newInstance();
                    int counter = unmarshalAsPropagationVertical(configCriteria, obj, oC, idxRow, idxCell, 1);
                    if (obj != null && counter != -5) {
                        collection.add((Object) obj);
                        idxCell = idxCell + 1;
                        // idxRow = idxRow+1;
                    } else {
                        break;
                    }
                } catch (InstantiationException | IllegalAccessException e) {
                    throw new CustomizedRulesException(ExceptionMessage.ELEMENT_NO_SUCH_METHOD.getMessage(), e);
                }

            }

        }
        return collection;
    }

    /**
     * Method to truncate title of the sheet. The length max is 31 caracters
     * 
     * @param title
     * @return
     */
    private String truncateTitle(String title) {
        return title != null && title.length() > 31 ? title.substring(0, 31) : title;
    }
}