das.pf.io.IOExcel.java Source code

Java tutorial

Introduction

Here is the source code for das.pf.io.IOExcel.java

Source

/**
 * Copyright (C) 2014  Steven Rey Sequeira
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

package das.pf.io;

import das.pf.Util;
import java.awt.Color;
import java.awt.Desktop;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Stream;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFPalette;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
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.usermodel.WorkbookFactory;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

/**
 *
 * @author Steven Rey Sequeira
 */
public class IOExcel {
    private Path out = null;
    private StringProperty messages = null;

    private enum TypeValues {
        VALUES, UNITS, U_E;
    };

    private enum TypeUnits {
        MTH, QRT, YTD, MAT;
    };

    public IOExcel(Path output) {
        super();

        this.out = output;
        this.messages = new SimpleStringProperty(this, "mesages", "");
    }

    public boolean processFile(Path input, boolean openFile) {
        boolean result = false;
        int endRow = 0;

        try {
            updateMessages(String.format("Inicializando el documento: %s", input.toString()));
            Path copy = createCopy(input);

            if (copy != null && Files.exists(copy, LinkOption.NOFOLLOW_LINKS)) {
                Workbook workbook = WorkbookFactory.create(copy.toFile());
                Sheet sheet = workbook.getSheetAt(0);
                Sheet newSheet = workbook.createSheet("Procesado");

                workbook.setSheetName(0, "Crudo");

                endRow = getLasRow(sheet);

                // seccion para la creacion de los encabezados
                updateMessages("Creando la cabecera de los datos");
                createHeaderData(newSheet, getCellStyleHeaderData(workbook));

                // seccion para los values USD
                updateMessages(
                        String.format("Creando la cabecera para los: 'values USD' %s", TypeUnits.MTH.name()));
                createHeaderValues(newSheet, sheet, getCellStyleValues(workbook, TypeValues.VALUES, TypeUnits.MTH),
                        11, 35, 14);
                updateMessages(
                        String.format("Creando la cabecera para los: 'values USD' %s", TypeUnits.QRT.name()));
                createHeaderValues(newSheet, sheet, getCellStyleValues(workbook, TypeValues.VALUES, TypeUnits.QRT),
                        35, 49, 38);
                updateMessages(
                        String.format("Creando la cabecera para los: 'values USD' %s", TypeUnits.YTD.name()));
                createHeaderValues(newSheet, sheet, getCellStyleValues(workbook, TypeValues.VALUES, TypeUnits.YTD),
                        49, 54, 52);
                updateMessages(
                        String.format("Creando la cabecera para los: 'values USD' %s", TypeUnits.MAT.name()));
                createHeaderValues(newSheet, sheet, getCellStyleValues(workbook, TypeValues.VALUES, TypeUnits.MAT),
                        54, 59, 57);

                // seccion para los values units
                updateMessages(
                        String.format("Creando la cabecera para los: 'values Units' %s", TypeUnits.MTH.name()));
                createHeaderValues(newSheet, sheet, getCellStyleValues(workbook, TypeValues.UNITS, TypeUnits.MTH),
                        59, 83, 63);
                updateMessages(
                        String.format("Creando la cabecera para los: 'values Units' %s", TypeUnits.QRT.name()));
                createHeaderValues(newSheet, sheet, getCellStyleValues(workbook, TypeValues.UNITS, TypeUnits.QRT),
                        83, 97, 87);
                updateMessages(
                        String.format("Creando la cabecera para los: 'values Units' %s", TypeUnits.YTD.name()));
                createHeaderValues(newSheet, sheet, getCellStyleValues(workbook, TypeValues.UNITS, TypeUnits.YTD),
                        97, 102, 101);
                updateMessages(
                        String.format("Creando la cabecera para los: 'values Units' %s", TypeUnits.MAT.name()));
                createHeaderValues(newSheet, sheet, getCellStyleValues(workbook, TypeValues.UNITS, TypeUnits.MAT),
                        102, 107, 106);
                //            
                //            // seccion para los values units standars
                updateMessages(String.format("Creando la cabecera para los: 'values Standard Units' %s",
                        TypeUnits.MTH.name()));
                createHeaderValues(newSheet, sheet, getCellStyleValues(workbook, TypeValues.U_E, TypeUnits.MTH),
                        107, 131, 112);
                updateMessages(String.format("Creando la cabecera para los: 'values Standard Units' %s",
                        TypeUnits.QRT.name()));
                createHeaderValues(newSheet, sheet, getCellStyleValues(workbook, TypeValues.U_E, TypeUnits.QRT),
                        131, 145, 136);
                updateMessages(String.format("Creando la cabecera para los: 'values Standard Units' %s",
                        TypeUnits.YTD.name()));
                createHeaderValues(newSheet, sheet, getCellStyleValues(workbook, TypeValues.U_E, TypeUnits.YTD),
                        145, 150, 150);
                updateMessages(String.format("Creando la cabecera para los: 'values Standard Units' %s",
                        TypeUnits.MAT.name()));
                createHeaderValues(newSheet, sheet, getCellStyleValues(workbook, TypeValues.U_E, TypeUnits.MAT),
                        150, 155, 155);

                // fin de la seccion para la creacion de los encabezados

                // seccion para escribir los CT
                updateMessages("Escribiendo las clases terampeuticas...");
                writeCT(newSheet, sheet, 13, endRow);

                // seccion para escribir los productos
                updateMessages("Escribiendo los productos...");
                writeProducts(newSheet, sheet, 14);

                // seccion para escribir los otros valores
                updateMessages("Escribiendo datos en general...");
                writerOthersValues(newSheet, sheet, 15);

                // seccion para escribir los key competitors
                updateMessages("Escribiendo los Key Competitors...");
                writeKeyCompetitors(newSheet, 3, endRow, 9, 5);

                // seccion para escribir el pais
                XmlContry contry = writeContries(newSheet, 3, 0, input);

                // seccion para escribir la region
                writeRegions(contry, newSheet, 3, 1);

                for (int i = 0; i < 155; i++)
                    newSheet.autoSizeColumn(i);

                newSheet.setAutoFilter(CellRangeAddress.valueOf(String.format("A3:K%d", newSheet.getLastRowNum())));

                String pathOutput = "DAS PF - " + input.getFileName().toString();

                try (FileOutputStream fos = new FileOutputStream(
                        Paths.get(this.out.toString(), pathOutput).toFile())) {

                    updateMessages(String.format("Guadando el trabajo en la ruta: '%s'",
                            Paths.get(this.out.toString(), pathOutput)));

                    workbook.write(fos);
                } catch (IOException ex) {
                    Logger.getLogger(IOExcel.class.getName()).log(Level.SEVERE, null, ex);
                } finally {
                    workbook.close();
                }

                if (openFile && Desktop.isDesktopSupported()
                        && Desktop.getDesktop().isSupported(Desktop.Action.OPEN))
                    Desktop.getDesktop().open(Paths.get(this.out.toString(), pathOutput).toFile());

                result = true;

                newSheet = null;
                sheet = null;
                workbook = null;

                Files.delete(copy);
            }
        } catch (IOException | InvalidFormatException ex) {
            Logger.getLogger(IOExcel.class.getName()).log(Level.SEVERE, null, ex);

            Util.showException("No se pudo guardar el archivo", ex);
        }

        return result;
    }

    public StringProperty messagesProperty() {
        return this.messages;
    }

    public boolean consolidateFiles() {
        boolean result = false;
        AtomicInteger rowIndex = new AtomicInteger(3);

        String outputName = "DAS - " + this.out.getFileName().toString() + " consolidate.xlsx";
        Workbook consolidateWb = new XSSFWorkbook();

        try {
            Sheet sheetConsolidate = consolidateWb.createSheet("Consolidado");

            Files.list(this.out).filter((p) -> {
                String name = p.toString();

                return (name.endsWith(".xlsx") || name.endsWith(".xls"))
                        && !p.getFileName().toString().equals(outputName);
            }).sorted((p1, p2) -> {
                String acronym = getAcromynName(p1);
                String acronym2 = getAcromynName(p2);

                return acronym.compareToIgnoreCase(acronym2);
            }).forEach(p -> {
                try {
                    Workbook wb = WorkbookFactory.create(p.toFile());
                    Sheet sheet = wb.getSheet("Procesado");

                    updateMessages(String.format("Copiando los datos del archivo: %s dentro del archivo: %s",
                            p.toString(), outputName));

                    for (int index = 3; index < sheet.getLastRowNum(); index++) {
                        Row row = sheet.getRow(index);
                        Row r = sheetConsolidate.createRow(rowIndex.getAndIncrement());

                        row.forEach(c -> {
                            if (c != null && c.getCellType() != Cell.CELL_TYPE_BLANK) {
                                final Cell cell = r.createCell(c.getColumnIndex(), c.getCellType());

                                updateMessages(
                                        String.format("Copiando los datos de la fila: #%d", c.getRowIndex()));

                                switch (c.getCellType()) {
                                case Cell.CELL_TYPE_NUMERIC:
                                    cell.setCellValue(c.getNumericCellValue());

                                    break;

                                case Cell.CELL_TYPE_STRING:
                                    cell.setCellValue(c.getRichStringCellValue());

                                    break;
                                }
                            }
                        });

                        row = null;
                    }

                    sheet = null;
                    wb.close();
                    wb = null;
                } catch (IOException | InvalidFormatException | EncryptedDocumentException ex) {
                    Logger.getLogger(IOExcel.class.getName()).log(Level.SEVERE, null, ex);
                }
            });

            Path path = Files.list(this.out).filter((p) -> {
                String name = p.toString();

                return (name.endsWith(".xlsx") || name.endsWith(".xls"))
                        && !p.getFileName().toString().equals(outputName);
            }).findFirst().get();

            createHeadersConsolidateFile(consolidateWb, path);

            for (int i = 0; i < 155; i++)
                sheetConsolidate.autoSizeColumn(i);

            sheetConsolidate.setAutoFilter(
                    CellRangeAddress.valueOf(String.format("A3:K%d", sheetConsolidate.getLastRowNum())));

            try (FileOutputStream fos = new FileOutputStream(Paths.get(out.toString(), outputName).toFile())) {
                updateMessages(String.format("Guadando el trabajo en la ruta: '%s'",
                        Paths.get(this.out.toString(), outputName)));

                consolidateWb.write(fos);

                result = true;
            } catch (IOException ex) {
                Logger.getLogger(IOExcel.class.getName()).log(Level.SEVERE,
                        "Ocurrio un error al intenatr guardar el archivo consolidado", ex);
            } finally {
                consolidateWb.close();
            }

        } catch (IOException ex) {
            Logger.getLogger(IOExcel.class.getName()).log(Level.SEVERE, null, ex);
        }

        consolidateWb = null;

        return result;
    }

    // seccion de metodos privados

    private Path createCopy(Path source) {
        Path target = null;

        try {
            if (Files.exists(source, LinkOption.NOFOLLOW_LINKS)) {
                Path tmpDir = Paths.get(System.getProperty("java.io.tmpdir"));

                target = Files.copy(source, tmpDir.resolve(source.getFileName()),
                        StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);
            }
        } catch (IOException ex) {
            Logger.getLogger(IOExcel.class.getName()).log(Level.SEVERE, null, ex);
        }

        return target;
    }

    private void createHeadersConsolidateFile(Workbook consolidadteWb, Path source) {
        try {
            Workbook wb = WorkbookFactory.create(source.toFile());
            Sheet sheet = wb.getSheetAt(0);
            Sheet consolidaeSheet = consolidadteWb.getSheetAt(0);

            updateMessages("Creando la cabecera de los datos del archivo consolidado");
            createHeaderData(consolidaeSheet, getCellStyleHeaderData(consolidadteWb));

            // seccion para los values USD
            updateMessages(String.format("Creando la cabecera para los: 'values USD' %s", TypeUnits.MTH.name()));
            createHeaderValues(consolidaeSheet, sheet,
                    getCellStyleValues(consolidadteWb, TypeValues.VALUES, TypeUnits.MTH), 11, 35, 14);
            updateMessages(String.format("Creando la cabecera para los: 'values USD' %s", TypeUnits.QRT.name()));
            createHeaderValues(consolidaeSheet, sheet,
                    getCellStyleValues(consolidadteWb, TypeValues.VALUES, TypeUnits.QRT), 35, 49, 38);
            updateMessages(String.format("Creando la cabecera para los: 'values USD' %s", TypeUnits.YTD.name()));
            createHeaderValues(consolidaeSheet, sheet,
                    getCellStyleValues(consolidadteWb, TypeValues.VALUES, TypeUnits.YTD), 49, 54, 52);
            updateMessages(String.format("Creando la cabecera para los: 'values USD' %s", TypeUnits.MAT.name()));
            createHeaderValues(consolidaeSheet, sheet,
                    getCellStyleValues(consolidadteWb, TypeValues.VALUES, TypeUnits.MAT), 54, 59, 57);

            // seccion para los values units
            updateMessages(String.format("Creando la cabecera para los: 'values Units' %s", TypeUnits.MTH.name()));
            createHeaderValues(consolidaeSheet, sheet,
                    getCellStyleValues(consolidadteWb, TypeValues.UNITS, TypeUnits.MTH), 59, 83, 63);
            updateMessages(String.format("Creando la cabecera para los: 'values Units' %s", TypeUnits.QRT.name()));
            createHeaderValues(consolidaeSheet, sheet,
                    getCellStyleValues(consolidadteWb, TypeValues.UNITS, TypeUnits.QRT), 83, 97, 87);
            updateMessages(String.format("Creando la cabecera para los: 'values Units' %s", TypeUnits.YTD.name()));
            createHeaderValues(consolidaeSheet, sheet,
                    getCellStyleValues(consolidadteWb, TypeValues.UNITS, TypeUnits.YTD), 97, 102, 101);
            updateMessages(String.format("Creando la cabecera para los: 'values Units' %s", TypeUnits.MAT.name()));
            createHeaderValues(consolidaeSheet, sheet,
                    getCellStyleValues(consolidadteWb, TypeValues.UNITS, TypeUnits.MAT), 102, 107, 106);
            //            
            //            // seccion para los values units standars
            updateMessages(String.format("Creando la cabecera para los: 'values Standard Units' %s",
                    TypeUnits.MTH.name()));
            createHeaderValues(consolidaeSheet, sheet,
                    getCellStyleValues(consolidadteWb, TypeValues.U_E, TypeUnits.MTH), 107, 131, 112);
            updateMessages(String.format("Creando la cabecera para los: 'values Standard Units' %s",
                    TypeUnits.QRT.name()));
            createHeaderValues(consolidaeSheet, sheet,
                    getCellStyleValues(consolidadteWb, TypeValues.U_E, TypeUnits.QRT), 131, 145, 136);
            updateMessages(String.format("Creando la cabecera para los: 'values Standard Units' %s",
                    TypeUnits.YTD.name()));
            createHeaderValues(consolidaeSheet, sheet,
                    getCellStyleValues(consolidadteWb, TypeValues.U_E, TypeUnits.YTD), 145, 150, 150);
            updateMessages(String.format("Creando la cabecera para los: 'values Standard Units' %s",
                    TypeUnits.MAT.name()));
            createHeaderValues(consolidaeSheet, sheet,
                    getCellStyleValues(consolidadteWb, TypeValues.U_E, TypeUnits.MAT), 150, 155, 155);
        } catch (IOException | InvalidFormatException | EncryptedDocumentException ex) {
            Logger.getLogger(IOExcel.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private CellStyle getCellStyleValues(Workbook worbook, TypeValues typeValue, TypeUnits typeUnit) {
        if (worbook instanceof XSSFWorkbook)
            return getXSSFCellStyleValues(worbook, typeValue, typeUnit);

        return getHSSFCellStyleValue(worbook, typeValue, typeUnit);
    }

    private XSSFCellStyle getXSSFCellStyleValues(Workbook worbook, TypeValues typeValue, TypeUnits typeUnit) {
        XSSFCellStyle style = (XSSFCellStyle) worbook.createCellStyle();
        XSSFFont font = (XSSFFont) worbook.createFont();

        font.setBold(true);
        font.setColor(new XSSFColor(Color.WHITE));

        style.setAlignment(HorizontalAlignment.CENTER);

        switch (typeValue) {
        case VALUES:
            switch (typeUnit) {
            case MTH:
                style.setFillForegroundColor(new XSSFColor(Color.BLUE.darker()));

                break;

            case QRT:
                style.setFillForegroundColor(new XSSFColor(Color.BLUE.darker().darker()));

                break;

            case YTD:
                style.setFillForegroundColor(new XSSFColor(Color.BLUE));

                break;

            case MAT:
                style.setFillForegroundColor(new XSSFColor(Color.CYAN));

                break;
            }

            break;

        case UNITS:
            switch (typeUnit) {
            case MTH:
                style.setFillForegroundColor(new XSSFColor(Color.RED.darker()));

                break;

            case QRT:
                style.setFillForegroundColor(new XSSFColor(Color.RED.darker().darker()));

                break;

            case YTD:
                style.setFillForegroundColor(new XSSFColor(Color.ORANGE));

                break;

            case MAT:
                style.setFillForegroundColor(new XSSFColor(Color.YELLOW));

                break;
            }

            break;

        case U_E:
            switch (typeUnit) {
            case MTH:
                style.setFillForegroundColor(new XSSFColor(Color.GRAY.darker()));

                break;

            case QRT:
                style.setFillForegroundColor(new XSSFColor(Color.GREEN.darker().darker()));

                break;

            case YTD:
                style.setFillForegroundColor(new XSSFColor(Color.GRAY));

                break;

            case MAT:
                style.setFillForegroundColor(new XSSFColor(Color.LIGHT_GRAY));

                break;
            }

            break;
        }

        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        style.setFont(font);

        return style;
    }

    private HSSFCellStyle getHSSFCellStyleValue(Workbook worbook, TypeValues typeValue, TypeUnits typeUnit) {
        HSSFCellStyle style = (HSSFCellStyle) worbook.createCellStyle();
        HSSFFont font = (HSSFFont) worbook.createFont();
        HSSFPalette palette = ((HSSFWorkbook) worbook).getCustomPalette();

        font.setColor(HSSFColor.WHITE.index);

        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);

        switch (typeValue) {
        case VALUES:
            switch (typeUnit) {
            case MTH:
                style.setFillForegroundColor(HSSFColor.DARK_BLUE.index);

                break;

            case QRT:
                style.setFillForegroundColor(HSSFColor.DARK_BLUE.index);
                palette.setColorAtIndex(HSSFColor.DARK_BLUE.index, (byte) 0, (byte) 0, (byte) 102);

                break;

            case YTD:
                style.setFillForegroundColor(HSSFColor.BLUE.index);

                break;

            case MAT:
                style.setFillForegroundColor(HSSFColor.AQUA.index);

                break;
            }

            break;

        case UNITS:
            switch (typeUnit) {
            case MTH:
                style.setFillForegroundColor(HSSFColor.RED.index);

                break;

            case QRT:
                style.setFillForegroundColor(HSSFColor.DARK_RED.index);

                break;

            case YTD:
                style.setFillForegroundColor(HSSFColor.ORANGE.index);

                break;

            case MAT:
                style.setFillForegroundColor(HSSFColor.YELLOW.index);

                break;
            }

            break;

        case U_E:
            switch (typeUnit) {
            case MTH:
                style.setFillForegroundColor(HSSFColor.GREY_50_PERCENT.index);

                break;

            case QRT:
                style.setFillForegroundColor(HSSFColor.DARK_GREEN.index);

                break;

            case YTD:
                style.setFillForegroundColor(HSSFColor.GREY_40_PERCENT.index);

                break;

            case MAT:
                style.setFillForegroundColor(HSSFColor.GREY_25_PERCENT.index);

                break;
            }

            break;
        }

        style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
        style.setFont(font);

        return style;
    }

    private CellStyle getCellStyleHeaderData(Workbook workbook) {
        if (workbook instanceof XSSFWorkbook)
            return getXSSFCellStyleHeaderData(workbook);

        return getHSSFCellStyleHeaderData(workbook);
    }

    private XSSFCellStyle getXSSFCellStyleHeaderData(Workbook workbook) {
        XSSFCellStyle style = (XSSFCellStyle) workbook.createCellStyle();
        XSSFFont font = (XSSFFont) workbook.createFont();

        font.setBold(true);
        font.setColor(new XSSFColor(Color.WHITE));

        style.setAlignment(HorizontalAlignment.CENTER);
        style.setFillForegroundColor(new XSSFColor(Color.GRAY));
        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        style.setFont(font);

        return style;
    }

    private HSSFCellStyle getHSSFCellStyleHeaderData(Workbook worbook) {
        HSSFCellStyle style = (HSSFCellStyle) worbook.createCellStyle();
        HSSFFont font = (HSSFFont) worbook.createFont();

        font.setBoldweight((short) 2);
        font.setColor(HSSFColor.WHITE.index);

        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        style.setFillForegroundColor(HSSFColor.GREY_50_PERCENT.index);
        style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);

        return style;
    }

    private void createHeaderData(Sheet sheet, CellStyle style) {
        Row row = sheet.createRow(2);
        CreationHelper helper = sheet.getWorkbook().getCreationHelper();

        String[] titles = new String[] { "Pais", "Regiones", "Mercados Relevantes", "CT", "Key Markets", "Producto",
                "Key Competitors", "Sku", "Laboratorios", "Tipo de Mercado", "Molculas" };

        for (int index = 0; index < titles.length; index++) {
            Cell cell = row.createCell(index);

            cell.setCellType(Cell.CELL_TYPE_STRING);
            cell.setCellValue(helper.createRichTextString(titles[index]));
            cell.setCellStyle(style);

            cell = null;
        }

        row = null;
        helper = null;
    }

    private void createHeaderValues(Sheet sheet, Sheet source, CellStyle style, int start, int end,
            int indexSource) {
        Row rowSource = source.getRow(9);
        Row row = sheet.getRow(1) != null ? sheet.getRow(1) : sheet.createRow(1);

        for (int index = start; index < end; index++) {
            Cell cellSource = rowSource.getCell(indexSource++);
            Cell cell = row.createCell(index);

            cell.setCellType(Cell.CELL_TYPE_STRING);
            cell.setCellValue(cellSource.getRichStringCellValue());

            cell.setCellStyle(style);

            cell = null;
            cellSource = null;
        }

        row = null;
        rowSource = null;
    }

    /**
     * Este metodo se encarga de escribir en la hoja de destino todos los datos relacionados con las Clases
     * Terapeuticas, que se encuentren dentro de la hoja fuente.
     * 
     * @param sheet
     *          Instancia que modela la hoja objetivo o hoja en la que se desea trabajar.
     * 
     * @param source
     *          Instancia que modela la hoja que posee todos las Clases Terapeuticas.
     * 
     * @param start 
     *          Indica el indice de la primer fila donde se encuentran las clases terapeuticas.
     * 
     * @param endRow 
     *          Inidca el indice de la ultima fila que se desea escribir.
     */
    private void writeCT(Sheet sheet, Sheet source, int start, int endRow) {
        int indexTarget = 3;
        int indexRow = start;

        String ct = "";
        CreationHelper helper = sheet.getWorkbook().getCreationHelper();

        while (indexRow < (endRow + start)) {
            try {
                Row rowSource = source.getRow(indexRow);

                if (rowSource != null) {
                    Cell type = rowSource.getCell(2);

                    if (type != null) {

                        if (type.getRichStringCellValue().getString().equals("ATC IV")) {
                            ct = rowSource.getCell(6).getRichStringCellValue().getString();

                            int totalPacks = 0;
                            int indexProd = indexRow + 1;
                            int count = 0;
                            int totalProdu = getNumberOfSubNodes(source, indexRow, "Prds.", "ATC IV");

                            // se obtienen los totales de productos de todos los paquetes que pertenescan a la clase terapeutica
                            for (int subNodeProduc = 0; subNodeProduc < totalProdu; subNodeProduc++) {
                                count = getNumberOfSubNodes(source, indexProd, "Packs", "Prds.");
                                totalPacks += count;

                                indexProd += count + 1;
                            }

                            // se escribes la cantidad correcta de filas con la clase terapeutica correspondiente
                            for (int indexCT = 0; indexCT < totalPacks; indexCT++) {
                                Row row = sheet.createRow(indexTarget++);
                                Cell cellCT = row.createCell(3);

                                cellCT.setCellType(Cell.CELL_TYPE_STRING);
                                cellCT.setCellValue(helper.createRichTextString(ct));

                                cellCT = null;
                                row = null;
                            }

                            indexRow += (totalPacks + totalProdu);
                        } else
                            indexRow++;

                        type = null;
                    } else
                        indexRow++;
                } else
                    indexRow++;
            } catch (NullPointerException ex) {
                Logger.getLogger(IOExcel.class.getName()).log(Level.SEVERE, String.format("indexRow: %d", indexRow),
                        ex);

                Util.showException("Ocurrio un error procesando las Clases Terapeuticas", ex);
            }
        }
    }

    /**
     * Este metodo se encarga de escribir o llenar todos los productos en la hoja de destino u objetivo,
     * que se encuentran en la hoja fuente.
     * 
     * @param sheet
     *          Intancia que modela la hoja objetivo o la hoja que se desea trabajar.
     * 
     * @param source
     *          Instancia que modela la hoja que contiene todos los productos.
     * 
     * @param start 
     *          Indica la posicion de la primer fila donde se encuentran los productos en
     *          la hoja fuente.
     */
    private void writeProducts(Sheet sheet, Sheet source, int start) {
        AtomicInteger rowIndex = new AtomicInteger(3);

        final CreationHelper helper = sheet.getWorkbook().getCreationHelper();

        Stream<Row> rows = getRows(source, start).stream().filter((Row r) -> {
            Cell type = r.getCell(2);

            return type != null && type.getRichStringCellValue().getString().equals("Prds.");
        });

        if (rows != null) {
            rows.forEach(r -> {
                String product = r.getCell(6).getRichStringCellValue().getString()
                        .replaceFirst("\\[[0-9]+/[0-9]+\\]", "");

                int numbeerOfSubNodes = getNumberOfSubNodes(source, r.getRowNum(), "Packs", "Prds.");

                for (int subNodes = 0; subNodes < numbeerOfSubNodes; subNodes++) {
                    Row row = sheet.getRow(rowIndex.getAndIncrement());

                    if (row != null) {
                        Cell cellProductSubNode = row.createCell(5);

                        cellProductSubNode.setCellType(Cell.CELL_TYPE_STRING);
                        cellProductSubNode.setCellValue(helper.createRichTextString(product));

                        cellProductSubNode = null;
                        row = null;
                    }
                }
            });
        }
    }

    private List<Row> getRows(Sheet source, int start) {
        List<Row> rows = new ArrayList<>(source.getLastRowNum());

        for (int index = start; index < source.getLastRowNum(); index++)
            if (source.getRow(index) != null)
                rows.add(source.getRow(index));

        return rows;
    }

    /**
     * Este metodo se encarga de escribir o llenar las columnas en la hoja objetivo o la hoja
     * en la que se desea trabajar, con los datos que se encuentran dentro de la hoja fuente.
     * Los datos que seran toamdos encuenta son todas las columnas menos: "Productos", "Clases Terapeuticas",
     * "Key Competitors".
     * 
     * @param sheet
     *          Instancia que modela la hoja objetivo o de destino.
     * 
     * @param source
     *          Instancia que modela la hoja fuente o que contiene los datos que sedesea
     *          procesar.
     * 
     * @param start 
     *          Indica el indice de la primer fila donde se encuentran los datos.   
     */
    private void writerOthersValues(Sheet sheet, Sheet source, int start) {
        int indexTarget = 3;

        for (int indexRow = start; indexRow < (source.getLastRowNum() - 1); indexRow++) {
            Row rowSource = source.getRow(indexRow);

            if (rowSource != null) {
                Cell type = rowSource.getCell(2);

                if (type != null && type.getRichStringCellValue().getString().equals("Packs")) {
                    Row row = sheet.getRow(indexTarget++);

                    if (row != null) {
                        Cell sku = row.createCell(7);
                        Cell laboratory = row.createCell(8);
                        Cell typeOfMark = row.createCell(9);
                        Cell molecules = row.createCell(10);

                        sku.setCellType(Cell.CELL_TYPE_STRING);
                        sku.setCellValue(rowSource.getCell(6).getRichStringCellValue().getString());

                        laboratory.setCellType(Cell.CELL_TYPE_STRING);
                        laboratory.setCellValue(rowSource.getCell(8).getRichStringCellValue().getString());

                        typeOfMark.setCellType(Cell.CELL_TYPE_STRING);
                        typeOfMark.setCellValue(rowSource.getCell(9).getRichStringCellValue().getString());

                        molecules.setCellType(Cell.CELL_TYPE_STRING);
                        molecules.setCellValue(rowSource.getCell(10).getRichStringCellValue().getString());

                        writeUnitValues(row, rowSource, 11, 155, 14);

                        sku = null;
                        laboratory = null;
                        typeOfMark = null;
                        molecules = null;
                    }

                    row = null;
                }

                type = null;
            }

            rowSource = null;
        }
    }

    /**
     * Este metodo se encarga de escribir todos los valores correspondientes a las 
     * unidades en dolares, estandares y de valores.
     * 
     * @param target
     *          Instancia que modela la fila sobre la cual se escribiran en la celdas.
     * 
     * @param source
     *          Instancia que modela la fila que contiene las celdas con los datos a escribir.
     * 
     * @param startValues
     *          Indice que marca la primer celda a escribir
     * 
     * @param endValues
     *          Indice que indica la ultima celda sobre la que se debe escribir.
     * 
     * @param indexValuesSource 
     *          Indice que indica la primer celda que contiene los datos a escribir dentro de la fila fuente.
     */
    private void writeUnitValues(Row target, Row source, int startValues, int endValues, int indexValuesSource) {
        try {
            for (int indexCell = startValues; indexCell < endValues; indexCell++) {
                if (indexValuesSource == 62 || indexValuesSource == 111)
                    indexValuesSource++;

                Cell value = target.createCell(indexCell);
                Cell valueSource = source.getCell(indexValuesSource++);

                if (valueSource != null) {
                    if (valueSource.getCellType() == Cell.CELL_TYPE_NUMERIC)
                        value.setCellValue(valueSource.getNumericCellValue());
                    else if (valueSource.getCellType() == Cell.CELL_TYPE_STRING)
                        value.setCellValue(Double.parseDouble(valueSource.getRichStringCellValue().getString()));

                    value.setCellType(Cell.CELL_TYPE_NUMERIC);
                }

                value = null;
                valueSource = null;
            }
        } catch (NumberFormatException ex) {
            Logger.getLogger(IOExcel.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);

            Util.showException("Ocurrio un error procensado los valores de las unidades", ex);
        }
    }

    /**
     * Este metodo se encarga de escribir los datos correspondientes a los Key Competitors
     * 
     * @param sheet
     *          Instancia que modela la hoja en la que se va a trabajar.
     * 
     * @param startRow
     *          Indica el indice de la primer fila en la que se trabajara.
     * 
     *  @param endRow
     *          Indica el indice para la ultima fila que se desea escribir.
     * 
     * @param indexColumSource
     *          Indica el indice de la celda donde se tomara como parametro los datos
     * 
     * @param indexColumnProduct 
     *          Indica el indice de la celda donde estan los productos.
     */
    private void writeKeyCompetitors(Sheet sheet, int startRow, int endRow, int indexColumSource,
            int indexColumnProduct) {
        CreationHelper helper = sheet.getWorkbook().getCreationHelper();
        int index = 6;

        for (int indexRow = startRow; indexRow < (endRow + startRow); indexRow++) {
            Row row = sheet.getRow(indexRow);

            if (row != null) {
                Cell cellKeyCompetitor = row.createCell(index);
                Cell cellSource = row.getCell(indexColumSource);

                if (cellSource != null) {
                    cellKeyCompetitor.setCellType(Cell.CELL_TYPE_STRING);

                    if (cellSource.getRichStringCellValue().getString().trim().equals("Generico"))
                        cellKeyCompetitor.setCellValue(helper.createRichTextString("Genricos"));
                    else {
                        Cell cellProduct = row.getCell(indexColumnProduct);

                        if (cellProduct != null)
                            cellKeyCompetitor.setCellValue(cellProduct.getRichStringCellValue().getString());
                    }
                }

                cellKeyCompetitor = null;
                cellSource = null;
            }

            row = null;
        }
    }

    private void updateMessages(String message) {
        this.messages.setValue(message);
    }

    private int getLasRow(Sheet source) {
        int count = 0;

        for (int index = 13; index < source.getLastRowNum(); index++) {
            try {
                if (source.getRow(index) != null) {
                    Row r = source.getRow(index);
                    Cell cell = r.getCell(2);

                    if (cell != null && cell.getRichStringCellValue().getString().equalsIgnoreCase("Packs")
                            || cell != null && cell.getRichStringCellValue().getString().equalsIgnoreCase("Prds.")
                            || cell != null && cell.getRichStringCellValue().getString().equalsIgnoreCase("ATC IV"))
                        count++;

                    r = null;
                    cell = null;
                }
            } catch (NullPointerException ex) {
                Logger.getLogger(IOExcel.class.getName()).log(Level.SEVERE, String.format("Index: %d", index), ex);

                Util.showException("Ocurrio un error opteniendo la ultima fila del archivo", ex);
            }
        }

        return count;
    }

    /**
     * Este metodo se encarga de contar cuantos sub-nodos existen.
     * 
     * @param sheet
     *                  Instancia que modela una hoja dentro del libro de Excel
     * 
     * @param start
     *                  Indica la primer posicion donde se encuentran los sub-nodos a contar
     * 
     * @param find
     *                  Indica la palabra a buscar con la que se relacionaran los sub-nodos a contar.
     * 
     * @param delimiter 
     *                  Indica el delimitador o palabra que ocacionara una interrupcion en la busqueda
     * 
     * @return 
     *          Retorna el numero de sub-nodos deacuerdo a una posocion especificada.
     */
    private int getNumberOfSubNodes(Sheet sheet, int start, String find, String delimiter) {
        int result = 0;

        try {
            Row row = sheet.getRow(++start);

            while ((row != null && row.getCell(2) != null)
                    && !row.getCell(2).getRichStringCellValue().getString().equalsIgnoreCase(delimiter)) {
                if (row.getCell(2).getRichStringCellValue().getString().equalsIgnoreCase(find))
                    result++;

                row = sheet.getRow(++start);
            }

            row = null;
        } catch (NullPointerException ex) {
            Logger.getLogger(IOExcel.class.getName()).log(Level.SEVERE,
                    String.format("Index: %d, valor buscado: %s, delimitador: %s", start, find, delimiter), ex);

            Util.showException(
                    String.format("Index: %d, valor buscado: %s, delimitador: %s", start, find, delimiter), ex);
        }

        return result;
    }

    private XmlContry writeContries(Sheet sheet, int startRow, int column, Path pathFile) {
        CreationHelper helper = sheet.getWorkbook().getCreationHelper();

        XmlContry contry = Util.getContryByAcronym(getAcromynName(pathFile));

        if (contry != null) {
            try {
                for (int index = startRow; index < sheet.getLastRowNum() + 1; index++) {
                    Row row = sheet.getRow(index);

                    if (row != null) {
                        Cell cellContry = row.createCell(column);

                        cellContry.setCellType(Cell.CELL_TYPE_STRING);
                        cellContry.setCellValue(helper.createRichTextString(contry.getName()));

                        updateMessages(String.format("Escribiendo el pais: %s en la fila: %d", contry.getName(),
                                index + 1));
                    }
                }
            } catch (Exception ex) {
                Logger.getLogger(getClass().getName()).log(Level.SEVERE, "Error al escribir la columna Pais", ex);

                Util.showException("Error al escribir la columna Pais", ex);
            }
        }

        return contry;
    }

    private void writeRegions(XmlContry contry, Sheet sheet, int startRow, int column) {
        CreationHelper helper = sheet.getWorkbook().getCreationHelper();
        XmlRegion region = Util.getRegionByContry(contry);

        if (region != null) {
            for (int index = startRow; index < sheet.getLastRowNum() + 1; index++) {
                Row r = sheet.getRow(index);

                try {
                    if (r != null) {
                        Cell cellRegion = r.createCell(column);

                        cellRegion.setCellType(Cell.CELL_TYPE_STRING);
                        cellRegion.setCellValue(helper.createRichTextString(region.getName()));

                        updateMessages(String.format("Escribiendo la region: %s en la fila: %d", region.getName(),
                                r.getRowNum() + 1));
                    }
                } catch (Exception ex) {
                    Logger.getLogger(getClass().getName()).log(Level.SEVERE, "Error al escribir la columna Region",
                            ex);

                    Util.showException("Error al escribir la columna Region", ex);
                }
            }
        }
    }

    /**
     * Este metodo se encarga de obtener el acronimo del pais, segun el nombre del archivo que
     * se este procesando
     * 
     * @param path
     *          Instancia que contiene la informacion de la ruta del archivo que se esta procesando
     * 
     * @return 
     *      Retorna un {@code String} que contiene el acronimo del pais especificado en el
     *      nombre del archivo.
     */
    private String getAcromynName(Path path) {
        String acronym = "";
        XmlConfigFile cnf = Util.getConfigFile(Paths.get("config", "general_config.xml"));

        if (path != null) {
            String stringPath = path.getFileName().toString();
            String[] tmp = null;

            String separator = "";

            if (stringPath.contains("_")) {
                separator = "_";
            } else if (stringPath.contains("-")) {
                separator = "-";
            } else if (stringPath.contains(" ")) {
                separator = " ";
            }

            if (!separator.isEmpty()) {
                tmp = stringPath.split("[\\s_-]");

                acronym = Arrays.stream(tmp).filter(str -> {
                    return cnf.getContries().stream().anyMatch((c) -> {
                        if (str.endsWith(".xlsx") || str.endsWith(".xls"))
                            return (c.getAcronym().equals(str.substring(0, str.indexOf("."))));

                        return c.getAcronym().equals(str.trim());
                    });
                }).findFirst().orElse("");

            } else {
                for (XmlContry c : cnf.getContries()) {
                    if (stringPath.contains(c.getAcronym())) {
                        acronym = c.getAcronym();

                        break;
                    }
                }
            }
        }

        if (acronym.endsWith(".xlsx") || acronym.endsWith(".xls"))
            acronym = acronym.substring(0, acronym.indexOf("."));

        return acronym.trim();
    }
}